From 2b5f40b36e461baa5df72bfbde5aaf667ccd342e Mon Sep 17 00:00:00 2001
From: DimitrisJim <d.f.hilliard@gmail.com>
Date: Tue, 3 Dec 2024 07:20:50 +0200
Subject: [PATCH] chore: add channel client state rpc

---
 modules/core/04-channel/v2/client/cli/abci.go |   4 +
 modules/core/04-channel/v2/client/cli/cli.go  |   1 +
 .../core/04-channel/v2/client/cli/query.go    |  45 +
 .../core/04-channel/v2/keeper/grpc_query.go   |  18 +
 modules/core/04-channel/v2/types/query.go     |  16 +
 modules/core/04-channel/v2/types/query.pb.go  | 772 +++++++++++++++---
 .../core/04-channel/v2/types/query.pb.gw.go   | 101 +++
 proto/ibc/core/channel/v2/query.proto         |  24 +
 8 files changed, 849 insertions(+), 132 deletions(-)

diff --git a/modules/core/04-channel/v2/client/cli/abci.go b/modules/core/04-channel/v2/client/cli/abci.go
index d341e35b4e2..4344e4db8f5 100644
--- a/modules/core/04-channel/v2/client/cli/abci.go
+++ b/modules/core/04-channel/v2/client/cli/abci.go
@@ -12,6 +12,10 @@ import (
 	ibcclient "github.com/cosmos/ibc-go/v9/modules/core/client"
 )
 
+func queryChannelClientStateABCI(clientCtx client.Context, channelID string) (*types.QueryChannelClientStateResponse, error) {
+	return &types.QueryChannelClientStateResponse{}, nil
+}
+
 func queryNextSequenceSendABCI(clientCtx client.Context, channelID string) (*types.QueryNextSequenceSendResponse, error) {
 	key := hostv2.NextSequenceSendKey(channelID)
 	value, proofBz, proofHeight, err := ibcclient.QueryTendermintProof(clientCtx, key)
diff --git a/modules/core/04-channel/v2/client/cli/cli.go b/modules/core/04-channel/v2/client/cli/cli.go
index c9a0d954287..5fdde6a87dc 100644
--- a/modules/core/04-channel/v2/client/cli/cli.go
+++ b/modules/core/04-channel/v2/client/cli/cli.go
@@ -20,6 +20,7 @@ func GetQueryCmd() *cobra.Command {
 
 	queryCmd.AddCommand(
 		getCmdQueryChannel(),
+		getCmdQueryChannelClientState(),
 		getCmdQueryNextSequenceSend(),
 		getCmdQueryPacketCommitment(),
 		getCmdQueryPacketCommitments(),
diff --git a/modules/core/04-channel/v2/client/cli/query.go b/modules/core/04-channel/v2/client/cli/query.go
index 2be1a004d3e..fd66f4529f1 100644
--- a/modules/core/04-channel/v2/client/cli/query.go
+++ b/modules/core/04-channel/v2/client/cli/query.go
@@ -49,6 +49,51 @@ func getCmdQueryChannel() *cobra.Command {
 	return cmd
 }
 
+// getCmdQueryChannelClientState defines the command to query the channel client state for the given channel ID.
+func getCmdQueryChannelClientState() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:     "client-state [channel-id]",
+		Short:   "Query the client state associated with a channel.",
+		Long:    "Query the client state associated with a channel for the provided channel ID.",
+		Example: fmt.Sprintf("%s query %s %s client-state [channel-id]", version.AppName, exported.ModuleName, types.SubModuleName),
+		Args:    cobra.ExactArgs(1),
+		RunE: func(cmd *cobra.Command, args []string) error {
+			clientCtx, err := client.GetClientQueryContext(cmd)
+			if err != nil {
+				return err
+			}
+
+			channelID := args[0]
+			prove, err := cmd.Flags().GetBool(flags.FlagProve)
+			if err != nil {
+				return err
+			}
+
+			if prove {
+				res, err := queryChannelClientStateABCI(clientCtx, channelID)
+				if err != nil {
+					return err
+				}
+
+				return clientCtx.PrintProto(res)
+			}
+
+			queryClient := types.NewQueryClient(clientCtx)
+			res, err := queryClient.ChannelClientState(cmd.Context(), types.NewQueryChannelClientStateRequest(channelID))
+			if err != nil {
+				return err
+			}
+
+			return clientCtx.PrintProto(res)
+		},
+	}
+
+	cmd.Flags().Bool(flags.FlagProve, true, "show proofs for the query results")
+	flags.AddQueryFlagsToCmd(cmd)
+
+	return cmd
+}
+
 // getCmdQueryNextSequenceSend defines the command to query a next send sequence for a given channel
 func getCmdQueryNextSequenceSend() *cobra.Command {
 	cmd := &cobra.Command{
diff --git a/modules/core/04-channel/v2/keeper/grpc_query.go b/modules/core/04-channel/v2/keeper/grpc_query.go
index 3f5c7b1e59d..56a6b224aba 100644
--- a/modules/core/04-channel/v2/keeper/grpc_query.go
+++ b/modules/core/04-channel/v2/keeper/grpc_query.go
@@ -51,6 +51,24 @@ func (q *queryServer) Channel(ctx context.Context, req *types.QueryChannelReques
 	return types.NewQueryChannelResponse(channel), nil
 }
 
+// ChannelClientState implements the Query/ChannelClientState gRPC method
+func (q *queryServer) ChannelClientState(ctx context.Context, req *types.QueryChannelClientStateRequest) (*types.QueryChannelClientStateResponse, error) {
+	if req == nil {
+		return nil, status.Error(codes.InvalidArgument, "empty request")
+	}
+
+	if err := host.ChannelIdentifierValidator(req.ChannelId); err != nil {
+		return nil, status.Error(codes.InvalidArgument, err.Error())
+	}
+
+	_, found := q.GetChannel(ctx, req.ChannelId)
+	if !found {
+		return nil, status.Error(codes.NotFound, errorsmod.Wrapf(types.ErrChannelNotFound, "channel-id: %s", req.ChannelId).Error())
+	}
+
+	return nil, nil
+}
+
 // NextSequenceSend implements the Query/NextSequenceSend gRPC method
 func (q *queryServer) NextSequenceSend(ctx context.Context, req *types.QueryNextSequenceSendRequest) (*types.QueryNextSequenceSendResponse, error) {
 	if req == nil {
diff --git a/modules/core/04-channel/v2/types/query.go b/modules/core/04-channel/v2/types/query.go
index b02d0275537..af4b2d7ae45 100644
--- a/modules/core/04-channel/v2/types/query.go
+++ b/modules/core/04-channel/v2/types/query.go
@@ -16,6 +16,22 @@ func NewQueryChannelResponse(channel Channel) *QueryChannelResponse {
 	}
 }
 
+// NewQueryChannelClientStateRequest creates and returns a new ChannelClientState query request.
+func NewQueryChannelClientStateRequest(channelID string) *QueryChannelClientStateRequest {
+	return &QueryChannelClientStateRequest{
+		ChannelId: channelID,
+	}
+}
+
+// NewQueryChannelClientStateResponse creates and returns a new ChannelClientState query response.
+func NewQueryChannelClientStateResponse(identifiedClientState clienttypes.IdentifiedClientState, proof []byte, height clienttypes.Height) *QueryChannelClientStateResponse {
+	return &QueryChannelClientStateResponse{
+		IdentifiedClientState: &identifiedClientState,
+		Proof:                 proof,
+		ProofHeight:           height,
+	}
+}
+
 // NewQueryNextSequenceSendRequest creates a new next sequence send query.
 func NewQueryNextSequenceSendRequest(channelID string) *QueryNextSequenceSendRequest {
 	return &QueryNextSequenceSendRequest{
diff --git a/modules/core/04-channel/v2/types/query.pb.go b/modules/core/04-channel/v2/types/query.pb.go
index 5ae8436bd9b..37132d2bebc 100644
--- a/modules/core/04-channel/v2/types/query.pb.go
+++ b/modules/core/04-channel/v2/types/query.pb.go
@@ -122,6 +122,118 @@ func (m *QueryChannelResponse) GetChannel() Channel {
 	return Channel{}
 }
 
+// QueryChannelClientStateRequest is the request type for the Query/ClientState
+// RPC method
+type QueryChannelClientStateRequest struct {
+	// channel unique identifier
+	ChannelId string `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
+}
+
+func (m *QueryChannelClientStateRequest) Reset()         { *m = QueryChannelClientStateRequest{} }
+func (m *QueryChannelClientStateRequest) String() string { return proto.CompactTextString(m) }
+func (*QueryChannelClientStateRequest) ProtoMessage()    {}
+func (*QueryChannelClientStateRequest) Descriptor() ([]byte, []int) {
+	return fileDescriptor_a328cba4986edcab, []int{2}
+}
+func (m *QueryChannelClientStateRequest) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *QueryChannelClientStateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_QueryChannelClientStateRequest.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalToSizedBuffer(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (m *QueryChannelClientStateRequest) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_QueryChannelClientStateRequest.Merge(m, src)
+}
+func (m *QueryChannelClientStateRequest) XXX_Size() int {
+	return m.Size()
+}
+func (m *QueryChannelClientStateRequest) XXX_DiscardUnknown() {
+	xxx_messageInfo_QueryChannelClientStateRequest.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_QueryChannelClientStateRequest proto.InternalMessageInfo
+
+func (m *QueryChannelClientStateRequest) GetChannelId() string {
+	if m != nil {
+		return m.ChannelId
+	}
+	return ""
+}
+
+// QueryChannelClientStateResponse is the Response type for the
+// Query/QueryChannelClientState RPC method
+type QueryChannelClientStateResponse struct {
+	// client state associated with the channel
+	IdentifiedClientState *types.IdentifiedClientState `protobuf:"bytes,1,opt,name=identified_client_state,json=identifiedClientState,proto3" json:"identified_client_state,omitempty"`
+	// merkle proof of existence
+	Proof []byte `protobuf:"bytes,2,opt,name=proof,proto3" json:"proof,omitempty"`
+	// height at which the proof was retrieved
+	ProofHeight types.Height `protobuf:"bytes,3,opt,name=proof_height,json=proofHeight,proto3" json:"proof_height"`
+}
+
+func (m *QueryChannelClientStateResponse) Reset()         { *m = QueryChannelClientStateResponse{} }
+func (m *QueryChannelClientStateResponse) String() string { return proto.CompactTextString(m) }
+func (*QueryChannelClientStateResponse) ProtoMessage()    {}
+func (*QueryChannelClientStateResponse) Descriptor() ([]byte, []int) {
+	return fileDescriptor_a328cba4986edcab, []int{3}
+}
+func (m *QueryChannelClientStateResponse) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *QueryChannelClientStateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_QueryChannelClientStateResponse.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalToSizedBuffer(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (m *QueryChannelClientStateResponse) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_QueryChannelClientStateResponse.Merge(m, src)
+}
+func (m *QueryChannelClientStateResponse) XXX_Size() int {
+	return m.Size()
+}
+func (m *QueryChannelClientStateResponse) XXX_DiscardUnknown() {
+	xxx_messageInfo_QueryChannelClientStateResponse.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_QueryChannelClientStateResponse proto.InternalMessageInfo
+
+func (m *QueryChannelClientStateResponse) GetIdentifiedClientState() *types.IdentifiedClientState {
+	if m != nil {
+		return m.IdentifiedClientState
+	}
+	return nil
+}
+
+func (m *QueryChannelClientStateResponse) GetProof() []byte {
+	if m != nil {
+		return m.Proof
+	}
+	return nil
+}
+
+func (m *QueryChannelClientStateResponse) GetProofHeight() types.Height {
+	if m != nil {
+		return m.ProofHeight
+	}
+	return types.Height{}
+}
+
 // QueryNextSequenceSendRequest is the request type for the Query/QueryNextSequenceSend RPC method
 type QueryNextSequenceSendRequest struct {
 	// channel unique identifier
@@ -132,7 +244,7 @@ func (m *QueryNextSequenceSendRequest) Reset()         { *m = QueryNextSequenceS
 func (m *QueryNextSequenceSendRequest) String() string { return proto.CompactTextString(m) }
 func (*QueryNextSequenceSendRequest) ProtoMessage()    {}
 func (*QueryNextSequenceSendRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a328cba4986edcab, []int{2}
+	return fileDescriptor_a328cba4986edcab, []int{4}
 }
 func (m *QueryNextSequenceSendRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -182,7 +294,7 @@ func (m *QueryNextSequenceSendResponse) Reset()         { *m = QueryNextSequence
 func (m *QueryNextSequenceSendResponse) String() string { return proto.CompactTextString(m) }
 func (*QueryNextSequenceSendResponse) ProtoMessage()    {}
 func (*QueryNextSequenceSendResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a328cba4986edcab, []int{3}
+	return fileDescriptor_a328cba4986edcab, []int{5}
 }
 func (m *QueryNextSequenceSendResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -244,7 +356,7 @@ func (m *QueryPacketCommitmentRequest) Reset()         { *m = QueryPacketCommitm
 func (m *QueryPacketCommitmentRequest) String() string { return proto.CompactTextString(m) }
 func (*QueryPacketCommitmentRequest) ProtoMessage()    {}
 func (*QueryPacketCommitmentRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a328cba4986edcab, []int{4}
+	return fileDescriptor_a328cba4986edcab, []int{6}
 }
 func (m *QueryPacketCommitmentRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -301,7 +413,7 @@ func (m *QueryPacketCommitmentResponse) Reset()         { *m = QueryPacketCommit
 func (m *QueryPacketCommitmentResponse) String() string { return proto.CompactTextString(m) }
 func (*QueryPacketCommitmentResponse) ProtoMessage()    {}
 func (*QueryPacketCommitmentResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a328cba4986edcab, []int{5}
+	return fileDescriptor_a328cba4986edcab, []int{7}
 }
 func (m *QueryPacketCommitmentResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -363,7 +475,7 @@ func (m *QueryPacketCommitmentsRequest) Reset()         { *m = QueryPacketCommit
 func (m *QueryPacketCommitmentsRequest) String() string { return proto.CompactTextString(m) }
 func (*QueryPacketCommitmentsRequest) ProtoMessage()    {}
 func (*QueryPacketCommitmentsRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a328cba4986edcab, []int{6}
+	return fileDescriptor_a328cba4986edcab, []int{8}
 }
 func (m *QueryPacketCommitmentsRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -420,7 +532,7 @@ func (m *QueryPacketCommitmentsResponse) Reset()         { *m = QueryPacketCommi
 func (m *QueryPacketCommitmentsResponse) String() string { return proto.CompactTextString(m) }
 func (*QueryPacketCommitmentsResponse) ProtoMessage()    {}
 func (*QueryPacketCommitmentsResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a328cba4986edcab, []int{7}
+	return fileDescriptor_a328cba4986edcab, []int{9}
 }
 func (m *QueryPacketCommitmentsResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -482,7 +594,7 @@ func (m *QueryPacketAcknowledgementRequest) Reset()         { *m = QueryPacketAc
 func (m *QueryPacketAcknowledgementRequest) String() string { return proto.CompactTextString(m) }
 func (*QueryPacketAcknowledgementRequest) ProtoMessage()    {}
 func (*QueryPacketAcknowledgementRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a328cba4986edcab, []int{8}
+	return fileDescriptor_a328cba4986edcab, []int{10}
 }
 func (m *QueryPacketAcknowledgementRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -539,7 +651,7 @@ func (m *QueryPacketAcknowledgementResponse) Reset()         { *m = QueryPacketA
 func (m *QueryPacketAcknowledgementResponse) String() string { return proto.CompactTextString(m) }
 func (*QueryPacketAcknowledgementResponse) ProtoMessage()    {}
 func (*QueryPacketAcknowledgementResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a328cba4986edcab, []int{9}
+	return fileDescriptor_a328cba4986edcab, []int{11}
 }
 func (m *QueryPacketAcknowledgementResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -604,7 +716,7 @@ func (m *QueryPacketAcknowledgementsRequest) Reset()         { *m = QueryPacketA
 func (m *QueryPacketAcknowledgementsRequest) String() string { return proto.CompactTextString(m) }
 func (*QueryPacketAcknowledgementsRequest) ProtoMessage()    {}
 func (*QueryPacketAcknowledgementsRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a328cba4986edcab, []int{10}
+	return fileDescriptor_a328cba4986edcab, []int{12}
 }
 func (m *QueryPacketAcknowledgementsRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -668,7 +780,7 @@ func (m *QueryPacketAcknowledgementsResponse) Reset()         { *m = QueryPacket
 func (m *QueryPacketAcknowledgementsResponse) String() string { return proto.CompactTextString(m) }
 func (*QueryPacketAcknowledgementsResponse) ProtoMessage()    {}
 func (*QueryPacketAcknowledgementsResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a328cba4986edcab, []int{11}
+	return fileDescriptor_a328cba4986edcab, []int{13}
 }
 func (m *QueryPacketAcknowledgementsResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -732,7 +844,7 @@ func (m *QueryPacketReceiptRequest) Reset()         { *m = QueryPacketReceiptReq
 func (m *QueryPacketReceiptRequest) String() string { return proto.CompactTextString(m) }
 func (*QueryPacketReceiptRequest) ProtoMessage()    {}
 func (*QueryPacketReceiptRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a328cba4986edcab, []int{12}
+	return fileDescriptor_a328cba4986edcab, []int{14}
 }
 func (m *QueryPacketReceiptRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -796,7 +908,7 @@ func (m *QueryPacketReceiptResponse) Reset()         { *m = QueryPacketReceiptRe
 func (m *QueryPacketReceiptResponse) String() string { return proto.CompactTextString(m) }
 func (*QueryPacketReceiptResponse) ProtoMessage()    {}
 func (*QueryPacketReceiptResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a328cba4986edcab, []int{13}
+	return fileDescriptor_a328cba4986edcab, []int{15}
 }
 func (m *QueryPacketReceiptResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -858,7 +970,7 @@ func (m *QueryUnreceivedPacketsRequest) Reset()         { *m = QueryUnreceivedPa
 func (m *QueryUnreceivedPacketsRequest) String() string { return proto.CompactTextString(m) }
 func (*QueryUnreceivedPacketsRequest) ProtoMessage()    {}
 func (*QueryUnreceivedPacketsRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a328cba4986edcab, []int{14}
+	return fileDescriptor_a328cba4986edcab, []int{16}
 }
 func (m *QueryUnreceivedPacketsRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -913,7 +1025,7 @@ func (m *QueryUnreceivedPacketsResponse) Reset()         { *m = QueryUnreceivedP
 func (m *QueryUnreceivedPacketsResponse) String() string { return proto.CompactTextString(m) }
 func (*QueryUnreceivedPacketsResponse) ProtoMessage()    {}
 func (*QueryUnreceivedPacketsResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a328cba4986edcab, []int{15}
+	return fileDescriptor_a328cba4986edcab, []int{17}
 }
 func (m *QueryUnreceivedPacketsResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -969,7 +1081,7 @@ func (m *QueryUnreceivedAcksRequest) Reset()         { *m = QueryUnreceivedAcksR
 func (m *QueryUnreceivedAcksRequest) String() string { return proto.CompactTextString(m) }
 func (*QueryUnreceivedAcksRequest) ProtoMessage()    {}
 func (*QueryUnreceivedAcksRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a328cba4986edcab, []int{16}
+	return fileDescriptor_a328cba4986edcab, []int{18}
 }
 func (m *QueryUnreceivedAcksRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -1025,7 +1137,7 @@ func (m *QueryUnreceivedAcksResponse) Reset()         { *m = QueryUnreceivedAcks
 func (m *QueryUnreceivedAcksResponse) String() string { return proto.CompactTextString(m) }
 func (*QueryUnreceivedAcksResponse) ProtoMessage()    {}
 func (*QueryUnreceivedAcksResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a328cba4986edcab, []int{17}
+	return fileDescriptor_a328cba4986edcab, []int{19}
 }
 func (m *QueryUnreceivedAcksResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -1071,6 +1183,8 @@ func (m *QueryUnreceivedAcksResponse) GetHeight() types.Height {
 func init() {
 	proto.RegisterType((*QueryChannelRequest)(nil), "ibc.core.channel.v2.QueryChannelRequest")
 	proto.RegisterType((*QueryChannelResponse)(nil), "ibc.core.channel.v2.QueryChannelResponse")
+	proto.RegisterType((*QueryChannelClientStateRequest)(nil), "ibc.core.channel.v2.QueryChannelClientStateRequest")
+	proto.RegisterType((*QueryChannelClientStateResponse)(nil), "ibc.core.channel.v2.QueryChannelClientStateResponse")
 	proto.RegisterType((*QueryNextSequenceSendRequest)(nil), "ibc.core.channel.v2.QueryNextSequenceSendRequest")
 	proto.RegisterType((*QueryNextSequenceSendResponse)(nil), "ibc.core.channel.v2.QueryNextSequenceSendResponse")
 	proto.RegisterType((*QueryPacketCommitmentRequest)(nil), "ibc.core.channel.v2.QueryPacketCommitmentRequest")
@@ -1092,77 +1206,82 @@ func init() {
 func init() { proto.RegisterFile("ibc/core/channel/v2/query.proto", fileDescriptor_a328cba4986edcab) }
 
 var fileDescriptor_a328cba4986edcab = []byte{
-	// 1113 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0x5f, 0x6f, 0xdb, 0x54,
-	0x14, 0xef, 0x6d, 0xba, 0xb5, 0x3d, 0x29, 0xa3, 0xbb, 0x2b, 0x90, 0x79, 0x5d, 0x96, 0x19, 0x09,
-	0xc2, 0xb4, 0xf9, 0x36, 0xd9, 0x04, 0x43, 0xda, 0x40, 0x6d, 0x19, 0x5b, 0x27, 0x40, 0xc5, 0x05,
-	0x24, 0xd0, 0xb4, 0xc8, 0x71, 0xee, 0x5c, 0x2b, 0x89, 0xaf, 0x17, 0x3b, 0xa1, 0xd3, 0xd4, 0x17,
-	0x1e, 0x78, 0x46, 0xec, 0x8d, 0x4f, 0x00, 0x2f, 0x7c, 0x05, 0x90, 0x78, 0x99, 0xb4, 0x97, 0x49,
-	0x7b, 0x80, 0x27, 0x04, 0x2d, 0x12, 0xdf, 0x80, 0x67, 0x94, 0xeb, 0xeb, 0xf8, 0x4f, 0x1c, 0xd7,
-	0xde, 0x56, 0xc4, 0x9b, 0x7d, 0x73, 0xfe, 0xfc, 0x7e, 0xe7, 0xfe, 0x8e, 0xcf, 0x51, 0xe0, 0x8c,
-	0xd9, 0xd4, 0x89, 0xce, 0x7a, 0x94, 0xe8, 0xdb, 0x9a, 0x65, 0xd1, 0x0e, 0x19, 0xd4, 0xc9, 0xdd,
-	0x3e, 0xed, 0xdd, 0x53, 0xec, 0x1e, 0x73, 0x19, 0x3e, 0x61, 0x36, 0x75, 0x65, 0x68, 0xa0, 0x08,
-	0x03, 0x65, 0x50, 0x97, 0xce, 0xe9, 0xcc, 0xe9, 0x32, 0x87, 0x34, 0x35, 0x87, 0x7a, 0xd6, 0x64,
-	0x50, 0x6b, 0x52, 0x57, 0xab, 0x11, 0x5b, 0x33, 0x4c, 0x4b, 0x73, 0x4d, 0x66, 0x79, 0x01, 0xa4,
-	0xb3, 0x49, 0x19, 0xfc, 0x58, 0x29, 0x26, 0x06, 0xb5, 0xa8, 0x63, 0x3a, 0xc2, 0x24, 0x84, 0xb3,
-	0x63, 0x52, 0xcb, 0x25, 0x83, 0x9a, 0x78, 0x12, 0x06, 0xcb, 0x06, 0x63, 0x46, 0x87, 0x12, 0xcd,
-	0x36, 0x89, 0x66, 0x59, 0xcc, 0xe5, 0x18, 0x7c, 0xf7, 0x25, 0x83, 0x19, 0x8c, 0x3f, 0x92, 0xe1,
-	0x93, 0x77, 0x2a, 0x5f, 0x82, 0x13, 0x1f, 0x0f, 0xc1, 0xaf, 0x7b, 0x59, 0x55, 0x7a, 0xb7, 0x4f,
-	0x1d, 0x17, 0x9f, 0x06, 0x10, 0x38, 0x1a, 0x66, 0xab, 0x84, 0x2a, 0xa8, 0x3a, 0xaf, 0xce, 0x8b,
-	0x93, 0x8d, 0x96, 0xfc, 0x09, 0x2c, 0x45, 0xbd, 0x1c, 0x9b, 0x59, 0x0e, 0xc5, 0x57, 0x60, 0x56,
-	0x18, 0x71, 0x9f, 0x62, 0x7d, 0x59, 0x49, 0xa8, 0x9d, 0x22, 0xdc, 0xd6, 0x66, 0x1e, 0xfe, 0x7e,
-	0x66, 0x4a, 0xf5, 0x5d, 0xe4, 0xab, 0xb0, 0xcc, 0xa3, 0x7e, 0x44, 0x77, 0xdc, 0xad, 0x21, 0x10,
-	0x4b, 0xa7, 0x5b, 0xd4, 0x6a, 0x65, 0x04, 0xf5, 0x3d, 0x82, 0xd3, 0x13, 0xfc, 0x05, 0xbc, 0xf3,
-	0x80, 0x2d, 0xba, 0xe3, 0x36, 0x1c, 0xf1, 0x63, 0xc3, 0xa1, 0x96, 0x17, 0x68, 0x46, 0x5d, 0xb4,
-	0x62, 0x5e, 0x78, 0x09, 0x8e, 0xd8, 0x3d, 0xc6, 0xee, 0x94, 0xa6, 0x2b, 0xa8, 0xba, 0xa0, 0x7a,
-	0x2f, 0x78, 0x1d, 0x16, 0xf8, 0x43, 0x63, 0x9b, 0x9a, 0xc6, 0xb6, 0x5b, 0x2a, 0x70, 0x9e, 0x52,
-	0x88, 0xa7, 0x77, 0x25, 0x83, 0x9a, 0x72, 0x83, 0x5b, 0x08, 0x96, 0x45, 0xee, 0xe5, 0x1d, 0xc9,
-	0x9f, 0x0b, 0xa6, 0x9b, 0x9a, 0xde, 0xa6, 0xee, 0x3a, 0xeb, 0x76, 0x4d, 0xb7, 0x4b, 0x2d, 0x37,
-	0x1b, 0x53, 0x2c, 0xc1, 0x9c, 0x4f, 0x81, 0x83, 0x9b, 0x51, 0x47, 0xef, 0xf2, 0x77, 0x7e, 0x15,
-	0xc6, 0x63, 0x8b, 0x2a, 0x94, 0x01, 0xf4, 0xd1, 0x29, 0x0f, 0xbe, 0xa0, 0x86, 0x4e, 0x0e, 0x93,
-	0xf7, 0xd7, 0x93, 0xc0, 0x39, 0x19, 0x99, 0xbf, 0x0f, 0x10, 0x74, 0x17, 0x07, 0x58, 0xac, 0xbf,
-	0xa6, 0x78, 0xad, 0xa8, 0x0c, 0x5b, 0x51, 0xf1, 0x1a, 0x57, 0xb4, 0xa2, 0xb2, 0xa9, 0x19, 0x54,
-	0x84, 0x56, 0x43, 0x9e, 0xf2, 0xdf, 0x08, 0xca, 0x93, 0x80, 0x88, 0x32, 0xad, 0x41, 0x31, 0x28,
-	0x8a, 0x53, 0x42, 0x95, 0x42, 0xb5, 0x58, 0xaf, 0x24, 0xea, 0xd9, 0x0b, 0xb2, 0xe5, 0x6a, 0x2e,
-	0x55, 0xc3, 0x4e, 0xf8, 0x7a, 0x02, 0xdc, 0xd7, 0x0f, 0x84, 0xeb, 0x01, 0x08, 0xe3, 0xc5, 0x97,
-	0xe1, 0x68, 0xce, 0xba, 0x0b, 0x7b, 0xf9, 0x36, 0x9c, 0x0d, 0x11, 0x5d, 0xd5, 0xdb, 0x16, 0xfb,
-	0xb2, 0x43, 0x5b, 0x06, 0x7d, 0x4e, 0x7a, 0xfb, 0x01, 0x81, 0x9c, 0x96, 0x40, 0x54, 0xb3, 0x0a,
-	0x2f, 0x6a, 0xd1, 0x9f, 0x84, 0xf2, 0xe2, 0xc7, 0x87, 0x29, 0xbf, 0x47, 0xa9, 0x58, 0xff, 0x63,
-	0x0d, 0xe2, 0x77, 0xe0, 0x94, 0xcd, 0x71, 0x34, 0x02, 0xc9, 0x8c, 0x3e, 0x4d, 0x4e, 0xa9, 0x50,
-	0x29, 0x54, 0x67, 0xd4, 0x93, 0x76, 0x4c, 0xa0, 0xfe, 0x27, 0xca, 0x91, 0xff, 0x41, 0xf0, 0x6a,
-	0x2a, 0x1b, 0x51, 0xfa, 0x0f, 0x60, 0x31, 0x56, 0xe3, 0xec, 0x6a, 0x1e, 0xf3, 0xfc, 0x3f, 0x48,
-	0x9a, 0xc1, 0xc9, 0x10, 0x6f, 0x95, 0xea, 0xd4, 0xb4, 0x47, 0x52, 0x7e, 0x05, 0x66, 0x6d, 0xd6,
-	0x73, 0x83, 0x9b, 0x3b, 0x3a, 0x7c, 0xdd, 0x68, 0xc5, 0x6e, 0x75, 0x3a, 0x4d, 0xe3, 0x85, 0x98,
-	0xc6, 0x1f, 0x20, 0x90, 0x92, 0x32, 0x8a, 0x02, 0x4b, 0x30, 0xd7, 0x1b, 0x1e, 0x0d, 0xa8, 0x17,
-	0x77, 0x4e, 0x1d, 0xbd, 0x07, 0x6a, 0x2e, 0xa4, 0xa9, 0x79, 0xe6, 0x69, 0xd4, 0x7c, 0x4b, 0x7c,
-	0x4b, 0x3f, 0xb5, 0xfc, 0x6c, 0x1e, 0xbc, 0xac, 0x3a, 0x5e, 0x86, 0xf9, 0x40, 0x6d, 0xd3, 0x5c,
-	0x6d, 0xc1, 0x81, 0xbc, 0x23, 0x3e, 0x90, 0x09, 0xd1, 0x05, 0xed, 0x88, 0x3f, 0x8a, 0xf9, 0x87,
-	0xae, 0x77, 0x3a, 0xe7, 0xf5, 0x76, 0x45, 0xb1, 0x83, 0xcc, 0xab, 0x7a, 0x3b, 0x2b, 0xa9, 0x15,
-	0x58, 0x12, 0x4d, 0xa5, 0xe9, 0xed, 0x46, 0x9c, 0x1f, 0xb6, 0xfd, 0x56, 0x09, 0xda, 0xa8, 0x0f,
-	0xa7, 0x12, 0xd3, 0x1d, 0x2e, 0xcb, 0xfa, 0x8f, 0xc7, 0xe0, 0x08, 0xcf, 0x8b, 0xbf, 0x45, 0x30,
-	0x2b, 0x36, 0x22, 0x5c, 0x4d, 0xec, 0xc8, 0x84, 0x0d, 0x4d, 0x7a, 0x23, 0x83, 0xa5, 0x47, 0x41,
-	0xae, 0x7f, 0xf5, 0xe4, 0xaf, 0x07, 0xd3, 0xe7, 0xf1, 0x39, 0x92, 0xb2, 0x87, 0x3a, 0xe4, 0x7e,
-	0x50, 0xd7, 0x5d, 0xfc, 0x33, 0x82, 0xc5, 0xf8, 0x1e, 0x85, 0x6b, 0x93, 0x73, 0x4e, 0xd8, 0xd9,
-	0xa4, 0x7a, 0x1e, 0x17, 0x81, 0xf7, 0x1a, 0xc7, 0xfb, 0x2e, 0xbe, 0x9a, 0x1d, 0x2f, 0x19, 0xdf,
-	0xeb, 0xf0, 0x23, 0x04, 0x8b, 0xf1, 0xf1, 0x9e, 0x46, 0x61, 0xc2, 0x32, 0x96, 0x46, 0x61, 0xd2,
-	0x8e, 0x25, 0x6f, 0x72, 0x0a, 0x37, 0xf1, 0x8d, 0x1c, 0x14, 0xc6, 0x86, 0x81, 0x43, 0xee, 0xfb,
-	0x8c, 0x76, 0xf1, 0x2f, 0x08, 0x8e, 0x8f, 0x2d, 0x2b, 0x38, 0x07, 0x36, 0xbf, 0x83, 0xa4, 0x8b,
-	0xb9, 0x7c, 0x9e, 0xe1, 0x4e, 0xc6, 0x09, 0xe1, 0x27, 0x08, 0x5e, 0x4a, 0x1c, 0x57, 0xf8, 0xcd,
-	0x83, 0x50, 0x25, 0xaf, 0x2e, 0xd2, 0x5b, 0xb9, 0xfd, 0x04, 0xa3, 0x0d, 0xce, 0x68, 0x1d, 0xaf,
-	0xe6, 0x67, 0xa4, 0xe9, 0xed, 0xc8, 0xdd, 0xfc, 0x8a, 0xe0, 0xe5, 0xe4, 0x21, 0x8c, 0xf3, 0xc2,
-	0x1b, 0xdd, 0xd2, 0xe5, 0xfc, 0x8e, 0x82, 0xd8, 0x4d, 0x4e, 0xec, 0x3d, 0xbc, 0xf6, 0x54, 0xc4,
-	0xa2, 0xf0, 0x7f, 0x42, 0xf0, 0x42, 0x64, 0xe8, 0x61, 0xe5, 0x20, 0x5c, 0xd1, 0x79, 0x2c, 0x91,
-	0xcc, 0xf6, 0x02, 0xfe, 0x87, 0x1c, 0xfe, 0x75, 0x7c, 0x2d, 0x3f, 0xfc, 0x9e, 0x17, 0x2a, 0x72,
-	0x37, 0x7b, 0x08, 0x8e, 0x8f, 0xcd, 0xb0, 0xb4, 0xbe, 0x99, 0x34, 0x4e, 0xd3, 0xfa, 0x66, 0xe2,
-	0x90, 0x94, 0x5b, 0x9c, 0xcd, 0x6d, 0x7c, 0xeb, 0x39, 0x7d, 0x08, 0x9c, 0x5d, 0xd2, 0x1f, 0x25,
-	0x6b, 0xd8, 0x82, 0xce, 0x9f, 0x08, 0x8e, 0x45, 0xe7, 0x17, 0x26, 0x59, 0xd0, 0x86, 0x06, 0xab,
-	0xb4, 0x92, 0xdd, 0x41, 0x70, 0xeb, 0x70, 0x6e, 0x77, 0x70, 0xeb, 0x19, 0xb9, 0x25, 0x0d, 0xec,
-	0x08, 0xcd, 0x61, 0xbf, 0xad, 0x7d, 0xf6, 0x70, 0xaf, 0x8c, 0x1e, 0xef, 0x95, 0xd1, 0x1f, 0x7b,
-	0x65, 0xf4, 0xcd, 0x7e, 0x79, 0xea, 0xf1, 0x7e, 0x79, 0xea, 0xb7, 0xfd, 0xf2, 0xd4, 0x17, 0x57,
-	0x0c, 0xd3, 0xdd, 0xee, 0x37, 0x15, 0x9d, 0x75, 0x89, 0xf8, 0x57, 0xc6, 0x6c, 0xea, 0x17, 0x0c,
-	0x46, 0x06, 0x6f, 0x93, 0x2e, 0x6b, 0xf5, 0x3b, 0xd4, 0xf1, 0xe0, 0xad, 0x5c, 0xba, 0x10, 0x42,
-	0xe8, 0xde, 0xb3, 0xa9, 0xd3, 0x3c, 0xca, 0xff, 0x08, 0xb9, 0xf8, 0x6f, 0x00, 0x00, 0x00, 0xff,
-	0xff, 0xd2, 0x18, 0x54, 0x2c, 0x07, 0x12, 0x00, 0x00,
+	// 1197 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0xcf, 0x6f, 0xdc, 0x44,
+	0x14, 0xce, 0x64, 0xd3, 0xfc, 0x78, 0x09, 0x34, 0x9d, 0xa6, 0x34, 0x75, 0xd3, 0x4d, 0x6a, 0x24,
+	0xd8, 0x56, 0xad, 0x27, 0xd9, 0x44, 0xb4, 0x95, 0x5a, 0xa2, 0x24, 0x94, 0x36, 0x15, 0xa0, 0xe0,
+	0x00, 0x12, 0xa8, 0xea, 0xca, 0xeb, 0x9d, 0x38, 0x56, 0x76, 0x3d, 0xee, 0x8e, 0x77, 0x49, 0x55,
+	0xe5, 0xc2, 0x81, 0x33, 0xa2, 0x37, 0xfe, 0x02, 0xf8, 0x2b, 0x40, 0xe2, 0x52, 0xa9, 0x97, 0x4a,
+	0x3d, 0xc0, 0x89, 0x1f, 0x09, 0x12, 0x67, 0x2e, 0x9c, 0xd1, 0x8e, 0xc7, 0xbb, 0x5e, 0xaf, 0xd7,
+	0xb1, 0xdb, 0x06, 0xf5, 0x66, 0xcf, 0xbe, 0xef, 0xbd, 0xef, 0x7b, 0xf3, 0xde, 0xf3, 0xd3, 0xc2,
+	0xac, 0x5d, 0x36, 0x89, 0xc9, 0xea, 0x94, 0x98, 0xdb, 0x86, 0xe3, 0xd0, 0x2a, 0x69, 0x16, 0xc9,
+	0xfd, 0x06, 0xad, 0x3f, 0xd0, 0xdc, 0x3a, 0xf3, 0x18, 0x3e, 0x69, 0x97, 0x4d, 0xad, 0x65, 0xa0,
+	0x49, 0x03, 0xad, 0x59, 0x54, 0x2e, 0x9a, 0x8c, 0xd7, 0x18, 0x27, 0x65, 0x83, 0x53, 0xdf, 0x9a,
+	0x34, 0x17, 0xca, 0xd4, 0x33, 0x16, 0x88, 0x6b, 0x58, 0xb6, 0x63, 0x78, 0x36, 0x73, 0x7c, 0x07,
+	0xca, 0xf9, 0xb8, 0x08, 0x81, 0xaf, 0x04, 0x13, 0x8b, 0x3a, 0x94, 0xdb, 0x5c, 0x9a, 0x84, 0x78,
+	0x56, 0x6d, 0xea, 0x78, 0xa4, 0xb9, 0x20, 0x9f, 0xa4, 0xc1, 0x8c, 0xc5, 0x98, 0x55, 0xa5, 0xc4,
+	0x70, 0x6d, 0x62, 0x38, 0x0e, 0xf3, 0x04, 0x87, 0x00, 0x3e, 0x65, 0x31, 0x8b, 0x89, 0x47, 0xd2,
+	0x7a, 0xf2, 0x4f, 0xd5, 0x25, 0x38, 0xf9, 0x71, 0x8b, 0xfc, 0x9a, 0x1f, 0x55, 0xa7, 0xf7, 0x1b,
+	0x94, 0x7b, 0xf8, 0x1c, 0x80, 0xe4, 0x51, 0xb2, 0x2b, 0xd3, 0x68, 0x0e, 0x15, 0xc6, 0xf4, 0x31,
+	0x79, 0xb2, 0x5e, 0x51, 0x3f, 0x81, 0xa9, 0x6e, 0x14, 0x77, 0x99, 0xc3, 0x29, 0xbe, 0x0e, 0x23,
+	0xd2, 0x48, 0x60, 0xc6, 0x8b, 0x33, 0x5a, 0x4c, 0xee, 0x34, 0x09, 0x5b, 0x1d, 0x7a, 0xfc, 0xdb,
+	0xec, 0x80, 0x1e, 0x40, 0xd4, 0x65, 0xc8, 0x87, 0xbd, 0xae, 0x09, 0x6d, 0x9b, 0x9e, 0xe1, 0xd1,
+	0x94, 0xb4, 0x7e, 0x47, 0x30, 0xdb, 0xd7, 0x83, 0xa4, 0x68, 0xc0, 0x69, 0xbb, 0x42, 0x1d, 0xcf,
+	0xde, 0xb2, 0x69, 0xa5, 0xe4, 0xe7, 0xaf, 0xc4, 0x5b, 0x26, 0x92, 0xf2, 0x85, 0x10, 0x65, 0x3f,
+	0xbb, 0xcd, 0x05, 0x6d, 0xbd, 0x0d, 0x09, 0xfb, 0x3c, 0x65, 0xc7, 0x1d, 0xe3, 0x29, 0x38, 0xe6,
+	0xd6, 0x19, 0xdb, 0x9a, 0x1e, 0x9c, 0x43, 0x85, 0x09, 0xdd, 0x7f, 0xc1, 0x6b, 0x30, 0x21, 0x1e,
+	0x4a, 0xdb, 0xd4, 0xb6, 0xb6, 0xbd, 0xe9, 0x9c, 0x88, 0xa6, 0xc4, 0x45, 0xbb, 0x2d, 0x2c, 0x64,
+	0x7a, 0xc6, 0x05, 0xca, 0x3f, 0x52, 0x6f, 0xc0, 0x8c, 0x10, 0xf8, 0x11, 0xdd, 0xf5, 0x36, 0x5b,
+	0x49, 0x71, 0x4c, 0xba, 0x49, 0x9d, 0x4a, 0xca, 0x04, 0x7d, 0x8f, 0xe0, 0x5c, 0x1f, 0xbc, 0x4c,
+	0xcf, 0x25, 0xc0, 0x0e, 0xdd, 0xf5, 0x4a, 0x5c, 0xfe, 0x58, 0xe2, 0xd4, 0xf1, 0x1d, 0x0d, 0xe9,
+	0x93, 0x4e, 0x04, 0x75, 0x94, 0x4a, 0x3f, 0x97, 0x4a, 0x37, 0x0c, 0x73, 0x87, 0x7a, 0x6b, 0xac,
+	0x56, 0xb3, 0xbd, 0x1a, 0x75, 0xbc, 0x74, 0x4a, 0xb1, 0x02, 0xa3, 0x81, 0x04, 0x41, 0x6e, 0x48,
+	0x6f, 0xbf, 0xab, 0xdf, 0x05, 0x59, 0xe8, 0xf5, 0x2d, 0xb3, 0x90, 0x07, 0x30, 0xdb, 0xa7, 0xc2,
+	0xf9, 0x84, 0x1e, 0x3a, 0x39, 0x4a, 0xdd, 0x5f, 0xf7, 0x23, 0xc7, 0x53, 0x2a, 0x7f, 0x1f, 0xa0,
+	0x33, 0x80, 0x04, 0xc1, 0xf1, 0xe2, 0x5b, 0x9a, 0x3f, 0xad, 0xb4, 0xd6, 0xb4, 0xd2, 0xfc, 0xd9,
+	0x26, 0xa7, 0x95, 0xb6, 0x61, 0x58, 0x41, 0x7f, 0xe9, 0x21, 0xa4, 0xfa, 0x37, 0x92, 0xed, 0x18,
+	0x43, 0x44, 0xa6, 0x69, 0x15, 0xc6, 0x3b, 0x49, 0xe1, 0xd3, 0x68, 0x2e, 0x57, 0x18, 0x2f, 0xce,
+	0xc5, 0xb6, 0xbc, 0xef, 0xc4, 0x6f, 0x9b, 0x30, 0x08, 0xdf, 0x8a, 0xa1, 0xfb, 0xf6, 0xa1, 0x74,
+	0x7d, 0x02, 0x61, 0xbe, 0xf8, 0x2a, 0x0c, 0x67, 0xcc, 0xbb, 0xb4, 0x57, 0xef, 0xc1, 0xf9, 0x90,
+	0xd0, 0x15, 0x73, 0xc7, 0x61, 0x5f, 0x56, 0x69, 0xc5, 0xa2, 0x2f, 0xa9, 0xde, 0x7e, 0x40, 0xa0,
+	0x26, 0x05, 0x90, 0xd9, 0x2c, 0xc0, 0x71, 0xa3, 0xfb, 0x27, 0x59, 0x79, 0xd1, 0xe3, 0xa3, 0x2c,
+	0xbf, 0x27, 0x89, 0x5c, 0xff, 0xe7, 0x1a, 0xc4, 0xef, 0xc2, 0x59, 0x57, 0xf0, 0x28, 0x75, 0x4a,
+	0xa6, 0x3d, 0x9a, 0xf8, 0x74, 0x6e, 0x2e, 0x57, 0x18, 0xd2, 0xcf, 0xb8, 0x91, 0x02, 0x0d, 0x46,
+	0x14, 0x57, 0xff, 0x45, 0xf0, 0x66, 0xa2, 0x1a, 0x99, 0xfa, 0x0f, 0x60, 0x32, 0x92, 0xe3, 0xf4,
+	0xd5, 0xdc, 0x83, 0x7c, 0x15, 0x4a, 0x9a, 0xc1, 0x99, 0x90, 0x6e, 0x9d, 0x9a, 0xd4, 0x76, 0xdb,
+	0xa5, 0x7c, 0x1a, 0x46, 0x5c, 0x56, 0xf7, 0x3a, 0x37, 0x37, 0xdc, 0x7a, 0x5d, 0xaf, 0x44, 0x6e,
+	0x75, 0x30, 0xa9, 0xc6, 0x73, 0x91, 0x1a, 0x7f, 0x84, 0x40, 0x89, 0x8b, 0x28, 0x13, 0xac, 0xc0,
+	0x68, 0xbd, 0x75, 0xd4, 0xa4, 0xbe, 0xdf, 0x51, 0xbd, 0xfd, 0xde, 0xa9, 0xe6, 0x5c, 0x52, 0x35,
+	0x0f, 0x3d, 0x4f, 0x35, 0xdf, 0x95, 0xb3, 0xf4, 0x53, 0x27, 0x88, 0xe6, 0xd3, 0x4b, 0x5b, 0xc7,
+	0x33, 0x30, 0xd6, 0xa9, 0xb6, 0x41, 0x51, 0x6d, 0x9d, 0x03, 0x75, 0x57, 0x0e, 0xc8, 0x18, 0xef,
+	0x52, 0x76, 0x17, 0x1e, 0x45, 0xf0, 0xa1, 0xeb, 0x1d, 0xcc, 0x78, 0xbd, 0x35, 0x99, 0xec, 0x4e,
+	0xe4, 0x15, 0x73, 0x27, 0xad, 0xa8, 0x79, 0x98, 0x92, 0x4d, 0x65, 0x98, 0x3b, 0xa5, 0xa8, 0x3e,
+	0xec, 0x06, 0xad, 0xd2, 0x69, 0xa3, 0x06, 0x9c, 0x8d, 0x0d, 0x77, 0xb4, 0x2a, 0x8b, 0xff, 0x1c,
+	0x87, 0x63, 0x22, 0x2e, 0xfe, 0x16, 0xc1, 0x88, 0xdc, 0xe9, 0x70, 0x21, 0xb6, 0x23, 0x63, 0x96,
+	0x58, 0xe5, 0x42, 0x0a, 0x4b, 0x5f, 0x82, 0x5a, 0xfc, 0xea, 0xd9, 0x5f, 0x8f, 0x06, 0x2f, 0xe1,
+	0x8b, 0x24, 0x61, 0x55, 0xe7, 0xe4, 0x61, 0x27, 0xaf, 0x7b, 0xf8, 0x27, 0x04, 0xb8, 0x77, 0xd1,
+	0xc4, 0x8b, 0x87, 0x46, 0xed, 0x5d, 0x6c, 0x95, 0xa5, 0x6c, 0x20, 0xc9, 0x7a, 0x59, 0xb0, 0xbe,
+	0x86, 0xaf, 0xa4, 0x67, 0x4d, 0xc2, 0x1b, 0x6f, 0x4b, 0xc2, 0x64, 0x74, 0x15, 0xc4, 0x0b, 0xfd,
+	0xb9, 0xf4, 0x59, 0x3b, 0x95, 0x62, 0x16, 0x88, 0x24, 0x7f, 0x53, 0x90, 0x5f, 0xc6, 0x37, 0x32,
+	0x90, 0xef, 0x5d, 0x4d, 0xf1, 0x13, 0x04, 0x93, 0xd1, 0x0d, 0x25, 0x49, 0x42, 0x9f, 0x7d, 0x32,
+	0x49, 0x42, 0xbf, 0x35, 0x51, 0xdd, 0x10, 0x12, 0xee, 0xe0, 0xdb, 0x19, 0x24, 0xf4, 0x7c, 0xcf,
+	0x38, 0x79, 0x18, 0x28, 0xda, 0xc3, 0x3f, 0x23, 0x38, 0xd1, 0xb3, 0x6f, 0xe1, 0x0c, 0xdc, 0x82,
+	0x21, 0xa0, 0x2c, 0x66, 0xc2, 0xbc, 0xc0, 0x9d, 0xf4, 0x0a, 0xc2, 0xcf, 0x10, 0x9c, 0x8a, 0xfd,
+	0xe2, 0xe2, 0x77, 0x0e, 0x63, 0x15, 0xbf, 0x7d, 0x29, 0x57, 0x32, 0xe3, 0xa4, 0xa2, 0x75, 0xa1,
+	0x68, 0x0d, 0xaf, 0x64, 0x57, 0x64, 0x98, 0x3b, 0x5d, 0x77, 0xf3, 0x0b, 0x82, 0x37, 0xe2, 0xf7,
+	0x08, 0x9c, 0x95, 0x5e, 0xfb, 0x96, 0xae, 0x66, 0x07, 0x4a, 0x61, 0x77, 0x84, 0xb0, 0xf7, 0xf0,
+	0xea, 0x73, 0x09, 0xeb, 0xa6, 0xff, 0x23, 0x82, 0xd7, 0xba, 0xbe, 0xdb, 0x58, 0x3b, 0x8c, 0x57,
+	0xf7, 0x4a, 0xa1, 0x90, 0xd4, 0xf6, 0x92, 0xfe, 0x87, 0x82, 0xfe, 0x2d, 0x7c, 0x33, 0x3b, 0xfd,
+	0xba, 0xef, 0xaa, 0xeb, 0x6e, 0xf6, 0x11, 0x9c, 0xe8, 0xf9, 0x0c, 0x27, 0xf5, 0x4d, 0xbf, 0x8d,
+	0x20, 0xa9, 0x6f, 0xfa, 0x7e, 0xe7, 0xd5, 0x8a, 0x50, 0x73, 0x0f, 0xdf, 0x7d, 0x49, 0x83, 0x80,
+	0xef, 0x91, 0x46, 0x3b, 0x58, 0xc9, 0x95, 0x72, 0xfe, 0x44, 0xf0, 0x7a, 0xf7, 0x27, 0x18, 0x93,
+	0x34, 0x6c, 0x43, 0xbb, 0x81, 0x32, 0x9f, 0x1e, 0x20, 0xb5, 0x55, 0x85, 0xb6, 0x2d, 0x5c, 0x79,
+	0x41, 0x6d, 0x71, 0x3b, 0x47, 0x97, 0xcc, 0x56, 0xbf, 0xad, 0x7e, 0xf6, 0x78, 0x3f, 0x8f, 0x9e,
+	0xee, 0xe7, 0xd1, 0x1f, 0xfb, 0x79, 0xf4, 0xcd, 0x41, 0x7e, 0xe0, 0xe9, 0x41, 0x7e, 0xe0, 0xd7,
+	0x83, 0xfc, 0xc0, 0x17, 0xd7, 0x2d, 0xdb, 0xdb, 0x6e, 0x94, 0x35, 0x93, 0xd5, 0x88, 0xfc, 0xef,
+	0xcd, 0x2e, 0x9b, 0x97, 0x2d, 0x46, 0x9a, 0xd7, 0x48, 0x8d, 0x55, 0x1a, 0x55, 0xca, 0x7d, 0x7a,
+	0xf3, 0x4b, 0x97, 0x43, 0x0c, 0xbd, 0x07, 0x2e, 0xe5, 0xe5, 0x61, 0xf1, 0x77, 0xd7, 0xe2, 0x7f,
+	0x01, 0x00, 0x00, 0xff, 0xff, 0x15, 0x99, 0x77, 0xb3, 0xed, 0x13, 0x00, 0x00,
 }
 
 // Reference imports to suppress errors if they are not otherwise used.
@@ -1179,6 +1298,9 @@ const _ = grpc.SupportPackageIsVersion4
 type QueryClient interface {
 	// Channel queries the counterparty of an IBC client.
 	Channel(ctx context.Context, in *QueryChannelRequest, opts ...grpc.CallOption) (*QueryChannelResponse, error)
+	// ChannelClientState queries for the client state for the channel associated
+	// with the provided channel identifiers.
+	ChannelClientState(ctx context.Context, in *QueryChannelClientStateRequest, opts ...grpc.CallOption) (*QueryChannelClientStateResponse, error)
 	// NextSequenceSend returns the next send sequence for a given channel.
 	NextSequenceSend(ctx context.Context, in *QueryNextSequenceSendRequest, opts ...grpc.CallOption) (*QueryNextSequenceSendResponse, error)
 	// PacketCommitment queries a stored packet commitment hash.
@@ -1214,6 +1336,15 @@ func (c *queryClient) Channel(ctx context.Context, in *QueryChannelRequest, opts
 	return out, nil
 }
 
+func (c *queryClient) ChannelClientState(ctx context.Context, in *QueryChannelClientStateRequest, opts ...grpc.CallOption) (*QueryChannelClientStateResponse, error) {
+	out := new(QueryChannelClientStateResponse)
+	err := c.cc.Invoke(ctx, "/ibc.core.channel.v2.Query/ChannelClientState", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
 func (c *queryClient) NextSequenceSend(ctx context.Context, in *QueryNextSequenceSendRequest, opts ...grpc.CallOption) (*QueryNextSequenceSendResponse, error) {
 	out := new(QueryNextSequenceSendResponse)
 	err := c.cc.Invoke(ctx, "/ibc.core.channel.v2.Query/NextSequenceSend", in, out, opts...)
@@ -1290,6 +1421,9 @@ func (c *queryClient) UnreceivedAcks(ctx context.Context, in *QueryUnreceivedAck
 type QueryServer interface {
 	// Channel queries the counterparty of an IBC client.
 	Channel(context.Context, *QueryChannelRequest) (*QueryChannelResponse, error)
+	// ChannelClientState queries for the client state for the channel associated
+	// with the provided channel identifiers.
+	ChannelClientState(context.Context, *QueryChannelClientStateRequest) (*QueryChannelClientStateResponse, error)
 	// NextSequenceSend returns the next send sequence for a given channel.
 	NextSequenceSend(context.Context, *QueryNextSequenceSendRequest) (*QueryNextSequenceSendResponse, error)
 	// PacketCommitment queries a stored packet commitment hash.
@@ -1315,6 +1449,9 @@ type UnimplementedQueryServer struct {
 func (*UnimplementedQueryServer) Channel(ctx context.Context, req *QueryChannelRequest) (*QueryChannelResponse, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method Channel not implemented")
 }
+func (*UnimplementedQueryServer) ChannelClientState(ctx context.Context, req *QueryChannelClientStateRequest) (*QueryChannelClientStateResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ChannelClientState not implemented")
+}
 func (*UnimplementedQueryServer) NextSequenceSend(ctx context.Context, req *QueryNextSequenceSendRequest) (*QueryNextSequenceSendResponse, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method NextSequenceSend not implemented")
 }
@@ -1362,6 +1499,24 @@ func _Query_Channel_Handler(srv interface{}, ctx context.Context, dec func(inter
 	return interceptor(ctx, in, info, handler)
 }
 
+func _Query_ChannelClientState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(QueryChannelClientStateRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(QueryServer).ChannelClientState(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/ibc.core.channel.v2.Query/ChannelClientState",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(QueryServer).ChannelClientState(ctx, req.(*QueryChannelClientStateRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
 func _Query_NextSequenceSend_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
 	in := new(QueryNextSequenceSendRequest)
 	if err := dec(in); err != nil {
@@ -1514,6 +1669,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{
 			MethodName: "Channel",
 			Handler:    _Query_Channel_Handler,
 		},
+		{
+			MethodName: "ChannelClientState",
+			Handler:    _Query_ChannelClientState_Handler,
+		},
 		{
 			MethodName: "NextSequenceSend",
 			Handler:    _Query_NextSequenceSend_Handler,
@@ -1614,6 +1773,88 @@ func (m *QueryChannelResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 	return len(dAtA) - i, nil
 }
 
+func (m *QueryChannelClientStateRequest) Marshal() (dAtA []byte, err error) {
+	size := m.Size()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalToSizedBuffer(dAtA[:size])
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
+}
+
+func (m *QueryChannelClientStateRequest) MarshalTo(dAtA []byte) (int, error) {
+	size := m.Size()
+	return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *QueryChannelClientStateRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+	i := len(dAtA)
+	_ = i
+	var l int
+	_ = l
+	if len(m.ChannelId) > 0 {
+		i -= len(m.ChannelId)
+		copy(dAtA[i:], m.ChannelId)
+		i = encodeVarintQuery(dAtA, i, uint64(len(m.ChannelId)))
+		i--
+		dAtA[i] = 0xa
+	}
+	return len(dAtA) - i, nil
+}
+
+func (m *QueryChannelClientStateResponse) Marshal() (dAtA []byte, err error) {
+	size := m.Size()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalToSizedBuffer(dAtA[:size])
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
+}
+
+func (m *QueryChannelClientStateResponse) MarshalTo(dAtA []byte) (int, error) {
+	size := m.Size()
+	return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *QueryChannelClientStateResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+	i := len(dAtA)
+	_ = i
+	var l int
+	_ = l
+	{
+		size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i])
+		if err != nil {
+			return 0, err
+		}
+		i -= size
+		i = encodeVarintQuery(dAtA, i, uint64(size))
+	}
+	i--
+	dAtA[i] = 0x1a
+	if len(m.Proof) > 0 {
+		i -= len(m.Proof)
+		copy(dAtA[i:], m.Proof)
+		i = encodeVarintQuery(dAtA, i, uint64(len(m.Proof)))
+		i--
+		dAtA[i] = 0x12
+	}
+	if m.IdentifiedClientState != nil {
+		{
+			size, err := m.IdentifiedClientState.MarshalToSizedBuffer(dAtA[:i])
+			if err != nil {
+				return 0, err
+			}
+			i -= size
+			i = encodeVarintQuery(dAtA, i, uint64(size))
+		}
+		i--
+		dAtA[i] = 0xa
+	}
+	return len(dAtA) - i, nil
+}
+
 func (m *QueryNextSequenceSendRequest) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
 	dAtA = make([]byte, size)
@@ -1975,20 +2216,20 @@ func (m *QueryPacketAcknowledgementsRequest) MarshalToSizedBuffer(dAtA []byte) (
 	var l int
 	_ = l
 	if len(m.PacketCommitmentSequences) > 0 {
-		dAtA9 := make([]byte, len(m.PacketCommitmentSequences)*10)
-		var j8 int
+		dAtA11 := make([]byte, len(m.PacketCommitmentSequences)*10)
+		var j10 int
 		for _, num := range m.PacketCommitmentSequences {
 			for num >= 1<<7 {
-				dAtA9[j8] = uint8(uint64(num)&0x7f | 0x80)
+				dAtA11[j10] = uint8(uint64(num)&0x7f | 0x80)
 				num >>= 7
-				j8++
+				j10++
 			}
-			dAtA9[j8] = uint8(num)
-			j8++
+			dAtA11[j10] = uint8(num)
+			j10++
 		}
-		i -= j8
-		copy(dAtA[i:], dAtA9[:j8])
-		i = encodeVarintQuery(dAtA, i, uint64(j8))
+		i -= j10
+		copy(dAtA[i:], dAtA11[:j10])
+		i = encodeVarintQuery(dAtA, i, uint64(j10))
 		i--
 		dAtA[i] = 0x1a
 	}
@@ -2186,20 +2427,20 @@ func (m *QueryUnreceivedPacketsRequest) MarshalToSizedBuffer(dAtA []byte) (int,
 	var l int
 	_ = l
 	if len(m.Sequences) > 0 {
-		dAtA15 := make([]byte, len(m.Sequences)*10)
-		var j14 int
+		dAtA17 := make([]byte, len(m.Sequences)*10)
+		var j16 int
 		for _, num := range m.Sequences {
 			for num >= 1<<7 {
-				dAtA15[j14] = uint8(uint64(num)&0x7f | 0x80)
+				dAtA17[j16] = uint8(uint64(num)&0x7f | 0x80)
 				num >>= 7
-				j14++
+				j16++
 			}
-			dAtA15[j14] = uint8(num)
-			j14++
+			dAtA17[j16] = uint8(num)
+			j16++
 		}
-		i -= j14
-		copy(dAtA[i:], dAtA15[:j14])
-		i = encodeVarintQuery(dAtA, i, uint64(j14))
+		i -= j16
+		copy(dAtA[i:], dAtA17[:j16])
+		i = encodeVarintQuery(dAtA, i, uint64(j16))
 		i--
 		dAtA[i] = 0x12
 	}
@@ -2244,20 +2485,20 @@ func (m *QueryUnreceivedPacketsResponse) MarshalToSizedBuffer(dAtA []byte) (int,
 	i--
 	dAtA[i] = 0x12
 	if len(m.Sequences) > 0 {
-		dAtA18 := make([]byte, len(m.Sequences)*10)
-		var j17 int
+		dAtA20 := make([]byte, len(m.Sequences)*10)
+		var j19 int
 		for _, num := range m.Sequences {
 			for num >= 1<<7 {
-				dAtA18[j17] = uint8(uint64(num)&0x7f | 0x80)
+				dAtA20[j19] = uint8(uint64(num)&0x7f | 0x80)
 				num >>= 7
-				j17++
+				j19++
 			}
-			dAtA18[j17] = uint8(num)
-			j17++
+			dAtA20[j19] = uint8(num)
+			j19++
 		}
-		i -= j17
-		copy(dAtA[i:], dAtA18[:j17])
-		i = encodeVarintQuery(dAtA, i, uint64(j17))
+		i -= j19
+		copy(dAtA[i:], dAtA20[:j19])
+		i = encodeVarintQuery(dAtA, i, uint64(j19))
 		i--
 		dAtA[i] = 0xa
 	}
@@ -2285,20 +2526,20 @@ func (m *QueryUnreceivedAcksRequest) MarshalToSizedBuffer(dAtA []byte) (int, err
 	var l int
 	_ = l
 	if len(m.PacketAckSequences) > 0 {
-		dAtA20 := make([]byte, len(m.PacketAckSequences)*10)
-		var j19 int
+		dAtA22 := make([]byte, len(m.PacketAckSequences)*10)
+		var j21 int
 		for _, num := range m.PacketAckSequences {
 			for num >= 1<<7 {
-				dAtA20[j19] = uint8(uint64(num)&0x7f | 0x80)
+				dAtA22[j21] = uint8(uint64(num)&0x7f | 0x80)
 				num >>= 7
-				j19++
+				j21++
 			}
-			dAtA20[j19] = uint8(num)
-			j19++
+			dAtA22[j21] = uint8(num)
+			j21++
 		}
-		i -= j19
-		copy(dAtA[i:], dAtA20[:j19])
-		i = encodeVarintQuery(dAtA, i, uint64(j19))
+		i -= j21
+		copy(dAtA[i:], dAtA22[:j21])
+		i = encodeVarintQuery(dAtA, i, uint64(j21))
 		i--
 		dAtA[i] = 0x12
 	}
@@ -2343,20 +2584,20 @@ func (m *QueryUnreceivedAcksResponse) MarshalToSizedBuffer(dAtA []byte) (int, er
 	i--
 	dAtA[i] = 0x12
 	if len(m.Sequences) > 0 {
-		dAtA23 := make([]byte, len(m.Sequences)*10)
-		var j22 int
+		dAtA25 := make([]byte, len(m.Sequences)*10)
+		var j24 int
 		for _, num := range m.Sequences {
 			for num >= 1<<7 {
-				dAtA23[j22] = uint8(uint64(num)&0x7f | 0x80)
+				dAtA25[j24] = uint8(uint64(num)&0x7f | 0x80)
 				num >>= 7
-				j22++
+				j24++
 			}
-			dAtA23[j22] = uint8(num)
-			j22++
+			dAtA25[j24] = uint8(num)
+			j24++
 		}
-		i -= j22
-		copy(dAtA[i:], dAtA23[:j22])
-		i = encodeVarintQuery(dAtA, i, uint64(j22))
+		i -= j24
+		copy(dAtA[i:], dAtA25[:j24])
+		i = encodeVarintQuery(dAtA, i, uint64(j24))
 		i--
 		dAtA[i] = 0xa
 	}
@@ -2398,6 +2639,38 @@ func (m *QueryChannelResponse) Size() (n int) {
 	return n
 }
 
+func (m *QueryChannelClientStateRequest) Size() (n int) {
+	if m == nil {
+		return 0
+	}
+	var l int
+	_ = l
+	l = len(m.ChannelId)
+	if l > 0 {
+		n += 1 + l + sovQuery(uint64(l))
+	}
+	return n
+}
+
+func (m *QueryChannelClientStateResponse) Size() (n int) {
+	if m == nil {
+		return 0
+	}
+	var l int
+	_ = l
+	if m.IdentifiedClientState != nil {
+		l = m.IdentifiedClientState.Size()
+		n += 1 + l + sovQuery(uint64(l))
+	}
+	l = len(m.Proof)
+	if l > 0 {
+		n += 1 + l + sovQuery(uint64(l))
+	}
+	l = m.ProofHeight.Size()
+	n += 1 + l + sovQuery(uint64(l))
+	return n
+}
+
 func (m *QueryNextSequenceSendRequest) Size() (n int) {
 	if m == nil {
 		return 0
@@ -2867,6 +3140,241 @@ func (m *QueryChannelResponse) Unmarshal(dAtA []byte) error {
 	}
 	return nil
 }
+func (m *QueryChannelClientStateRequest) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowQuery
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= uint64(b&0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: QueryChannelClientStateRequest: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: QueryChannelClientStateRequest: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowQuery
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= uint64(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthQuery
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex < 0 {
+				return ErrInvalidLengthQuery
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.ChannelId = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipQuery(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if (skippy < 0) || (iNdEx+skippy) < 0 {
+				return ErrInvalidLengthQuery
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func (m *QueryChannelClientStateResponse) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowQuery
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= uint64(b&0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: QueryChannelClientStateResponse: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: QueryChannelClientStateResponse: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field IdentifiedClientState", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowQuery
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthQuery
+			}
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLengthQuery
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if m.IdentifiedClientState == nil {
+				m.IdentifiedClientState = &types.IdentifiedClientState{}
+			}
+			if err := m.IdentifiedClientState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 2:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Proof", wireType)
+			}
+			var byteLen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowQuery
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				byteLen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if byteLen < 0 {
+				return ErrInvalidLengthQuery
+			}
+			postIndex := iNdEx + byteLen
+			if postIndex < 0 {
+				return ErrInvalidLengthQuery
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Proof = append(m.Proof[:0], dAtA[iNdEx:postIndex]...)
+			if m.Proof == nil {
+				m.Proof = []byte{}
+			}
+			iNdEx = postIndex
+		case 3:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field ProofHeight", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowQuery
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthQuery
+			}
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLengthQuery
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if err := m.ProofHeight.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipQuery(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if (skippy < 0) || (iNdEx+skippy) < 0 {
+				return ErrInvalidLengthQuery
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
 func (m *QueryNextSequenceSendRequest) Unmarshal(dAtA []byte) error {
 	l := len(dAtA)
 	iNdEx := 0
diff --git a/modules/core/04-channel/v2/types/query.pb.gw.go b/modules/core/04-channel/v2/types/query.pb.gw.go
index 2f03fdadfd5..47aa5757262 100644
--- a/modules/core/04-channel/v2/types/query.pb.gw.go
+++ b/modules/core/04-channel/v2/types/query.pb.gw.go
@@ -87,6 +87,60 @@ func local_request_Query_Channel_0(ctx context.Context, marshaler runtime.Marsha
 
 }
 
+func request_Query_ChannelClientState_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq QueryChannelClientStateRequest
+	var metadata runtime.ServerMetadata
+
+	var (
+		val string
+		ok  bool
+		err error
+		_   = err
+	)
+
+	val, ok = pathParams["channel_id"]
+	if !ok {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id")
+	}
+
+	protoReq.ChannelId, err = runtime.String(val)
+
+	if err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err)
+	}
+
+	msg, err := client.ChannelClientState(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+func local_request_Query_ChannelClientState_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq QueryChannelClientStateRequest
+	var metadata runtime.ServerMetadata
+
+	var (
+		val string
+		ok  bool
+		err error
+		_   = err
+	)
+
+	val, ok = pathParams["channel_id"]
+	if !ok {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id")
+	}
+
+	protoReq.ChannelId, err = runtime.String(val)
+
+	if err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err)
+	}
+
+	msg, err := server.ChannelClientState(ctx, &protoReq)
+	return msg, metadata, err
+
+}
+
 func request_Query_NextSequenceSend_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
 	var protoReq QueryNextSequenceSendRequest
 	var metadata runtime.ServerMetadata
@@ -712,6 +766,29 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
 
 	})
 
+	mux.Handle("GET", pattern_Query_ChannelClientState_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(req.Context())
+		defer cancel()
+		var stream runtime.ServerTransportStream
+		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := local_request_Query_ChannelClientState_0(rctx, inboundMarshaler, server, req, pathParams)
+		md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_Query_ChannelClientState_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
 	mux.Handle("GET", pattern_Query_NextSequenceSend_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
@@ -957,6 +1034,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie
 
 	})
 
+	mux.Handle("GET", pattern_Query_ChannelClientState_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(req.Context())
+		defer cancel()
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, mux, req)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_Query_ChannelClientState_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_Query_ChannelClientState_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
 	mux.Handle("GET", pattern_Query_NextSequenceSend_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
@@ -1123,6 +1220,8 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie
 var (
 	pattern_Query_Channel_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"ibc", "core", "channel", "v2", "channels", "channel_id"}, "", runtime.AssumeColonVerbOpt(false)))
 
+	pattern_Query_ChannelClientState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6}, []string{"ibc", "core", "channel", "v2", "channels", "channel_id", "client_state"}, "", runtime.AssumeColonVerbOpt(false)))
+
 	pattern_Query_NextSequenceSend_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6}, []string{"ibc", "core", "channel", "v2", "channels", "channel_id", "next_sequence_send"}, "", runtime.AssumeColonVerbOpt(false)))
 
 	pattern_Query_PacketCommitment_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7}, []string{"ibc", "core", "channel", "v2", "channels", "channel_id", "packet_commitments", "sequence"}, "", runtime.AssumeColonVerbOpt(false)))
@@ -1143,6 +1242,8 @@ var (
 var (
 	forward_Query_Channel_0 = runtime.ForwardResponseMessage
 
+	forward_Query_ChannelClientState_0 = runtime.ForwardResponseMessage
+
 	forward_Query_NextSequenceSend_0 = runtime.ForwardResponseMessage
 
 	forward_Query_PacketCommitment_0 = runtime.ForwardResponseMessage
diff --git a/proto/ibc/core/channel/v2/query.proto b/proto/ibc/core/channel/v2/query.proto
index 40d1cdc31eb..3ca8a2e16ad 100644
--- a/proto/ibc/core/channel/v2/query.proto
+++ b/proto/ibc/core/channel/v2/query.proto
@@ -18,6 +18,12 @@ service Query {
     option (google.api.http).get = "/ibc/core/channel/v2/channels/{channel_id}";
   }
 
+  // ChannelClientState queries for the client state for the channel associated
+  // with the provided channel identifiers.
+  rpc ChannelClientState(QueryChannelClientStateRequest) returns (QueryChannelClientStateResponse) {
+    option (google.api.http).get = "/ibc/core/channel/v2/channels/{channel_id}/client_state";
+  }
+
   // NextSequenceSend returns the next send sequence for a given channel.
   rpc NextSequenceSend(QueryNextSequenceSendRequest) returns (QueryNextSequenceSendResponse) {
     option (google.api.http).get = "/ibc/core/channel/v2/channels/{channel_id}/next_sequence_send";
@@ -72,6 +78,24 @@ message QueryChannelResponse {
   Channel channel = 1 [(gogoproto.nullable) = false];
 }
 
+// QueryChannelClientStateRequest is the request type for the Query/ClientState
+// RPC method
+message QueryChannelClientStateRequest {
+  // channel unique identifier
+  string channel_id = 1;
+}
+
+// QueryChannelClientStateResponse is the Response type for the
+// Query/QueryChannelClientState RPC method
+message QueryChannelClientStateResponse {
+  // client state associated with the channel
+  ibc.core.client.v1.IdentifiedClientState identified_client_state = 1;
+  // merkle proof of existence
+  bytes proof = 2;
+  // height at which the proof was retrieved
+  ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false];
+}
+
 // QueryNextSequenceSendRequest is the request type for the Query/QueryNextSequenceSend RPC method
 message QueryNextSequenceSendRequest {
   // channel unique identifier