Repository: cosmos/gaia

Issue:
[Feature]: Query liquidValidators in x/liquid
### Summary

In order to query the liquid shares of validators, the current `x/liquid` implementation only supports the `liquidValidator` query, which allows querying a specific validator.

However, there is no existing query to allow querying for all validators.

For optimal querying, would it be possible to create a `liquidValidators` query in `x/liquid` (with pagination), similar to how `x/staking` has both a `validator` (validator-specific) and a `validators` (with pagination) query.

Thank you.

### Problem Definition

I have a frontend app that uses the LSM and used to retrieve the amount of liquid staked tokens for all validators. 

It was previously easily retrievable using `x/staking` `validators` query, however since the LSM code is now moved to a new standalone module `x/liquid`, this possibility has been removed.

As I'd still would like to be able to show the information on my frontend app, without having to run hundreds of queries for each single validator, having this `liquidvalidators` query would be very helpful.

I don't see any disadvantage of including this feature. Also, it should not pose any security risk as it's only a query.

### Proposed Feature

Adding a `liquidvalidators` query in `x/liquid` to retrieve the list of validators (with pagination) would be meeting my needs.

### Work Breakdown

```[tasklist]
#### Must have
- [ ] add a `liquidvalidators` query in `x/liquid`
```

Discussion:
@linear: <p><a href="https://linear.app/skip/issue/GAIA-133/feature-query-liquidvalidators-in-xliquid">GAIA-133 [Feature]: Query liquidValidators in x/liquid</a></p>

Solution patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 51c4efe..f6f2cad 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -40,6 +40,7 @@
 - Add x/liquid module ([\#3712](https://github.com/cosmos/gaia/pull/3712))
 - Remove expedited gov prop type restrictions ([\#3723](https://github.com/cosmos/gaia/pull/3723))
 - Add liquid validator query to x/liquid ([\#3735](https://github.com/cosmos/gaia/pull/3735))
+- Add liquid validators query to x/liquid ([\#3760](https://github.com/cosmos/gaia/pull/3760))
 
 ### BUG-FIXES
 - Set x/liquid params during InitGenesis ([\#3759](https://github.com/cosmos/gaia/pull/3759))
diff --git a/Makefile b/Makefile
index 4e02747..3ebdd8d 100644
--- a/Makefile
+++ b/Makefile
@@ -208,6 +208,25 @@ build-static-linux-amd64: go.sum $(BUILDDIR)/
 	$(DOCKER) cp gaiabinary:/usr/local/bin/ $(BUILDDIR)/gaiad-linux-amd64
 	$(DOCKER) rm -f gaiabinary
 
+# Build static binaries for linux/arm64 using docker buildx
+# Pulled from neutron-org/neutron: https://github.com/neutron-org/neutron/blob/v4.2.2/Makefile#L107
+build-static-linux-arm64: go.sum $(BUILDDIR)/
+	$(DOCKER) buildx create --name gaiabuilder || true
+	$(DOCKER) buildx use gaiabuilder
+	$(DOCKER) buildx build \
+		--build-arg GO_VERSION=$(GO_VERSION) \
+		--build-arg GIT_VERSION=$(VERSION) \
+		--build-arg GIT_COMMIT=$(COMMIT) \
+		--build-arg BUILD_TAGS=$(build_tags_comma_sep),muslc \
+		--platform linux/arm64 \
+		-t gaiad-static-arm64 \
+		-f Dockerfile . \
+		--load
+	$(DOCKER) rm -f gaiabinary || true
+	$(DOCKER) create -ti --name gaiabinary gaiad-static-arm64
+	$(DOCKER) cp gaiabinary:/usr/local/bin/ $(BUILDDIR)/gaiad-linux-arm64
+	$(DOCKER) rm -f gaiabinary
+
 
 # uses goreleaser to create static binaries for darwin on local machine
 goreleaser-build-local:
diff --git a/proto/gaia/liquid/v1beta1/query.proto b/proto/gaia/liquid/v1beta1/query.proto
index 74abe23..8fcfd40 100644
--- a/proto/gaia/liquid/v1beta1/query.proto
+++ b/proto/gaia/liquid/v1beta1/query.proto
@@ -13,6 +13,15 @@ option go_package = "github.com/cosmos/gaia/x/liquid/types";
 
 // Query defines the gRPC querier service.
 service Query {
+  // LiquidValidators queries all liquid validators.
+  //
+  // When called from another module, this query might consume a high amount of
+  // gas if the pagination field is incorrectly set.
+  rpc LiquidValidators(QueryLiquidValidatorsRequest)
+      returns (QueryLiquidValidatorsResponse) {
+    option (cosmos.query.v1.module_query_safe) = true;
+    option (google.api.http).get = "/gaia/liquid/v1beta1/liquid_validators";
+  }
 
   // Query for an individual liquid validator by validator address
   rpc LiquidValidator(QueryLiquidValidatorRequest)
@@ -91,14 +100,31 @@ service Query {
   }
 }
 
-// QueryLiquidValidatorRequest is the request type for the Query/LiquidValidator RPC method.
-message QueryLiquidValidatorRequest {
-  string validator_addr = 1;
-}
+// QueryLiquidValidatorRequest is the request type for the Query/LiquidValidator
+// RPC method.
+message QueryLiquidValidatorRequest { string validator_addr = 1; }
 
-// QueryLiquidValidatorResponse is the response type for the Query/LiquidValidator RPC method.
+// QueryLiquidValidatorResponse is the response type for the
+// Query/LiquidValidator RPC method.
 message QueryLiquidValidatorResponse {
-  LiquidValidator liquid_validator = 1 [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true ];
+  LiquidValidator liquid_validator = 1
+      [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true ];
+}
+
+// QueryLiquidValidatorsRequest is request type for the
+// Query/QueryLiquidValidators RPC method.
+message QueryLiquidValidatorsRequest {
+  // pagination defines an optional pagination for the request.
+  cosmos.base.query.v1beta1.PageRequest pagination = 1;
+}
+
+// QueryLiquidValidatorsResponse is response type for the
+// Query/QueryLiquidValidators RPC method.
+message QueryLiquidValidatorsResponse {
+  repeated LiquidValidator liquid_validators = 1
+      [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true ];
+  // pagination defines the pagination in the response.
+  cosmos.base.query.v1beta1.PageResponse pagination = 2;
 }
 
 // QueryParamsRequest is request type for the Query/Params RPC method.
diff --git a/proto/gaia/metaprotocols/extensions.proto b/proto/gaia/metaprotocols/extensions.proto
index 868ee0b..2e4a4f2 100644
--- a/proto/gaia/metaprotocols/extensions.proto
+++ b/proto/gaia/metaprotocols/extensions.proto
@@ -5,15 +5,15 @@ option go_package = "github.com/cosmos/gaia/x/metaprotocols/types";
 
 // ExtensionData is a data structure that can be used in transaction extensions.
 message ExtensionData {
-    // protocol_id is the identifier of the protocol
-    // the field is not used internally but it is validated for correctness
-    string protocol_id = 1;
+  // protocol_id is the identifier of the protocol
+  // the field is not used internally but it is validated for correctness
+  string protocol_id = 1;
 
-    // protocol_version is the identifier of the protocol version
-    // the field is not used internally but it is validated for correctness
-    string protocol_version = 2;
+  // protocol_version is the identifier of the protocol version
+  // the field is not used internally but it is validated for correctness
+  string protocol_version = 2;
 
-    // arbitrary bytes data that can be used to store any data
-    // the field is not used internally but it is validated and must be provided
-    bytes data = 3;
+  // arbitrary bytes data that can be used to store any data
+  // the field is not used internally but it is validated and must be provided
+  bytes data = 3;
 }
diff --git a/x/liquid/autocli.go b/x/liquid/autocli.go
index c2ce97d..c943646 100644
--- a/x/liquid/autocli.go
+++ b/x/liquid/autocli.go
@@ -16,6 +16,12 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
 		Query: &autocliv1.ServiceCommandDescriptor{
 			Service: types.Query_serviceDesc.ServiceName,
 			RpcCommandOptions: []*autocliv1.RpcCommandOptions{
+				{
+					RpcMethod: "LiquidValidators",
+					Use:       "liquid-validators",
+					Short:     "Query for all liquid validators",
+					Example:   fmt.Sprintf("$ %s query liquid liquid-validators", version.AppName),
+				},
 				{
 					RpcMethod: "LiquidValidator",
 					Use:       "liquid-validator [validator-address]",
diff --git a/x/liquid/keeper/grpc_query.go b/x/liquid/keeper/grpc_query.go
index 1753e7d..0b9c9e6 100644
--- a/x/liquid/keeper/grpc_query.go
+++ b/x/liquid/keeper/grpc_query.go
@@ -55,6 +55,35 @@ func (k Querier) LiquidValidator(c context.Context, req *types.QueryLiquidValida
 	return &types.QueryLiquidValidatorResponse{LiquidValidator: lv}, nil
 }
 
+// LiquidValidators queries for all LiquidValidator records
+func (k Querier) LiquidValidators(c context.Context, req *types.QueryLiquidValidatorsRequest) (*types.QueryLiquidValidatorsResponse, error) {
+	if req == nil {
+		return nil, status.Error(codes.InvalidArgument, "empty request")
+	}
+
+	store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(c))
+	valStore := prefix.NewStore(store, types.LiquidValidatorPrefix)
+
+	var liquidValidators []types.LiquidValidator
+
+	pageRes, err := query.Paginate(valStore, req.Pagination, func(key, value []byte) error {
+		var val types.LiquidValidator
+		if err := k.cdc.Unmarshal(value, &val); err != nil {
+			return err
+		}
+		liquidValidators = append(liquidValidators, val)
+		return nil
+	})
+	if err != nil {
+		return nil, status.Error(codes.Internal, err.Error())
+	}
+
+	return &types.QueryLiquidValidatorsResponse{
+		LiquidValidators: liquidValidators,
+		Pagination:       pageRes,
+	}, nil
+}
+
 // TokenizeShareRecordById queries for individual tokenize share record information by share by id
 func (k Querier) TokenizeShareRecordById(c context.Context, req *types.QueryTokenizeShareRecordByIdRequest) (*types.QueryTokenizeShareRecordByIdResponse, error) { //nolint:revive // fixing this would require changing the .proto files, so we might as well leave it alone
 	if req == nil {
diff --git a/x/liquid/keeper/liquid_stake.go b/x/liquid/keeper/liquid_stake.go
index 405de6e..9ca4349 100644
--- a/x/liquid/keeper/liquid_stake.go
+++ b/x/liquid/keeper/liquid_stake.go
@@ -166,12 +166,10 @@ func (k Keeper) DecreaseTotalLiquidStakedTokens(ctx context.Context, amount math
 }
 
 // SafelyIncreaseValidatorLiquidShares increments the liquid shares on a validator, if:
-// the validator bond factor and validator liquid staking cap will not be exceeded by this delegation
+// the validator liquid staking cap will not be exceeded by this delegation
 //
-// The percentage of validator liquid shares must be less than the ValidatorLiquidStakingCap,
-// and the total liquid staked shares cannot exceed the validator bond cap
-//  1. (TotalLiquidStakedTokens / TotalStakedTokens) <= ValidatorLiquidStakingCap
-//  2. LiquidShares <= (ValidatorBondShares * ValidatorBondFactor)
+// The percentage of validator liquid shares must be less than the ValidatorLiquidStakingCap:
+// (TotalLiquidStakedTokens / TotalStakedTokens) <= ValidatorLiquidStakingCap
 func (k Keeper) SafelyIncreaseValidatorLiquidShares(
 	ctx context.Context,
 	valAddress sdk.ValAddress,
diff --git a/x/liquid/types/query.pb.go b/x/liquid/types/query.pb.go
index 37802db..c7d6bf8 100644
--- a/x/liquid/types/query.pb.go
+++ b/x/liquid/types/query.pb.go
@@ -33,7 +33,8 @@ var _ = math.Inf
 // proto package needs to be updated.
 const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
 
-// QueryLiquidValidatorRequest is the request type for the Query/LiquidValidator RPC method.
+// QueryLiquidValidatorRequest is the request type for the Query/LiquidValidator
+// RPC method.
 type QueryLiquidValidatorRequest struct {
 	ValidatorAddr string `protobuf:"bytes,1,opt,name=validator_addr,json=validatorAddr,proto3" json:"validator_addr,omitempty"`
 }
@@ -78,7 +79,8 @@ func (m *QueryLiquidValidatorRequest) GetValidatorAddr() string {
 	return ""
 }
 
-// QueryLiquidValidatorResponse is the response type for the Query/LiquidValidator RPC method.
+// QueryLiquidValidatorResponse is the response type for the
+// Query/LiquidValidator RPC method.
 type QueryLiquidValidatorResponse struct {
 	LiquidValidator LiquidValidator `protobuf:"bytes,1,opt,name=liquid_validator,json=liquidValidator,proto3" json:"liquid_validator"`
 }
@@ -123,6 +125,108 @@ func (m *QueryLiquidValidatorResponse) GetLiquidValidator() LiquidValidator {
 	return LiquidValidator{}
 }
 
+// QueryLiquidValidatorsRequest is request type for the
+// Query/QueryLiquidValidators RPC method.
+type QueryLiquidValidatorsRequest struct {
+	// pagination defines an optional pagination for the request.
+	Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"`
+}
+
+func (m *QueryLiquidValidatorsRequest) Reset()         { *m = QueryLiquidValidatorsRequest{} }
+func (m *QueryLiquidValidatorsRequest) String() string { return proto.CompactTextString(m) }
+func (*QueryLiquidValidatorsRequest) ProtoMessage()    {}
+func (*QueryLiquidValidatorsRequest) Descriptor() ([]byte, []int) {
+	return fileDescriptor_a7f79c476d0ac005, []int{2}
+}
+func (m *QueryLiquidValidatorsRequest) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *QueryLiquidValidatorsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_QueryLiquidValidatorsRequest.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 *QueryLiquidValidatorsRequest) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_QueryLiquidValidatorsRequest.Merge(m, src)
+}
+func (m *QueryLiquidValidatorsRequest) XXX_Size() int {
+	return m.Size()
+}
+func (m *QueryLiquidValidatorsRequest) XXX_DiscardUnknown() {
+	xxx_messageInfo_QueryLiquidValidatorsRequest.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_QueryLiquidValidatorsRequest proto.InternalMessageInfo
+
+func (m *QueryLiquidValidatorsRequest) GetPagination() *query.PageRequest {
+	if m != nil {
+		return m.Pagination
+	}
+	return nil
+}
+
+// QueryLiquidValidatorsResponse is response type for the
+// Query/QueryLiquidValidators RPC method.
+type QueryLiquidValidatorsResponse struct {
+	LiquidValidators []LiquidValidator `protobuf:"bytes,1,rep,name=liquid_validators,json=liquidValidators,proto3" json:"liquid_validators"`
+	// pagination defines the pagination in the response.
+	Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"`
+}
+
+func (m *QueryLiquidValidatorsResponse) Reset()         { *m = QueryLiquidValidatorsResponse{} }
+func (m *QueryLiquidValidatorsResponse) String() string { return proto.CompactTextString(m) }
+func (*QueryLiquidValidatorsResponse) ProtoMessage()    {}
+func (*QueryLiquidValidatorsResponse) Descriptor() ([]byte, []int) {
+	return fileDescriptor_a7f79c476d0ac005, []int{3}
+}
+func (m *QueryLiquidValidatorsResponse) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *QueryLiquidValidatorsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_QueryLiquidValidatorsResponse.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 *QueryLiquidValidatorsResponse) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_QueryLiquidValidatorsResponse.Merge(m, src)
+}
+func (m *QueryLiquidValidatorsResponse) XXX_Size() int {
+	return m.Size()
+}
+func (m *QueryLiquidValidatorsResponse) XXX_DiscardUnknown() {
+	xxx_messageInfo_QueryLiquidValidatorsResponse.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_QueryLiquidValidatorsResponse proto.InternalMessageInfo
+
+func (m *QueryLiquidValidatorsResponse) GetLiquidValidators() []LiquidValidator {
+	if m != nil {
+		return m.LiquidValidators
+	}
+	return nil
+}
+
+func (m *QueryLiquidValidatorsResponse) GetPagination() *query.PageResponse {
+	if m != nil {
+		return m.Pagination
+	}
+	return nil
+}
+
 // QueryParamsRequest is request type for the Query/Params RPC method.
 type QueryParamsRequest struct {
 }
@@ -131,7 +235,7 @@ func (m *QueryParamsRequest) Reset()         { *m = QueryParamsRequest{} }
 func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) }
 func (*QueryParamsRequest) ProtoMessage()    {}
 func (*QueryParamsRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a7f79c476d0ac005, []int{2}
+	return fileDescriptor_a7f79c476d0ac005, []int{4}
 }
 func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -170,7 +274,7 @@ func (m *QueryParamsResponse) Reset()         { *m = QueryParamsResponse{} }
 func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) }
 func (*QueryParamsResponse) ProtoMessage()    {}
 func (*QueryParamsResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a7f79c476d0ac005, []int{3}
+	return fileDescriptor_a7f79c476d0ac005, []int{5}
 }
 func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -216,7 +320,7 @@ func (m *QueryTokenizeShareRecordByIdRequest) Reset()         { *m = QueryTokeni
 func (m *QueryTokenizeShareRecordByIdRequest) String() string { return proto.CompactTextString(m) }
 func (*QueryTokenizeShareRecordByIdRequest) ProtoMessage()    {}
 func (*QueryTokenizeShareRecordByIdRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a7f79c476d0ac005, []int{4}
+	return fileDescriptor_a7f79c476d0ac005, []int{6}
 }
 func (m *QueryTokenizeShareRecordByIdRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -262,7 +366,7 @@ func (m *QueryTokenizeShareRecordByIdResponse) Reset()         { *m = QueryToken
 func (m *QueryTokenizeShareRecordByIdResponse) String() string { return proto.CompactTextString(m) }
 func (*QueryTokenizeShareRecordByIdResponse) ProtoMessage()    {}
 func (*QueryTokenizeShareRecordByIdResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a7f79c476d0ac005, []int{5}
+	return fileDescriptor_a7f79c476d0ac005, []int{7}
 }
 func (m *QueryTokenizeShareRecordByIdResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -310,7 +414,7 @@ func (m *QueryTokenizeShareRecordByDenomRequest) Reset() {
 func (m *QueryTokenizeShareRecordByDenomRequest) String() string { return proto.CompactTextString(m) }
 func (*QueryTokenizeShareRecordByDenomRequest) ProtoMessage()    {}
 func (*QueryTokenizeShareRecordByDenomRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a7f79c476d0ac005, []int{6}
+	return fileDescriptor_a7f79c476d0ac005, []int{8}
 }
 func (m *QueryTokenizeShareRecordByDenomRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -358,7 +462,7 @@ func (m *QueryTokenizeShareRecordByDenomResponse) Reset() {
 func (m *QueryTokenizeShareRecordByDenomResponse) String() string { return proto.CompactTextString(m) }
 func (*QueryTokenizeShareRecordByDenomResponse) ProtoMessage()    {}
 func (*QueryTokenizeShareRecordByDenomResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a7f79c476d0ac005, []int{7}
+	return fileDescriptor_a7f79c476d0ac005, []int{9}
 }
 func (m *QueryTokenizeShareRecordByDenomResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -404,7 +508,7 @@ func (m *QueryTokenizeShareRecordsOwnedRequest) Reset()         { *m = QueryToke
 func (m *QueryTokenizeShareRecordsOwnedRequest) String() string { return proto.CompactTextString(m) }
 func (*QueryTokenizeShareRecordsOwnedRequest) ProtoMessage()    {}
 func (*QueryTokenizeShareRecordsOwnedRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a7f79c476d0ac005, []int{8}
+	return fileDescriptor_a7f79c476d0ac005, []int{10}
 }
 func (m *QueryTokenizeShareRecordsOwnedRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -452,7 +556,7 @@ func (m *QueryTokenizeShareRecordsOwnedResponse) Reset() {
 func (m *QueryTokenizeShareRecordsOwnedResponse) String() string { return proto.CompactTextString(m) }
 func (*QueryTokenizeShareRecordsOwnedResponse) ProtoMessage()    {}
 func (*QueryTokenizeShareRecordsOwnedResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a7f79c476d0ac005, []int{9}
+	return fileDescriptor_a7f79c476d0ac005, []int{11}
 }
 func (m *QueryTokenizeShareRecordsOwnedResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -499,7 +603,7 @@ func (m *QueryAllTokenizeShareRecordsRequest) Reset()         { *m = QueryAllTok
 func (m *QueryAllTokenizeShareRecordsRequest) String() string { return proto.CompactTextString(m) }
 func (*QueryAllTokenizeShareRecordsRequest) ProtoMessage()    {}
 func (*QueryAllTokenizeShareRecordsRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a7f79c476d0ac005, []int{10}
+	return fileDescriptor_a7f79c476d0ac005, []int{12}
 }
 func (m *QueryAllTokenizeShareRecordsRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -547,7 +651,7 @@ func (m *QueryAllTokenizeShareRecordsResponse) Reset()         { *m = QueryAllTo
 func (m *QueryAllTokenizeShareRecordsResponse) String() string { return proto.CompactTextString(m) }
 func (*QueryAllTokenizeShareRecordsResponse) ProtoMessage()    {}
 func (*QueryAllTokenizeShareRecordsResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a7f79c476d0ac005, []int{11}
+	return fileDescriptor_a7f79c476d0ac005, []int{13}
 }
 func (m *QueryAllTokenizeShareRecordsResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -599,7 +703,7 @@ func (m *QueryLastTokenizeShareRecordIdRequest) Reset()         { *m = QueryLast
 func (m *QueryLastTokenizeShareRecordIdRequest) String() string { return proto.CompactTextString(m) }
 func (*QueryLastTokenizeShareRecordIdRequest) ProtoMessage()    {}
 func (*QueryLastTokenizeShareRecordIdRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a7f79c476d0ac005, []int{12}
+	return fileDescriptor_a7f79c476d0ac005, []int{14}
 }
 func (m *QueryLastTokenizeShareRecordIdRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -640,7 +744,7 @@ func (m *QueryLastTokenizeShareRecordIdResponse) Reset() {
 func (m *QueryLastTokenizeShareRecordIdResponse) String() string { return proto.CompactTextString(m) }
 func (*QueryLastTokenizeShareRecordIdResponse) ProtoMessage()    {}
 func (*QueryLastTokenizeShareRecordIdResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a7f79c476d0ac005, []int{13}
+	return fileDescriptor_a7f79c476d0ac005, []int{15}
 }
 func (m *QueryLastTokenizeShareRecordIdResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -685,7 +789,7 @@ func (m *QueryTotalTokenizeSharedAssetsRequest) Reset()         { *m = QueryTota
 func (m *QueryTotalTokenizeSharedAssetsRequest) String() string { return proto.CompactTextString(m) }
 func (*QueryTotalTokenizeSharedAssetsRequest) ProtoMessage()    {}
 func (*QueryTotalTokenizeSharedAssetsRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a7f79c476d0ac005, []int{14}
+	return fileDescriptor_a7f79c476d0ac005, []int{16}
 }
 func (m *QueryTotalTokenizeSharedAssetsRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -726,7 +830,7 @@ func (m *QueryTotalTokenizeSharedAssetsResponse) Reset() {
 func (m *QueryTotalTokenizeSharedAssetsResponse) String() string { return proto.CompactTextString(m) }
 func (*QueryTotalTokenizeSharedAssetsResponse) ProtoMessage()    {}
 func (*QueryTotalTokenizeSharedAssetsResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a7f79c476d0ac005, []int{15}
+	return fileDescriptor_a7f79c476d0ac005, []int{17}
 }
 func (m *QueryTotalTokenizeSharedAssetsResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -771,7 +875,7 @@ func (m *QueryTotalLiquidStaked) Reset()         { *m = QueryTotalLiquidStaked{}
 func (m *QueryTotalLiquidStaked) String() string { return proto.CompactTextString(m) }
 func (*QueryTotalLiquidStaked) ProtoMessage()    {}
 func (*QueryTotalLiquidStaked) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a7f79c476d0ac005, []int{16}
+	return fileDescriptor_a7f79c476d0ac005, []int{18}
 }
 func (m *QueryTotalLiquidStaked) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -810,7 +914,7 @@ func (m *QueryTotalLiquidStakedResponse) Reset()         { *m = QueryTotalLiquid
 func (m *QueryTotalLiquidStakedResponse) String() string { return proto.CompactTextString(m) }
 func (*QueryTotalLiquidStakedResponse) ProtoMessage()    {}
 func (*QueryTotalLiquidStakedResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a7f79c476d0ac005, []int{17}
+	return fileDescriptor_a7f79c476d0ac005, []int{19}
 }
 func (m *QueryTotalLiquidStakedResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -856,7 +960,7 @@ func (m *QueryTokenizeShareLockInfo) Reset()         { *m = QueryTokenizeShareLo
 func (m *QueryTokenizeShareLockInfo) String() string { return proto.CompactTextString(m) }
 func (*QueryTokenizeShareLockInfo) ProtoMessage()    {}
 func (*QueryTokenizeShareLockInfo) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a7f79c476d0ac005, []int{18}
+	return fileDescriptor_a7f79c476d0ac005, []int{20}
 }
 func (m *QueryTokenizeShareLockInfo) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -903,7 +1007,7 @@ func (m *QueryTokenizeShareLockInfoResponse) Reset()         { *m = QueryTokeniz
 func (m *QueryTokenizeShareLockInfoResponse) String() string { return proto.CompactTextString(m) }
 func (*QueryTokenizeShareLockInfoResponse) ProtoMessage()    {}
 func (*QueryTokenizeShareLockInfoResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a7f79c476d0ac005, []int{19}
+	return fileDescriptor_a7f79c476d0ac005, []int{21}
 }
 func (m *QueryTokenizeShareLockInfoResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -956,7 +1060,7 @@ func (m *QueryTokenizeShareRecordRewardRequest) Reset()         { *m = QueryToke
 func (m *QueryTokenizeShareRecordRewardRequest) String() string { return proto.CompactTextString(m) }
 func (*QueryTokenizeShareRecordRewardRequest) ProtoMessage()    {}
 func (*QueryTokenizeShareRecordRewardRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a7f79c476d0ac005, []int{20}
+	return fileDescriptor_a7f79c476d0ac005, []int{22}
 }
 func (m *QueryTokenizeShareRecordRewardRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -1000,7 +1104,7 @@ func (m *QueryTokenizeShareRecordRewardResponse) Reset() {
 func (m *QueryTokenizeShareRecordRewardResponse) String() string { return proto.CompactTextString(m) }
 func (*QueryTokenizeShareRecordRewardResponse) ProtoMessage()    {}
 func (*QueryTokenizeShareRecordRewardResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a7f79c476d0ac005, []int{21}
+	return fileDescriptor_a7f79c476d0ac005, []int{23}
 }
 func (m *QueryTokenizeShareRecordRewardResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -1046,6 +1150,8 @@ func (m *QueryTokenizeShareRecordRewardResponse) GetTotal() github_com_cosmos_co
 func init() {
 	proto.RegisterType((*QueryLiquidValidatorRequest)(nil), "gaia.liquid.v1beta1.QueryLiquidValidatorRequest")
 	proto.RegisterType((*QueryLiquidValidatorResponse)(nil), "gaia.liquid.v1beta1.QueryLiquidValidatorResponse")
+	proto.RegisterType((*QueryLiquidValidatorsRequest)(nil), "gaia.liquid.v1beta1.QueryLiquidValidatorsRequest")
+	proto.RegisterType((*QueryLiquidValidatorsResponse)(nil), "gaia.liquid.v1beta1.QueryLiquidValidatorsResponse")
 	proto.RegisterType((*QueryParamsRequest)(nil), "gaia.liquid.v1beta1.QueryParamsRequest")
 	proto.RegisterType((*QueryParamsResponse)(nil), "gaia.liquid.v1beta1.QueryParamsResponse")
 	proto.RegisterType((*QueryTokenizeShareRecordByIdRequest)(nil), "gaia.liquid.v1beta1.QueryTokenizeShareRecordByIdRequest")
@@ -1071,86 +1177,90 @@ func init() {
 func init() { proto.RegisterFile("gaia/liquid/v1beta1/query.proto", fileDescriptor_a7f79c476d0ac005) }
 
 var fileDescriptor_a7f79c476d0ac005 = []byte{
-	// 1260 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0x4d, 0x6f, 0xdc, 0x44,
-	0x18, 0x5e, 0x87, 0x26, 0x25, 0x03, 0x4d, 0xc8, 0x34, 0xb4, 0x89, 0x13, 0x76, 0xab, 0xa1, 0xe9,
-	0x46, 0x89, 0xba, 0x6e, 0x12, 0xd2, 0x7c, 0x91, 0x94, 0xa4, 0x51, 0xa1, 0x28, 0xe2, 0xc3, 0x2d,
-	0x1c, 0x7a, 0xb1, 0x26, 0xeb, 0xe9, 0x76, 0x94, 0x5d, 0xcf, 0xc6, 0xe3, 0x4d, 0x9a, 0xae, 0xf6,
-	0x82, 0x84, 0xd4, 0x0b, 0x12, 0x12, 0x7f, 0xa0, 0x37, 0x10, 0x27, 0x4e, 0x48, 0x5c, 0xe1, 0xd2,
-	0x0b, 0x22, 0x12, 0x12, 0xe2, 0x80, 0x4a, 0x49, 0x90, 0xe0, 0xcc, 0x2f, 0x40, 0x9e, 0x19, 0x7b,
-	0xd7, 0x89, 0xed, 0xcd, 0x46, 0xbd, 0x64, 0x3d, 0xe3, 0xf7, 0x99, 0xf7, 0x79, 0x66, 0xde, 0x8f,
-	0x71, 0x40, 0xae, 0x84, 0x29, 0x36, 0xca, 0x74, 0xbb, 0x46, 0x6d, 0x63, 0x67, 0x6a, 0x93, 0x78,
-	0x78, 0xca, 0xd8, 0xae, 0x11, 0x77, 0xaf, 0x50, 0x75, 0x99, 0xc7, 0xe0, 0x79, 0xdf, 0xa0, 0x20,
-	0x0d, 0x0a, 0xca, 0x40, 0x9f, 0x28, 0x32, 0x5e, 0x61, 0xdc, 0xd8, 0xc4, 0x9c, 0x48, 0xeb, 0x10,
-	0x5b, 0xc5, 0x25, 0xea, 0x60, 0x8f, 0x32, 0x47, 0x2e, 0xa0, 0x0f, 0x96, 0x58, 0x89, 0x89, 0x47,
-	0xc3, 0x7f, 0x52, 0xb3, 0xa3, 0x25, 0xc6, 0x4a, 0x65, 0x62, 0xe0, 0x2a, 0x35, 0xb0, 0xe3, 0x30,
-	0x4f, 0x40, 0xb8, 0x7a, 0x7b, 0x29, 0x8e, 0x95, 0xe2, 0x20, 0x2d, 0xb2, 0xad, 0x0c, 0x02, 0x8b,
-	0x22, 0xa3, 0x81, 0xd7, 0x11, 0xf5, 0x3e, 0x20, 0xd7, 0xaa, 0x49, 0x1f, 0xc0, 0x15, 0xea, 0x30,
-	0x43, 0xfc, 0x95, 0x53, 0x68, 0x1d, 0x8c, 0x7c, 0xec, 0x5b, 0x6c, 0x08, 0x27, 0x9f, 0xe2, 0x32,
-	0xb5, 0xb1, 0xc7, 0x5c, 0x93, 0x6c, 0xd7, 0x08, 0xf7, 0xe0, 0x18, 0xe8, 0xdb, 0x09, 0xe6, 0x2c,
-	0x6c, 0xdb, 0xee, 0x90, 0x76, 0x49, 0x1b, 0xef, 0x35, 0xcf, 0x85, 0xb3, 0xab, 0xb6, 0xed, 0xa2,
-	0x47, 0x60, 0x34, 0x7e, 0x15, 0x5e, 0x65, 0x0e, 0x27, 0xf0, 0x1e, 0x78, 0x4d, 0xaa, 0xb0, 0x42,
-	0x9c, 0x58, 0xe8, 0x95, 0xe9, 0xcb, 0x85, 0x98, 0x7d, 0x2e, 0x1c, 0x59, 0x67, 0xad, 0xf7, 0xe9,
-	0xb3, 0x5c, 0xe6, 0x9b, 0x7f, 0xbe, 0x9b, 0xd0, 0xcc, 0xfe, 0x72, 0xf4, 0x1d, 0x1a, 0x04, 0x50,
-	0xf8, 0xfe, 0x08, 0xbb, 0xb8, 0xc2, 0x15, 0x71, 0xf4, 0x09, 0x38, 0x1f, 0x99, 0x55, 0x44, 0x56,
-	0x40, 0x4f, 0x55, 0xcc, 0x28, 0xf7, 0x23, 0xb1, 0xee, 0x25, 0xa8, 0xd5, 0xab, 0x42, 0xa1, 0x59,
-	0xf0, 0xa6, 0x58, 0xf6, 0x2e, 0xdb, 0x22, 0x0e, 0x7d, 0x44, 0xee, 0x3c, 0xc0, 0x2e, 0x31, 0x49,
-	0x91, 0xb9, 0xf6, 0xda, 0xde, 0x6d, 0x3b, 0xd8, 0xb6, 0x3e, 0xd0, 0x45, 0x6d, 0xe1, 0xe2, 0x8c,
-	0xd9, 0x45, 0x6d, 0xe4, 0x80, 0xcb, 0xe9, 0x30, 0x45, 0xef, 0x16, 0xe8, 0x71, 0xc5, 0xac, 0xa2,
-	0x37, 0x1e, 0x4b, 0x2f, 0x6e, 0x95, 0x33, 0x3e, 0x57, 0x53, 0xa1, 0xd1, 0x0a, 0xb8, 0x92, 0xec,
-	0x6f, 0x9d, 0x38, 0xac, 0x12, 0x30, 0x1d, 0x04, 0xdd, 0xb6, 0x3f, 0x56, 0xe7, 0x2a, 0x07, 0x68,
-	0x1b, 0xe4, 0xdb, 0xe2, 0x5f, 0x30, 0xe5, 0x65, 0x30, 0x96, 0xe4, 0x92, 0x7f, 0xb8, 0xeb, 0x10,
-	0xbb, 0x85, 0x31, 0xdb, 0x75, 0x48, 0x10, 0x89, 0x72, 0x80, 0xdc, 0x64, 0xc5, 0x01, 0x5c, 0x11,
-	0x7e, 0x0f, 0x9c, 0x95, 0x2e, 0xfd, 0x18, 0x78, 0xe9, 0x14, 0x8c, 0x03, 0x38, 0xaa, 0xa8, 0x60,
-	0x58, 0x2d, 0x97, 0xe3, 0xdc, 0x06, 0x84, 0x6f, 0x01, 0xd0, 0x2c, 0x0e, 0x6a, 0x97, 0xae, 0x14,
-	0x64, 0x9e, 0x16, 0xfc, 0x3c, 0x2e, 0xc8, 0x1c, 0x6d, 0x46, 0x5f, 0x89, 0x28, 0xac, 0xd9, 0x82,
-	0x44, 0x3f, 0x68, 0x2a, 0x8a, 0x12, 0xfd, 0xbd, 0x68, 0x85, 0xf0, 0xdd, 0x08, 0xf5, 0x2e, 0x41,
-	0x3d, 0xdf, 0x96, 0xba, 0xa4, 0x11, 0xe1, 0x9e, 0x57, 0xa7, 0xbb, 0x81, 0xb9, 0x17, 0xe3, 0x37,
-	0xcc, 0x1c, 0x34, 0xaf, 0xce, 0x31, 0xc5, 0x50, 0xa9, 0x3c, 0x9a, 0x63, 0xf9, 0x30, 0x80, 0x3c,
-	0x1c, 0xdd, 0x1f, 0x7b, 0x95, 0x73, 0xe2, 0x85, 0xa5, 0xc1, 0x0a, 0x43, 0x25, 0xd1, 0x50, 0xb9,
-	0x98, 0x05, 0xdd, 0x3b, 0xb8, 0x5c, 0x23, 0xea, 0xd0, 0x86, 0x23, 0xca, 0x03, 0xcd, 0x37, 0x19,
-	0x75, 0xd4, 0xbe, 0x49, 0x6b, 0x34, 0x04, 0x2e, 0x34, 0x1d, 0xc8, 0x52, 0x76, 0xc7, 0xc3, 0x5b,
-	0xc4, 0x46, 0xf3, 0x20, 0x1b, 0xff, 0x26, 0x74, 0x79, 0x01, 0xf4, 0x78, 0x3e, 0x25, 0xae, 0xc2,
-	0x5b, 0x8d, 0xd0, 0x75, 0xa0, 0x1f, 0x8f, 0xef, 0x0d, 0x56, 0xdc, 0xba, 0xed, 0xdc, 0x67, 0x70,
-	0x08, 0x9c, 0xf5, 0x8b, 0x33, 0xe1, 0x01, 0x2c, 0x18, 0x22, 0x02, 0x50, 0x32, 0xae, 0xd5, 0x2b,
-	0xf7, 0xb0, 0x57, 0x0b, 0xbd, 0xca, 0x11, 0xcc, 0x83, 0x7e, 0xf2, 0xb0, 0x4a, 0x5d, 0x71, 0x88,
-	0x96, 0x47, 0x2b, 0x44, 0x04, 0x41, 0xaf, 0xd9, 0xd7, 0x9c, 0xbe, 0x4b, 0x2b, 0x04, 0x55, 0x93,
-	0xb3, 0xd7, 0x24, 0xbb, 0xd8, 0x0d, 0xb3, 0x77, 0x19, 0x9c, 0x13, 0x09, 0x6b, 0x45, 0xf8, 0xae,
-	0x0d, 0xfd, 0xf7, 0x2c, 0x37, 0xb8, 0x87, 0x2b, 0xe5, 0x45, 0x14, 0x79, 0x8d, 0xcc, 0x57, 0xc5,
-	0x78, 0x55, 0x0e, 0x17, 0x5f, 0x7e, 0xfc, 0x24, 0x97, 0xf9, 0xf7, 0x49, 0x2e, 0x83, 0xfe, 0xd2,
-	0x92, 0x33, 0x3e, 0x70, 0xa9, 0xd4, 0x7d, 0xe0, 0xe7, 0x83, 0x3f, 0x13, 0xe4, 0x43, 0xe1, 0xa4,
-	0xf9, 0x20, 0x17, 0x6a, 0x66, 0x85, 0x58, 0x04, 0x96, 0x40, 0xb7, 0xe7, 0x1f, 0xe0, 0x50, 0x97,
-	0x58, 0x6d, 0x34, 0x36, 0x2c, 0xd6, 0x49, 0x51, 0x44, 0xc6, 0x8c, 0x8f, 0xfd, 0xf6, 0xcf, 0xdc,
-	0x64, 0x89, 0x7a, 0x0f, 0x6a, 0x9b, 0x85, 0x22, 0xab, 0x18, 0xaa, 0x47, 0xcb, 0x9f, 0xab, 0xdc,
-	0xde, 0x32, 0xbc, 0xbd, 0x2a, 0xe1, 0x01, 0x86, 0x9b, 0x72, 0xfd, 0xe9, 0x2f, 0x06, 0x40, 0xb7,
-	0xd0, 0x08, 0xbf, 0xd7, 0x40, 0xff, 0x91, 0xa6, 0x08, 0xaf, 0xc5, 0xaa, 0x48, 0xe9, 0xe6, 0xfa,
-	0x54, 0x07, 0x08, 0xb9, 0x77, 0x68, 0xe5, 0xb3, 0x5f, 0xff, 0xfe, 0xaa, 0x6b, 0x1e, 0x5e, 0x37,
-	0x92, 0xaf, 0x26, 0xcd, 0xa6, 0x6e, 0xd4, 0xa3, 0xb7, 0x85, 0x06, 0xfc, 0x59, 0x03, 0x17, 0x13,
-	0xba, 0x1e, 0x9c, 0x4f, 0xa6, 0x93, 0xde, 0x5f, 0xf5, 0x85, 0x53, 0x20, 0x95, 0xa0, 0x65, 0x21,
-	0x68, 0x0e, 0xce, 0xc6, 0x0a, 0xf2, 0x14, 0xda, 0xe2, 0x3e, 0xdc, 0x92, 0x75, 0xd0, 0xda, 0xdc,
-	0xb3, 0xa8, 0x6d, 0xd4, 0xa9, 0xdd, 0x80, 0x7f, 0x68, 0x40, 0x4f, 0xee, 0x8a, 0x70, 0xa9, 0x43,
-	0x62, 0xad, 0xbd, 0x58, 0x7f, 0xfb, 0x74, 0x60, 0x25, 0xec, 0xa6, 0x10, 0xb6, 0x0c, 0x97, 0x3a,
-	0x13, 0x26, 0x1a, 0xbe, 0x51, 0x17, 0x3f, 0x0d, 0xf8, 0x9b, 0x06, 0x86, 0x13, 0x5b, 0x28, 0x5c,
-	0xec, 0x88, 0x60, 0xa4, 0x6d, 0xeb, 0x4b, 0xa7, 0xc2, 0x2a, 0x6d, 0xef, 0x08, 0x6d, 0x8b, 0x70,
-	0xbe, 0x03, 0x6d, 0x7e, 0xdd, 0xb0, 0x8d, 0xba, 0x28, 0x1f, 0x0d, 0xf8, 0x93, 0x06, 0x2e, 0x26,
-	0xf4, 0xcd, 0xb4, 0x38, 0x4c, 0x6f, 0xed, 0x69, 0x71, 0xd8, 0xa6, 0x49, 0xa3, 0x19, 0x21, 0xe9,
-	0x2a, 0x9c, 0x3c, 0xb9, 0x24, 0x0e, 0xf7, 0x35, 0x30, 0x9c, 0xd8, 0x19, 0xd3, 0x8e, 0xa7, 0x5d,
-	0xdf, 0x4d, 0x3b, 0x9e, 0xb6, 0xad, 0x18, 0x2d, 0x0a, 0x2d, 0x6f, 0xc1, 0xe9, 0xf8, 0x22, 0x81,
-	0xb9, 0x67, 0xc5, 0x9f, 0x11, 0xb5, 0xe1, 0x2f, 0x22, 0xe2, 0x12, 0x3a, 0x71, 0x7a, 0xc4, 0xa5,
-	0xf7, 0xf9, 0xf4, 0x88, 0x6b, 0xd3, 0xfa, 0xd1, 0x82, 0x90, 0x34, 0x03, 0xa7, 0x12, 0x8e, 0xc7,
-	0xc3, 0xe5, 0x23, 0x9a, 0x6c, 0x0b, 0x4b, 0xce, 0x5f, 0x6b, 0x60, 0xe0, 0x58, 0x83, 0x87, 0x93,
-	0x6d, 0xd8, 0xb4, 0x1a, 0xeb, 0x33, 0x1d, 0x18, 0x87, 0x94, 0xaf, 0x09, 0xca, 0x13, 0x70, 0x3c,
-	0x85, 0xb2, 0x2a, 0xd8, 0x5c, 0x72, 0xfa, 0x51, 0x03, 0xaf, 0xc7, 0x5f, 0x28, 0x8c, 0x13, 0x66,
-	0x6b, 0x00, 0xd0, 0xe7, 0x3a, 0x04, 0x84, 0xac, 0x6f, 0x08, 0xd6, 0x0b, 0x70, 0xee, 0x24, 0x79,
-	0x50, 0x66, 0xc5, 0x2d, 0x8b, 0x3a, 0xf7, 0x99, 0x51, 0x57, 0x17, 0x84, 0x06, 0xfc, 0x5c, 0x03,
-	0x3d, 0xf2, 0x83, 0x0d, 0xe6, 0x93, 0x49, 0x44, 0xbe, 0x0e, 0xf5, 0xf1, 0xf6, 0x86, 0x8a, 0xde,
-	0xf8, 0x63, 0xff, 0xfb, 0x4f, 0x70, 0x7c, 0x03, 0x8e, 0xc4, 0x72, 0x94, 0x9f, 0x86, 0xf0, 0x79,
-	0x7c, 0xe9, 0x94, 0x57, 0x88, 0x0e, 0x4b, 0x67, 0xe4, 0xce, 0xd4, 0x61, 0xe9, 0x8c, 0x5e, 0x7e,
-	0xd0, 0xfb, 0x82, 0xfb, 0x3a, 0x5c, 0x8b, 0xe5, 0x5e, 0x8f, 0xdc, 0xb6, 0x1a, 0x09, 0xa5, 0x54,
-	0x5d, 0x7c, 0xd6, 0x6e, 0x3c, 0x3d, 0xc8, 0x6a, 0xfb, 0x07, 0x59, 0xed, 0xf9, 0x41, 0x56, 0xfb,
-	0xf2, 0x30, 0x9b, 0xd9, 0x3f, 0xcc, 0x66, 0x7e, 0x3f, 0xcc, 0x66, 0xee, 0x8d, 0x1d, 0xbf, 0xdd,
-	0x08, 0x77, 0x0f, 0x03, 0x87, 0xe2, 0x82, 0xb3, 0xd9, 0x23, 0xfe, 0xe9, 0x30, 0xf3, 0x7f, 0x00,
-	0x00, 0x00, 0xff, 0xff, 0x64, 0x6d, 0x84, 0x43, 0x7e, 0x11, 0x00, 0x00,
+	// 1323 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0xcf, 0x6f, 0x1b, 0x45,
+	0x14, 0xf6, 0x86, 0x26, 0xa5, 0x03, 0xfd, 0x91, 0x69, 0x68, 0x9d, 0x4d, 0x6a, 0x47, 0x43, 0x13,
+	0x5b, 0x89, 0xea, 0x6d, 0x62, 0xd2, 0xfc, 0x22, 0x29, 0x49, 0xa3, 0x42, 0x51, 0x04, 0xc5, 0x2d,
+	0x1c, 0x2a, 0xa4, 0xd5, 0xc4, 0x3b, 0x71, 0x57, 0xb1, 0x77, 0x9c, 0x9d, 0x75, 0xd2, 0xd4, 0xf2,
+	0x05, 0x09, 0xa9, 0x47, 0x24, 0xfe, 0x81, 0xde, 0x40, 0x1c, 0x10, 0x27, 0x24, 0x2e, 0x1c, 0x40,
+	0x42, 0xbd, 0x20, 0x22, 0x21, 0x21, 0x0e, 0xa8, 0x94, 0x04, 0x09, 0xce, 0xfc, 0x05, 0x68, 0x67,
+	0x66, 0x37, 0x5e, 0x67, 0x77, 0x6d, 0x47, 0xb9, 0xc4, 0xde, 0xd9, 0xf7, 0xcd, 0xfb, 0xbe, 0x99,
+	0xf7, 0x66, 0x3e, 0x07, 0xa4, 0x4b, 0xd8, 0xc4, 0x5a, 0xd9, 0xdc, 0xaa, 0x99, 0x86, 0xb6, 0x3d,
+	0xb9, 0x4e, 0x1c, 0x3c, 0xa9, 0x6d, 0xd5, 0x88, 0xbd, 0x9b, 0xab, 0xda, 0xd4, 0xa1, 0xf0, 0xa2,
+	0x1b, 0x90, 0x13, 0x01, 0x39, 0x19, 0xa0, 0x8e, 0x17, 0x29, 0xab, 0x50, 0xa6, 0xad, 0x63, 0x46,
+	0x44, 0xb4, 0x8f, 0xad, 0xe2, 0x92, 0x69, 0x61, 0xc7, 0xa4, 0x96, 0x98, 0x40, 0x1d, 0x28, 0xd1,
+	0x12, 0xe5, 0x5f, 0x35, 0xf7, 0x9b, 0x1c, 0x1d, 0x2e, 0x51, 0x5a, 0x2a, 0x13, 0x0d, 0x57, 0x4d,
+	0x0d, 0x5b, 0x16, 0x75, 0x38, 0x84, 0xc9, 0xb7, 0x23, 0x61, 0xac, 0x24, 0x07, 0x11, 0x91, 0x6a,
+	0x66, 0xe0, 0x45, 0x14, 0xa9, 0xe9, 0x65, 0x1d, 0x92, 0xef, 0x3d, 0x72, 0xcd, 0x9a, 0xd4, 0x7e,
+	0x5c, 0x31, 0x2d, 0xaa, 0xf1, 0xbf, 0x62, 0x08, 0xad, 0x82, 0xa1, 0x0f, 0xdc, 0x88, 0x35, 0x9e,
+	0xe4, 0x23, 0x5c, 0x36, 0x0d, 0xec, 0x50, 0xbb, 0x40, 0xb6, 0x6a, 0x84, 0x39, 0x70, 0x14, 0x9c,
+	0xdb, 0xf6, 0xc6, 0x74, 0x6c, 0x18, 0x76, 0x52, 0x19, 0x51, 0xb2, 0x67, 0x0a, 0x67, 0xfd, 0xd1,
+	0x65, 0xc3, 0xb0, 0xd1, 0x63, 0x30, 0x1c, 0x3e, 0x0b, 0xab, 0x52, 0x8b, 0x11, 0xf8, 0x00, 0x5c,
+	0x10, 0x2a, 0x74, 0x1f, 0xc7, 0x27, 0x7a, 0x65, 0xea, 0x6a, 0x2e, 0x64, 0x9d, 0x73, 0x2d, 0xf3,
+	0xac, 0x9c, 0x79, 0xf6, 0x3c, 0x9d, 0xf8, 0xf2, 0x9f, 0x6f, 0xc6, 0x95, 0xc2, 0xf9, 0x72, 0xf0,
+	0x1d, 0xda, 0x08, 0xcf, 0xcd, 0x3c, 0x09, 0xb7, 0x01, 0x38, 0xdc, 0x1b, 0x99, 0x75, 0x2c, 0x27,
+	0x96, 0x29, 0xe7, 0x2e, 0x63, 0x4e, 0x2c, 0x91, 0x97, 0xfb, 0x2e, 0x2e, 0x11, 0x89, 0x2d, 0x34,
+	0x21, 0xd1, 0x4f, 0x0a, 0xb8, 0x12, 0x91, 0x48, 0xaa, 0xfc, 0x18, 0xf4, 0xb7, 0xaa, 0x64, 0x49,
+	0x65, 0xe4, 0xa5, 0xe3, 0xc8, 0xbc, 0xd0, 0x22, 0x93, 0xc1, 0xb7, 0x03, 0x3a, 0x7a, 0xb8, 0x8e,
+	0x4c, 0x5b, 0x1d, 0x82, 0x5a, 0x40, 0xc8, 0x00, 0x80, 0x5c, 0xc7, 0x5d, 0x6c, 0xe3, 0x8a, 0xb7,
+	0x4c, 0xe8, 0x43, 0x70, 0x31, 0x30, 0x2a, 0x35, 0x2d, 0x81, 0xbe, 0x2a, 0x1f, 0x91, 0x2b, 0x37,
+	0x14, 0x2a, 0x44, 0x80, 0x9a, 0xf9, 0x4b, 0x14, 0x9a, 0x06, 0xaf, 0xf3, 0x69, 0xef, 0xd3, 0x4d,
+	0x62, 0x99, 0x8f, 0xc9, 0xbd, 0x87, 0xd8, 0x26, 0x05, 0x52, 0xa4, 0xb6, 0xb1, 0xb2, 0x7b, 0xc7,
+	0xf0, 0x36, 0xe9, 0x1c, 0xe8, 0x31, 0x0d, 0x9e, 0xe2, 0x54, 0xa1, 0xc7, 0x34, 0x90, 0x05, 0xae,
+	0xc6, 0xc3, 0x24, 0xbd, 0xdb, 0xa0, 0xcf, 0xe6, 0xa3, 0x92, 0x5e, 0x36, 0x94, 0x5e, 0xd8, 0x2c,
+	0xa7, 0x5c, 0xae, 0x05, 0x89, 0x46, 0x4b, 0x60, 0x2c, 0x3a, 0xdf, 0x2a, 0xb1, 0x68, 0xc5, 0x63,
+	0x3a, 0x00, 0x7a, 0x0d, 0xf7, 0x59, 0x36, 0x82, 0x78, 0x40, 0x5b, 0x20, 0xd3, 0x16, 0x7f, 0xc2,
+	0x94, 0x17, 0xc1, 0x68, 0x54, 0x4a, 0xf6, 0xfe, 0x8e, 0x45, 0x8c, 0x26, 0xc6, 0x74, 0xc7, 0x22,
+	0x5e, 0xeb, 0x8a, 0x07, 0x64, 0x47, 0x2b, 0xf6, 0xe0, 0x92, 0xf0, 0x3b, 0xe0, 0xb4, 0x48, 0xe9,
+	0x15, 0x73, 0xb7, 0x8c, 0x3d, 0x38, 0xaa, 0xc8, 0x62, 0x58, 0x2e, 0x97, 0xc3, 0xd2, 0x9e, 0x74,
+	0xc7, 0x7e, 0xa7, 0xc8, 0x2a, 0x8a, 0xcc, 0x77, 0xd2, 0x0a, 0x4f, 0xae, 0x49, 0x33, 0x72, 0x77,
+	0xd7, 0x30, 0x73, 0x42, 0xf2, 0xfa, 0x9d, 0x83, 0x66, 0xe5, 0x3e, 0xc6, 0x04, 0x4a, 0x95, 0xad,
+	0x3d, 0x96, 0xf1, 0x0b, 0xc8, 0xc1, 0xc1, 0xf5, 0x31, 0x96, 0x19, 0x23, 0x8e, 0x7f, 0x34, 0xe8,
+	0x7e, 0xa9, 0x44, 0x06, 0xca, 0x14, 0xd3, 0xa0, 0x77, 0x1b, 0x97, 0x6b, 0x44, 0x6e, 0xda, 0x60,
+	0x40, 0xb9, 0xa7, 0xf9, 0x16, 0x35, 0x2d, 0xb9, 0x6e, 0x22, 0x1a, 0x25, 0xc1, 0xa5, 0xc3, 0x04,
+	0xe2, 0x50, 0xbc, 0xe7, 0xe0, 0x4d, 0x62, 0xa0, 0x59, 0x90, 0x0a, 0x7f, 0xe3, 0xa7, 0xbc, 0x04,
+	0xfa, 0x1c, 0x97, 0x12, 0x93, 0xe5, 0x2d, 0x9f, 0xd0, 0x0d, 0xa0, 0x1e, 0xad, 0xef, 0x35, 0x5a,
+	0xdc, 0xbc, 0x63, 0x6d, 0x50, 0x98, 0x04, 0xa7, 0xdd, 0xdb, 0x8c, 0x30, 0x0f, 0xe6, 0x3d, 0x22,
+	0x02, 0x50, 0x34, 0xae, 0x39, 0x2b, 0x73, 0xb0, 0x53, 0xf3, 0xb3, 0x8a, 0x27, 0x98, 0x01, 0xe7,
+	0xc9, 0xa3, 0xaa, 0x69, 0xf3, 0x4d, 0xd4, 0x1d, 0xb3, 0x42, 0x78, 0x11, 0x9c, 0x29, 0x9c, 0x3b,
+	0x1c, 0xbe, 0x6f, 0x56, 0x08, 0xaa, 0x46, 0x77, 0x6f, 0x81, 0xec, 0x60, 0xdb, 0xef, 0xde, 0x45,
+	0x70, 0x96, 0x37, 0xac, 0x1e, 0xe0, 0xbb, 0x92, 0xfc, 0xef, 0x79, 0x7a, 0x60, 0x17, 0x57, 0xca,
+	0xf3, 0x28, 0xf0, 0x1a, 0x15, 0x5e, 0xe5, 0xcf, 0xcb, 0xe2, 0x71, 0xfe, 0xe5, 0x27, 0x4f, 0xd3,
+	0x89, 0x7f, 0x9f, 0xa6, 0x13, 0xe8, 0x2f, 0x25, 0xba, 0xe3, 0xbd, 0x94, 0x52, 0xdd, 0x7b, 0x6e,
+	0x3f, 0xb8, 0x23, 0x5e, 0x3f, 0xe4, 0x3a, 0xed, 0x07, 0x31, 0xd1, 0x61, 0x57, 0xf0, 0x49, 0x60,
+	0x09, 0xf4, 0x3a, 0xee, 0x06, 0x26, 0x7b, 0xf8, 0x6c, 0xc3, 0xa1, 0x65, 0xb1, 0x4a, 0x8a, 0xbc,
+	0x32, 0xf2, 0x2e, 0xf6, 0xab, 0x3f, 0xd3, 0x13, 0x25, 0xd3, 0x79, 0x58, 0x5b, 0xcf, 0x15, 0x69,
+	0x45, 0x93, 0xa6, 0x46, 0x7c, 0x5c, 0x63, 0xc6, 0xa6, 0xe6, 0xec, 0x56, 0x09, 0xf3, 0x30, 0xac,
+	0x20, 0xe6, 0x9f, 0xfa, 0x1e, 0x82, 0x5e, 0xae, 0x11, 0x7e, 0xad, 0x80, 0x0b, 0xad, 0x17, 0x35,
+	0x9c, 0x0c, 0x95, 0x11, 0xe7, 0x1e, 0xd4, 0xa9, 0x6e, 0x20, 0x62, 0xf9, 0x50, 0xfe, 0x89, 0x7b,
+	0x05, 0x7e, 0xf2, 0xeb, 0xdf, 0x9f, 0xf7, 0x64, 0xe1, 0x98, 0x16, 0xed, 0xe9, 0x9a, 0x7c, 0x02,
+	0xfc, 0x56, 0x01, 0xe7, 0x5b, 0x66, 0x84, 0xd7, 0x3b, 0x4e, 0xee, 0xd1, 0x9d, 0xec, 0x02, 0x21,
+	0xd9, 0x2e, 0x71, 0xa2, 0xb3, 0xf0, 0x46, 0x47, 0x44, 0xb5, 0x7a, 0xd0, 0x0f, 0x36, 0xe0, 0xcf,
+	0x0a, 0xb8, 0x1c, 0x71, 0x4d, 0xc3, 0xd9, 0x68, 0x3a, 0xf1, 0x86, 0x40, 0x9d, 0x3b, 0x06, 0x52,
+	0x0a, 0x5a, 0xe4, 0x82, 0x66, 0xe0, 0x74, 0xa8, 0x20, 0x47, 0xa2, 0x75, 0xe6, 0xc2, 0x75, 0x71,
+	0x70, 0xeb, 0xeb, 0xbb, 0xba, 0x69, 0x68, 0x75, 0xd3, 0x68, 0xc0, 0x3f, 0x14, 0xa0, 0x46, 0x5f,
+	0xe3, 0x70, 0xa1, 0x4b, 0x62, 0xcd, 0xe6, 0x41, 0x7d, 0xf3, 0x78, 0x60, 0x29, 0xec, 0x16, 0x17,
+	0xb6, 0x08, 0x17, 0xba, 0x13, 0xc6, 0x1d, 0x8a, 0x56, 0xe7, 0x1f, 0x0d, 0xf8, 0x9b, 0x02, 0x06,
+	0x23, 0xef, 0x7c, 0x38, 0xdf, 0x15, 0xc1, 0x80, 0xcf, 0x50, 0x17, 0x8e, 0x85, 0x95, 0xda, 0xde,
+	0xe2, 0xda, 0xe6, 0xe1, 0x6c, 0x17, 0xda, 0xdc, 0x83, 0xce, 0xd0, 0xea, 0xfc, 0xbc, 0x6b, 0xc0,
+	0x1f, 0x15, 0x70, 0x39, 0xe2, 0xa2, 0x8f, 0xab, 0xc3, 0x78, 0x2f, 0x12, 0x57, 0x87, 0x6d, 0x5c,
+	0x05, 0xca, 0x73, 0x49, 0xd7, 0xe0, 0x44, 0xe7, 0x92, 0x18, 0xdc, 0x53, 0xc0, 0x60, 0xe4, 0x55,
+	0x1e, 0xb7, 0x3d, 0xed, 0x8c, 0x42, 0xdc, 0xf6, 0xb4, 0xf5, 0x0e, 0x68, 0x9e, 0x6b, 0x79, 0x03,
+	0x4e, 0x85, 0x1f, 0x12, 0x98, 0x39, 0x7a, 0xf8, 0x1e, 0x99, 0x06, 0xfc, 0x85, 0x57, 0x5c, 0x84,
+	0x75, 0x88, 0xaf, 0xb8, 0x78, 0x63, 0x12, 0x5f, 0x71, 0x6d, 0xbc, 0x0a, 0x9a, 0xe3, 0x92, 0xf2,
+	0x70, 0x32, 0x62, 0x7b, 0x1c, 0x5c, 0x6e, 0xd1, 0x64, 0xe8, 0x58, 0x70, 0xfe, 0x42, 0x01, 0xfd,
+	0x47, 0x1c, 0x09, 0x9c, 0x68, 0xc3, 0xa6, 0x39, 0x58, 0xcd, 0x77, 0x11, 0xec, 0x53, 0xbe, 0xce,
+	0x29, 0x8f, 0xc3, 0x6c, 0x0c, 0x65, 0x79, 0x60, 0x33, 0xc1, 0xe9, 0x07, 0x05, 0xbc, 0x16, 0xee,
+	0x80, 0xb4, 0x0e, 0xbb, 0xd5, 0x03, 0xa8, 0x33, 0x5d, 0x02, 0x7c, 0xd6, 0x37, 0x39, 0xeb, 0x39,
+	0x38, 0xd3, 0x49, 0x1f, 0x94, 0x69, 0x71, 0x53, 0x37, 0xad, 0x0d, 0xaa, 0xd5, 0xa5, 0xa3, 0x69,
+	0xc0, 0x4f, 0x15, 0xd0, 0x27, 0x7e, 0x61, 0xc2, 0x4c, 0x34, 0x89, 0xc0, 0xcf, 0x59, 0x35, 0xdb,
+	0x3e, 0x50, 0xd2, 0xcb, 0x1e, 0xde, 0xd6, 0x57, 0xe0, 0x50, 0x28, 0x47, 0xf1, 0x5b, 0x16, 0xbe,
+	0x08, 0x3f, 0x3a, 0x85, 0xe7, 0xe9, 0xf2, 0xe8, 0x0c, 0x98, 0xbc, 0x2e, 0x8f, 0xce, 0xa0, 0x5b,
+	0x43, 0xef, 0x72, 0xee, 0xab, 0x70, 0x25, 0x94, 0x7b, 0x3d, 0x60, 0x0f, 0x1b, 0x11, 0x47, 0xa9,
+	0x74, 0x6a, 0x2b, 0x37, 0x9f, 0xed, 0xa7, 0x94, 0xbd, 0xfd, 0x94, 0xf2, 0x62, 0x3f, 0xa5, 0x7c,
+	0x76, 0x90, 0x4a, 0xec, 0x1d, 0xa4, 0x12, 0xbf, 0x1f, 0xa4, 0x12, 0x0f, 0x46, 0x8f, 0xda, 0x31,
+	0x9e, 0xee, 0x91, 0x97, 0x90, 0x3b, 0xb2, 0xf5, 0x3e, 0xfe, 0x6f, 0xa5, 0xfc, 0xff, 0x01, 0x00,
+	0x00, 0xff, 0xff, 0x18, 0xf5, 0xc3, 0x1b, 0x60, 0x13, 0x00, 0x00,
 }
 
 // Reference imports to suppress errors if they are not otherwise used.
@@ -1165,6 +1275,11 @@ const _ = grpc.SupportPackageIsVersion4
 //
 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
 type QueryClient interface {
+	// LiquidValidators queries all liquid validators.
+	//
+	// When called from another module, this query might consume a high amount of
+	// gas if the pagination field is incorrectly set.
+	LiquidValidators(ctx context.Context, in *QueryLiquidValidatorsRequest, opts ...grpc.CallOption) (*QueryLiquidValidatorsResponse, error)
 	// Query for an individual liquid validator by validator address
 	LiquidValidator(ctx context.Context, in *QueryLiquidValidatorRequest, opts ...grpc.CallOption) (*QueryLiquidValidatorResponse, error)
 	// Query for individual tokenize share record information by share by id
@@ -1198,6 +1313,15 @@ func NewQueryClient(cc grpc1.ClientConn) QueryClient {
 	return &queryClient{cc}
 }
 
+func (c *queryClient) LiquidValidators(ctx context.Context, in *QueryLiquidValidatorsRequest, opts ...grpc.CallOption) (*QueryLiquidValidatorsResponse, error) {
+	out := new(QueryLiquidValidatorsResponse)
+	err := c.cc.Invoke(ctx, "/gaia.liquid.v1beta1.Query/LiquidValidators", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
 func (c *queryClient) LiquidValidator(ctx context.Context, in *QueryLiquidValidatorRequest, opts ...grpc.CallOption) (*QueryLiquidValidatorResponse, error) {
 	out := new(QueryLiquidValidatorResponse)
 	err := c.cc.Invoke(ctx, "/gaia.liquid.v1beta1.Query/LiquidValidator", in, out, opts...)
@@ -1299,6 +1423,11 @@ func (c *queryClient) TokenizeShareRecordReward(ctx context.Context, in *QueryTo
 
 // QueryServer is the server API for Query service.
 type QueryServer interface {
+	// LiquidValidators queries all liquid validators.
+	//
+	// When called from another module, this query might consume a high amount of
+	// gas if the pagination field is incorrectly set.
+	LiquidValidators(context.Context, *QueryLiquidValidatorsRequest) (*QueryLiquidValidatorsResponse, error)
 	// Query for an individual liquid validator by validator address
 	LiquidValidator(context.Context, *QueryLiquidValidatorRequest) (*QueryLiquidValidatorResponse, error)
 	// Query for individual tokenize share record information by share by id
@@ -1328,6 +1457,9 @@ type QueryServer interface {
 type UnimplementedQueryServer struct {
 }
 
+func (*UnimplementedQueryServer) LiquidValidators(ctx context.Context, req *QueryLiquidValidatorsRequest) (*QueryLiquidValidatorsResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method LiquidValidators not implemented")
+}
 func (*UnimplementedQueryServer) LiquidValidator(ctx context.Context, req *QueryLiquidValidatorRequest) (*QueryLiquidValidatorResponse, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method LiquidValidator not implemented")
 }
@@ -1366,6 +1498,24 @@ func RegisterQueryServer(s grpc1.Server, srv QueryServer) {
 	s.RegisterService(&_Query_serviceDesc, srv)
 }
 
+func _Query_LiquidValidators_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(QueryLiquidValidatorsRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(QueryServer).LiquidValidators(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/gaia.liquid.v1beta1.Query/LiquidValidators",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(QueryServer).LiquidValidators(ctx, req.(*QueryLiquidValidatorsRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
 func _Query_LiquidValidator_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
 	in := new(QueryLiquidValidatorRequest)
 	if err := dec(in); err != nil {
@@ -1569,6 +1719,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{
 	ServiceName: "gaia.liquid.v1beta1.Query",
 	HandlerType: (*QueryServer)(nil),
 	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "LiquidValidators",
+			Handler:    _Query_LiquidValidators_Handler,
+		},
 		{
 			MethodName: "LiquidValidator",
 			Handler:    _Query_LiquidValidator_Handler,
@@ -1681,6 +1835,90 @@ func (m *QueryLiquidValidatorResponse) MarshalToSizedBuffer(dAtA []byte) (int, e
 	return len(dAtA) - i, nil
 }
 
+func (m *QueryLiquidValidatorsRequest) 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 *QueryLiquidValidatorsRequest) MarshalTo(dAtA []byte) (int, error) {
+	size := m.Size()
+	return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *QueryLiquidValidatorsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+	i := len(dAtA)
+	_ = i
+	var l int
+	_ = l
+	if m.Pagination != nil {
+		{
+			size, err := m.Pagination.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 *QueryLiquidValidatorsResponse) 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 *QueryLiquidValidatorsResponse) MarshalTo(dAtA []byte) (int, error) {
+	size := m.Size()
+	return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *QueryLiquidValidatorsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+	i := len(dAtA)
+	_ = i
+	var l int
+	_ = l
+	if m.Pagination != nil {
+		{
+			size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i])
+			if err != nil {
+				return 0, err
+			}
+			i -= size
+			i = encodeVarintQuery(dAtA, i, uint64(size))
+		}
+		i--
+		dAtA[i] = 0x12
+	}
+	if len(m.LiquidValidators) > 0 {
+		for iNdEx := len(m.LiquidValidators) - 1; iNdEx >= 0; iNdEx-- {
+			{
+				size, err := m.LiquidValidators[iNdEx].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 *QueryParamsRequest) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
 	dAtA = make([]byte, size)
@@ -2355,6 +2593,38 @@ func (m *QueryLiquidValidatorResponse) Size() (n int) {
 	return n
 }
 
+func (m *QueryLiquidValidatorsRequest) Size() (n int) {
+	if m == nil {
+		return 0
+	}
+	var l int
+	_ = l
+	if m.Pagination != nil {
+		l = m.Pagination.Size()
+		n += 1 + l + sovQuery(uint64(l))
+	}
+	return n
+}
+
+func (m *QueryLiquidValidatorsResponse) Size() (n int) {
+	if m == nil {
+		return 0
+	}
+	var l int
+	_ = l
+	if len(m.LiquidValidators) > 0 {
+		for _, e := range m.LiquidValidators {
+			l = e.Size()
+			n += 1 + l + sovQuery(uint64(l))
+		}
+	}
+	if m.Pagination != nil {
+		l = m.Pagination.Size()
+		n += 1 + l + sovQuery(uint64(l))
+	}
+	return n
+}
+
 func (m *QueryParamsRequest) Size() (n int) {
 	if m == nil {
 		return 0
@@ -2780,6 +3050,212 @@ func (m *QueryLiquidValidatorResponse) Unmarshal(dAtA []byte) error {
 	}
 	return nil
 }
+func (m *QueryLiquidValidatorsRequest) 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: QueryLiquidValidatorsRequest: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: QueryLiquidValidatorsRequest: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Pagination", 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.Pagination == nil {
+				m.Pagination = &query.PageRequest{}
+			}
+			if err := m.Pagination.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 *QueryLiquidValidatorsResponse) 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: QueryLiquidValidatorsResponse: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: QueryLiquidValidatorsResponse: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field LiquidValidators", 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
+			}
+			m.LiquidValidators = append(m.LiquidValidators, LiquidValidator{})
+			if err := m.LiquidValidators[len(m.LiquidValidators)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 2:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Pagination", 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.Pagination == nil {
+				m.Pagination = &query.PageResponse{}
+			}
+			if err := m.Pagination.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 *QueryParamsRequest) Unmarshal(dAtA []byte) error {
 	l := len(dAtA)
 	iNdEx := 0
diff --git a/x/liquid/types/query.pb.gw.go b/x/liquid/types/query.pb.gw.go
index b10af6a..b371995 100644
--- a/x/liquid/types/query.pb.gw.go
+++ b/x/liquid/types/query.pb.gw.go
@@ -33,6 +33,42 @@ var _ = utilities.NewDoubleArray
 var _ = descriptor.ForMessage
 var _ = metadata.Join
 
+var (
+	filter_Query_LiquidValidators_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
+)
+
+func request_Query_LiquidValidators_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq QueryLiquidValidatorsRequest
+	var metadata runtime.ServerMetadata
+
+	if err := req.ParseForm(); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+	if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_LiquidValidators_0); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := client.LiquidValidators(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+func local_request_Query_LiquidValidators_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq QueryLiquidValidatorsRequest
+	var metadata runtime.ServerMetadata
+
+	if err := req.ParseForm(); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+	if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_LiquidValidators_0); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := server.LiquidValidators(ctx, &protoReq)
+	return msg, metadata, err
+
+}
+
 func request_Query_LiquidValidator_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
 	var protoReq QueryLiquidValidatorRequest
 	var metadata runtime.ServerMetadata
@@ -471,6 +507,29 @@ func local_request_Query_TokenizeShareRecordReward_0(ctx context.Context, marsha
 // Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead.
 func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error {
 
+	mux.Handle("GET", pattern_Query_LiquidValidators_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_LiquidValidators_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_LiquidValidators_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
 	mux.Handle("GET", pattern_Query_LiquidValidator_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
@@ -765,6 +824,26 @@ func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc
 // "QueryClient" to call the correct interceptors.
 func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error {
 
+	mux.Handle("GET", pattern_Query_LiquidValidators_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_LiquidValidators_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_LiquidValidators_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
 	mux.Handle("GET", pattern_Query_LiquidValidator_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
@@ -989,6 +1068,8 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie
 }
 
 var (
+	pattern_Query_LiquidValidators_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"gaia", "liquid", "v1beta1", "liquid_validators"}, "", runtime.AssumeColonVerbOpt(false)))
+
 	pattern_Query_LiquidValidator_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"gaia", "liquid", "v1beta1", "liquid_validator", "validator_addr"}, "", runtime.AssumeColonVerbOpt(false)))
 
 	pattern_Query_TokenizeShareRecordById_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"gaia", "liquid", "v1beta1", "tokenize_share_record_by_id", "id"}, "", runtime.AssumeColonVerbOpt(false)))
@@ -1013,6 +1094,8 @@ var (
 )
 
 var (
+	forward_Query_LiquidValidators_0 = runtime.ForwardResponseMessage
+
 	forward_Query_LiquidValidator_0 = runtime.ForwardResponseMessage
 
 	forward_Query_TokenizeShareRecordById_0 = runtime.ForwardResponseMessage



Test patch:
diff --git a/x/liquid/keeper/grpc_query_test.go b/x/liquid/keeper/grpc_query_test.go
index 36f4caa..cd6e5bb 100644
--- a/x/liquid/keeper/grpc_query_test.go
+++ b/x/liquid/keeper/grpc_query_test.go
@@ -7,6 +7,7 @@ import (
 	"cosmossdk.io/math"
 
 	sdk "github.com/cosmos/cosmos-sdk/types"
+	"github.com/cosmos/cosmos-sdk/types/query"
 
 	"github.com/cosmos/gaia/v25/x/liquid/types"
 )
@@ -71,3 +72,116 @@ func (s *KeeperTestSuite) TestGRPCQueryLiquidValidator() {
 		})
 	}
 }
+
+func (s *KeeperTestSuite) TestGRPCQueryLiquidValidators() {
+	ctx, keeper, queryClient := s.ctx, s.lsmKeeper, s.queryClient
+	require := s.Require()
+
+	// Create multiple liquid validators for testing
+	lVal1 := types.NewLiquidValidator(sdk.ValAddress(PKs[0].Address().Bytes()).String())
+	lVal1.LiquidShares = math.LegacyNewDec(10000)
+	require.NoError(keeper.SetLiquidValidator(ctx, lVal1))
+
+	lVal2 := types.NewLiquidValidator(sdk.ValAddress(PKs[1].Address().Bytes()).String())
+	lVal2.LiquidShares = math.LegacyNewDec(20000)
+	require.NoError(keeper.SetLiquidValidator(ctx, lVal2))
+
+	lVal3 := types.NewLiquidValidator(sdk.ValAddress(PKs[2].Address().Bytes()).String())
+	lVal3.LiquidShares = math.LegacyNewDec(30000)
+	require.NoError(keeper.SetLiquidValidator(ctx, lVal3))
+
+	var req *types.QueryLiquidValidatorsRequest
+	testCases := []struct {
+		msg      string
+		malleate func()
+		expPass  bool
+	}{
+		{
+			"empty request",
+			func() {
+				req = &types.QueryLiquidValidatorsRequest{}
+			},
+			true,
+		},
+		{
+			"valid request with pagination limit",
+			func() {
+				req = &types.QueryLiquidValidatorsRequest{
+					Pagination: &query.PageRequest{
+						Limit: 2,
+					},
+				}
+			},
+			true,
+		},
+		{
+			"valid request with offset pagination",
+			func() {
+				req = &types.QueryLiquidValidatorsRequest{
+					Pagination: &query.PageRequest{
+						Offset: 1,
+						Limit:  2,
+					},
+				}
+			},
+			true,
+		},
+		{
+			"request with count total",
+			func() {
+				req = &types.QueryLiquidValidatorsRequest{
+					Pagination: &query.PageRequest{
+						CountTotal: true,
+					},
+				}
+			},
+			true,
+		},
+	}
+
+	for _, tc := range testCases {
+		s.Run(fmt.Sprintf("Case %s", tc.msg), func() {
+			tc.malleate()
+			res, err := queryClient.LiquidValidators(gocontext.Background(), req)
+			if tc.expPass {
+				require.NoError(err)
+				require.NotNil(res)
+				require.NotNil(res.LiquidValidators)
+
+				// Additional checks for specific test cases
+				if tc.msg == "empty request" {
+					// Should return all validators
+					require.Len(res.LiquidValidators, 3)
+
+					// Verify the validators are correct
+					foundValidators := make(map[string]bool)
+					for _, lv := range res.LiquidValidators {
+						foundValidators[lv.OperatorAddress] = true
+					}
+					require.True(foundValidators[lVal1.OperatorAddress])
+					require.True(foundValidators[lVal2.OperatorAddress])
+					require.True(foundValidators[lVal3.OperatorAddress])
+				}
+
+				if tc.msg == "request with count total" {
+					require.NotNil(res.Pagination)
+					require.Equal(uint64(3), res.Pagination.Total)
+					require.Len(res.LiquidValidators, 3)
+				}
+
+				if tc.msg == "valid request with pagination limit" {
+					require.NotNil(res.Pagination)
+					require.Len(res.LiquidValidators, 2)
+				}
+
+				if tc.msg == "valid request with offset pagination" {
+					require.NotNil(res.Pagination)
+					require.Len(res.LiquidValidators, 2)
+				}
+			} else {
+				require.Error(err)
+				require.Nil(res)
+			}
+		})
+	}
+}