From ce9eda393fb339737e5091dfbf33e430c1e5914f Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Tue, 5 Mar 2024 21:56:31 +0700 Subject: [PATCH 01/14] add placeholder code --- x/interchainstaking/client/cli/query.go | 51 +++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/x/interchainstaking/client/cli/query.go b/x/interchainstaking/client/cli/query.go index d1bb5de5c..4fbbe6b8c 100644 --- a/x/interchainstaking/client/cli/query.go +++ b/x/interchainstaking/client/cli/query.go @@ -180,3 +180,54 @@ func GetMappedAccountsCmd() *cobra.Command { return cmd } + +func GetWithdrawalRecordsCmd() *cobra.Command { + // TODO: implement + return &cobra.Command{} +} + +func GetUserWithdrawalRecordCmd() *cobra.Command { + // TODO: implement + return &cobra.Command{} +} +func GetZoneWithdrawalRecords() *cobra.Command { + // TODO: implement + return &cobra.Command{} +} + +func GetUnbondingRecordsCmd() *cobra.Command { + // TODO: implement + return &cobra.Command{} +} + +func GetUserUnbondingRecordCmd() *cobra.Command { + // TODO: implement + return &cobra.Command{} +} + +func GetReceptsCmd() *cobra.Command { + // TODO: implement + return &cobra.Command{} +} + +func GetTxStatusCmd() *cobra.Command { + // TODO: implement + return &cobra.Command{} +} + +func GetDelegationRecordsCmd() *cobra.Command { + // TODO: implement + return &cobra.Command{} +} + +// GetZoneValidatorCmd returns the validators for the given zone. +func GetZoneValidatorsCmd() *cobra.Command { + // ToDO: implement + return &cobra.Command{} +} + +// GetZoneCmd returns the information about the zone. +func GetZoneCmd() *cobra.Command { + // TODO: implement + return &cobra.Command{} +} From 3a34bbba5c1897957cfb49e7b3b1ffc069ec8e8f Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Thu, 7 Mar 2024 17:13:47 +0700 Subject: [PATCH 02/14] refactor based on function names --- x/interchainstaking/keeper/grpc_query.go | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/x/interchainstaking/keeper/grpc_query.go b/x/interchainstaking/keeper/grpc_query.go index e8cd63105..9badca6c9 100644 --- a/x/interchainstaking/keeper/grpc_query.go +++ b/x/interchainstaking/keeper/grpc_query.go @@ -245,18 +245,7 @@ func (k *Keeper) ZoneWithdrawalRecords(c context.Context, req *types.QueryWithdr ctx := sdk.UnwrapSDKContext(c) - zone, found := k.GetZone(ctx, req.GetChainId()) - if !found { - return nil, status.Error(codes.NotFound, fmt.Sprintf("no zone found matching %s", req.GetChainId())) - } - - withdrawalrecords := make([]types.WithdrawalRecord, 0) - k.IterateZoneWithdrawalRecords(ctx, zone.ChainId, func(index int64, record types.WithdrawalRecord) (stop bool) { - if record.Delegator == req.DelegatorAddress { - withdrawalrecords = append(withdrawalrecords, record) - } - return false - }) + withdrawalrecords := k.AllZoneWithdrawalRecords(ctx, req.ChainId) return &types.QueryWithdrawalRecordsResponse{Withdrawals: withdrawalrecords}, nil } @@ -269,7 +258,7 @@ func (k *Keeper) WithdrawalRecords(c context.Context, req *types.QueryWithdrawal ctx := sdk.UnwrapSDKContext(c) - withdrawalrecords := k.AllZoneWithdrawalRecords(ctx, req.ChainId) + withdrawalrecords := k.AllWithdrawalRecords(ctx) return &types.QueryWithdrawalRecordsResponse{Withdrawals: withdrawalrecords}, nil } From 783d067b8a2ba3f6a055165487481585fcfb5b3f Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Thu, 7 Mar 2024 17:44:00 +0700 Subject: [PATCH 03/14] add queries to CLI --- x/interchainstaking/client/cli/query.go | 313 ++++++++++++++++-- x/interchainstaking/keeper/grpc_query.go | 1 + .../keeper/redelegation_record.go | 2 +- 3 files changed, 290 insertions(+), 26 deletions(-) diff --git a/x/interchainstaking/client/cli/query.go b/x/interchainstaking/client/cli/query.go index 4fbbe6b8c..dc65fdc32 100644 --- a/x/interchainstaking/client/cli/query.go +++ b/x/interchainstaking/client/cli/query.go @@ -30,6 +30,15 @@ func GetQueryCmd() *cobra.Command { GetDelegatorIntentCmd(), GetDepositAccountCmd(), GetMappedAccountsCmd(), + GetWithdrawalRecordsCmd(), + GetUserWithdrawalRecordsCmd(), + GetZoneWithdrawalRecords(), + GetUnbondingRecordsCmd(), + GetReceiptsCmd(), + GetTxStatusCmd(), + GetZoneRedelegationRecordsCmd(), + GetZoneValidatorsCmd(), + GetZoneCmd(), ) return cmd @@ -182,52 +191,306 @@ func GetMappedAccountsCmd() *cobra.Command { } func GetWithdrawalRecordsCmd() *cobra.Command { - // TODO: implement - return &cobra.Command{} + cmd := &cobra.Command{ + Use: "withdrawal-records", + Short: "Query all withdrawal records", + Example: strings.TrimSpace( + fmt.Sprintf(`$ %s query interchainstaking withdrawal-records`, + version.AppName, + )), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + + req := &types.QueryWithdrawalRecordsRequest{ + Pagination: pageReq, + } + + res, err := queryClient.WithdrawalRecords(cmd.Context(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + flags.AddQueryFlagsToCmd(cmd) + + return cmd } -func GetUserWithdrawalRecordCmd() *cobra.Command { - // TODO: implement - return &cobra.Command{} +func GetUserWithdrawalRecordsCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "user-withdrawal-record [user-address]", + Short: "Query withdrawal record for a given address.", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + // args + address := args[0] + + queryClient := types.NewQueryClient(clientCtx) + req := &types.QueryUserWithdrawalRecordsRequest{ + UserAddress: address, + } + + res, err := queryClient.UserWithdrawalRecords(cmd.Context(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + return cmd } func GetZoneWithdrawalRecords() *cobra.Command { - // TODO: implement - return &cobra.Command{} + cmd := &cobra.Command{ + Use: "zone-withdrawal-records [chain-id]", + Short: "Query withdrawal records for a given zone.", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + // args + chainID := args[0] + + queryClient := types.NewQueryClient(clientCtx) + req := &types.QueryWithdrawalRecordsRequest{ + ChainId: chainID, + } + + res, err := queryClient.ZoneWithdrawalRecords(cmd.Context(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + flags.AddQueryFlagsToCmd(cmd) + return cmd } func GetUnbondingRecordsCmd() *cobra.Command { - // TODO: implement - return &cobra.Command{} -} + cmd := &cobra.Command{ + Use: "unbonding-records", + Short: "Query all unbonding records", + Example: strings.TrimSpace( + fmt.Sprintf(`$ %s query interchainstaking unbonding-records`, + version.AppName, + )), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + + req := &types.QueryUnbondingRecordsRequest{ + Pagination: pageReq, + } + + res, err := queryClient.UnbondingRecords(cmd.Context(), req) + if err != nil { + return err + } -func GetUserUnbondingRecordCmd() *cobra.Command { - // TODO: implement - return &cobra.Command{} + return clientCtx.PrintProto(res) + }, + } + flags.AddQueryFlagsToCmd(cmd) + return cmd } -func GetReceptsCmd() *cobra.Command { - // TODO: implement - return &cobra.Command{} +func GetReceiptsCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "recepts", + Short: "Query all receipts", + Example: strings.TrimSpace( + fmt.Sprintf(`$ %s query interchainstaking receipts`, + version.AppName, + )), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + + req := &types.QueryReceiptsRequest{ + Pagination: pageReq, + } + + res, err := queryClient.Receipts(cmd.Context(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + flags.AddQueryFlagsToCmd(cmd) + return cmd } func GetTxStatusCmd() *cobra.Command { - // TODO: implement - return &cobra.Command{} + cmd := &cobra.Command{ + Use: "tx-status [chain-id] [tx-hash]", + Short: "Query the status of a transaction", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + chainID := args[0] + txHash := args[1] + + queryClient := types.NewQueryClient(clientCtx) + req := &types.QueryTxStatusRequest{ + ChainId: chainID, + TxHash: txHash, + } + + res, err := queryClient.TxStatus(cmd.Context(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + flags.AddQueryFlagsToCmd(cmd) + return cmd } -func GetDelegationRecordsCmd() *cobra.Command { - // TODO: implement - return &cobra.Command{} +func GetZoneRedelegationRecordsCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "zone-redelegation-records", + Short: "Query re-delegation records for a given zone.", + Example: strings.TrimSpace( + fmt.Sprintf(`$ %s query interchainstaking zone-redelegation-records`, + version.AppName, + )), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + if err != nil { + return err + } + chainID := args[0] + req := &types.QueryRedelegationRecordsRequest{ + ChainId: chainID, + } + + // TODO: refactor this. Should be RedelegationRecords + res, err := queryClient.RedelegationRecords(cmd.Context(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + flags.AddQueryFlagsToCmd(cmd) + return cmd } // GetZoneValidatorCmd returns the validators for the given zone. func GetZoneValidatorsCmd() *cobra.Command { - // ToDO: implement - return &cobra.Command{} + cmd := &cobra.Command{ + Use: "zone-validators", + Short: "Query validators for a given zone.", + Example: strings.TrimSpace( + fmt.Sprintf(`$ %s query interchainstaking zone-validators`, + version.AppName, + )), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + req := &types.QueryZoneValidatorsRequest{} + + res, err := queryClient.ZoneValidators(cmd.Context(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + flags.AddQueryFlagsToCmd(cmd) + return cmd } // GetZoneCmd returns the information about the zone. func GetZoneCmd() *cobra.Command { - // TODO: implement - return &cobra.Command{} + cmd := &cobra.Command{ + Use: "zone [chain-id]", + Short: "Query zone information for a given chain.", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + chainID := args[0] + + queryClient := types.NewQueryClient(clientCtx) + req := &types.QueryZoneRequest{ + ChainId: chainID, + } + + res, err := queryClient.Zone(cmd.Context(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + flags.AddQueryFlagsToCmd(cmd) + return cmd } diff --git a/x/interchainstaking/keeper/grpc_query.go b/x/interchainstaking/keeper/grpc_query.go index 9badca6c9..fe7cb083e 100644 --- a/x/interchainstaking/keeper/grpc_query.go +++ b/x/interchainstaking/keeper/grpc_query.go @@ -293,6 +293,7 @@ func (k *Keeper) UnbondingRecords(c context.Context, req *types.QueryUnbondingRe return &types.QueryUnbondingRecordsResponse{Unbondings: unbondings}, nil } +// TODO: refactor this. Should be ZoneRedelegationRecords since it's only for a specific zone func (k *Keeper) RedelegationRecords(c context.Context, req *types.QueryRedelegationRecordsRequest) (*types.QueryRedelegationRecordsResponse, error) { // TODO: implement pagination if req == nil { diff --git a/x/interchainstaking/keeper/redelegation_record.go b/x/interchainstaking/keeper/redelegation_record.go index 8dd1c9c47..2331e6241 100644 --- a/x/interchainstaking/keeper/redelegation_record.go +++ b/x/interchainstaking/keeper/redelegation_record.go @@ -66,7 +66,7 @@ func (k *Keeper) IterateRedelegationRecords(ctx sdk.Context, fn func(index int64 k.IteratePrefixedRedelegationRecords(ctx, nil, fn) } -// AllRedelegationRecords returns every record in the store for the specified zone. +// AllRedelegationRecords returns every record in the store func (k *Keeper) AllRedelegationRecords(ctx sdk.Context) []types.RedelegationRecord { records := []types.RedelegationRecord{} k.IterateRedelegationRecords(ctx, func(_ int64, _ []byte, record types.RedelegationRecord) (stop bool) { From e3e231417c6e4751232399e95a8577bc422e2c9a Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Thu, 7 Mar 2024 17:45:27 +0700 Subject: [PATCH 04/14] remove redundant code --- x/interchainstaking/client/cli/query.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/x/interchainstaking/client/cli/query.go b/x/interchainstaking/client/cli/query.go index dc65fdc32..e7719a448 100644 --- a/x/interchainstaking/client/cli/query.go +++ b/x/interchainstaking/client/cli/query.go @@ -259,6 +259,7 @@ func GetUserWithdrawalRecordsCmd() *cobra.Command { flags.AddQueryFlagsToCmd(cmd) return cmd } + func GetZoneWithdrawalRecords() *cobra.Command { cmd := &cobra.Command{ Use: "zone-withdrawal-records [chain-id]", @@ -412,9 +413,6 @@ func GetZoneRedelegationRecordsCmd() *cobra.Command { } queryClient := types.NewQueryClient(clientCtx) - if err != nil { - return err - } chainID := args[0] req := &types.QueryRedelegationRecordsRequest{ ChainId: chainID, From 69f5bf814953086308bb322d616e6ac2232f4e08 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Thu, 7 Mar 2024 18:05:15 +0700 Subject: [PATCH 05/14] Add missing chain-id check --- x/interchainstaking/keeper/grpc_query.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x/interchainstaking/keeper/grpc_query.go b/x/interchainstaking/keeper/grpc_query.go index fe7cb083e..b96dcf78e 100644 --- a/x/interchainstaking/keeper/grpc_query.go +++ b/x/interchainstaking/keeper/grpc_query.go @@ -244,6 +244,10 @@ func (k *Keeper) ZoneWithdrawalRecords(c context.Context, req *types.QueryWithdr } ctx := sdk.UnwrapSDKContext(c) + _, found := k.GetZone(ctx, req.ChainId) + if !found { + return nil, status.Error(codes.NotFound, fmt.Sprintf("no zone found matching %s", req.GetChainId())) + } withdrawalrecords := k.AllZoneWithdrawalRecords(ctx, req.ChainId) From 36c17143bef43697761494b42cda319b32d5e7e6 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Fri, 8 Mar 2024 15:59:28 +0700 Subject: [PATCH 06/14] add test and refactor query --- x/interchainstaking/client/cli/cli_test.go | 445 +++++++++++++++++++++ x/interchainstaking/client/cli/query.go | 25 +- 2 files changed, 461 insertions(+), 9 deletions(-) diff --git a/x/interchainstaking/client/cli/cli_test.go b/x/interchainstaking/client/cli/cli_test.go index 46bc379b7..e687f4852 100644 --- a/x/interchainstaking/client/cli/cli_test.go +++ b/x/interchainstaking/client/cli/cli_test.go @@ -12,6 +12,7 @@ import ( clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" "github.com/cosmos/cosmos-sdk/testutil/network" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" "github.com/quicksilver-zone/quicksilver/app" "github.com/quicksilver-zone/quicksilver/x/interchainstaking/client/cli" @@ -66,6 +67,7 @@ func (s *IntegrationTestSuite) SetupSuite() { MessagesPerTx: 0, Is_118: true, } + zone.Validators = append(zone.Validators, &types.Validator{ValoperAddress: "cosmosvaloper1sjllsnramtg3ewxqwwrwjxfgc4n4ef9u2lcnj0", CommissionRate: sdk.MustNewDecFromStr("0.2"), VotingPower: sdk.NewInt(2000), DelegatorShares: sdk.NewDec(2000), Score: sdk.ZeroDec(), ValidatorBondShares: sdk.ZeroDec(), LiquidShares: sdk.ZeroDec()}, &types.Validator{ValoperAddress: "cosmosvaloper156gqf9837u7d4c4678yt3rl4ls9c5vuursrrzf", CommissionRate: sdk.MustNewDecFromStr("0.2"), VotingPower: sdk.NewInt(2000), DelegatorShares: sdk.NewDec(2000), Score: sdk.ZeroDec(), ValidatorBondShares: sdk.ZeroDec(), LiquidShares: sdk.ZeroDec()}, @@ -419,6 +421,449 @@ func (s *IntegrationTestSuite) TestGetSignalIntentTxCmd() { } } +func (s *IntegrationTestSuite) TestGetWithdrawalRecordsCmd() { + val := s.network.Validators[0] + + tests := []struct { + name string + args []string + expectErr bool + respType proto.Message + expected proto.Message + }{ + { + "no args", + []string{}, + true, + &types.QueryWithdrawalRecordsResponse{}, + &types.QueryWithdrawalRecordsResponse{}, + }, + { + "empty args", + []string{""}, + true, + &types.QueryWithdrawalRecordsResponse{}, + &types.QueryWithdrawalRecordsResponse{}, + }, + { + "invalid chainID", + []string{"boguschainid"}, + true, + &types.QueryWithdrawalRecordsResponse{}, + &types.QueryWithdrawalRecordsResponse{}, + }, + /* { + "valid", + []string{s.cfg.ChainID}, + false, + &types.QueryWithdrawalRecordsResponse{}, + &types.QueryWithdrawalRecordsResponse{}, + }, */ + } + for _, tt := range tests { + tt := tt + + s.Run(tt.name, func() { + clientCtx := val.ClientCtx + + cmd := cli.GetWithdrawalRecordsCmd() + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tt.args) + if tt.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tt.respType), out.String()) + s.Require().Equal(tt.expected, tt.respType) + } + }) + } + +} + +func (s *IntegrationTestSuite) TestGetUserWithdrawalRecords() { + val := s.network.Validators[0] + + tests := []struct { + name string + args []string + expectErr bool + respType proto.Message + expected proto.Message + }{ + { + "no args", + []string{}, + true, + &types.QueryWithdrawalRecordsResponse{}, + &types.QueryWithdrawalRecordsResponse{}, + }, + { + "empty args", + []string{""}, + true, + &types.QueryWithdrawalRecordsResponse{}, + &types.QueryWithdrawalRecordsResponse{}, + }, + { + "invalid chainID", + []string{"boguschainid"}, + true, + &types.QueryWithdrawalRecordsResponse{}, + &types.QueryWithdrawalRecordsResponse{}, + }, + // { + // "valid", + // []string{}, + // false, + // &types.QueryWithdrawalRecordsResponse{}, + // &types.QueryWithdrawalRecordsResponse{}, + // }, + } + for _, tt := range tests { + tt := tt + + s.Run(tt.name, func() { + clientCtx := val.ClientCtx + + cmd := cli.GetUserWithdrawalRecordsCmd() + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tt.args) + if tt.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tt.respType), out.String()) + s.Require().Equal(tt.expected, tt.respType) + } + }) + } +} + +func (s *IntegrationTestSuite) TestGetZoneWithdrawalRecordsCmd() { + val := s.network.Validators[0] + + tests := []struct { + name string + args []string + expectErr bool + respType proto.Message + expected proto.Message + }{ + { + "no args", + []string{}, + true, + &types.QueryWithdrawalRecordsResponse{}, + &types.QueryWithdrawalRecordsResponse{}, + }, + { + "empty args", + []string{""}, + true, + &types.QueryWithdrawalRecordsResponse{}, + &types.QueryWithdrawalRecordsResponse{}, + }, + { + "invalid chainID", + []string{"boguschainid"}, + true, + &types.QueryWithdrawalRecordsResponse{}, + &types.QueryWithdrawalRecordsResponse{}, + }, + } + for _, tt := range tests { + tt := tt + + s.Run(tt.name, func() { + clientCtx := val.ClientCtx + + runFlags := []string{ + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=true", flags.FlagDryRun), + } + + tt.args = append(tt.args, runFlags...) + + cmd := cli.GetZoneWithdrawalRecordsCmd() + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tt.args) + if tt.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tt.respType), out.String()) + s.Require().Equal(tt.expected, tt.respType) + } + }) + } +} + +func (s *IntegrationTestSuite) TestGetZoneRedelegationRecordsCmd() { + val := s.network.Validators[0] + + tests := []struct { + name string + args []string + expectErr bool + respType proto.Message + expected proto.Message + }{ + { + "no args", + []string{}, + true, + &types.QueryRedelegationRecordsResponse{}, + &types.QueryRedelegationRecordsResponse{}, + }, + { + "empty args", + []string{""}, + true, + &types.QueryRedelegationRecordsResponse{}, + &types.QueryRedelegationRecordsResponse{}, + }, + { + "invalid chainID", + []string{"boguschainid"}, + true, + &types.QueryRedelegationRecordsResponse{}, + &types.QueryRedelegationRecordsResponse{}, + }, + { + "valid", + []string{s.cfg.ChainID}, + false, + &types.QueryRedelegationRecordsResponse{}, + &types.QueryRedelegationRecordsResponse{}, + }, + } + for _, tt := range tests { + tt := tt + + s.Run(tt.name, func() { + clientCtx := val.ClientCtx + + runFlags := []string{ + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + } + tt.args = append(tt.args, runFlags...) + + cmd := cli.GetZoneRedelegationRecordsCmd() + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tt.args) + if tt.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tt.respType), out.String()) + s.Require().Equal(tt.expected, tt.respType) + } + }) + } +} + +func (s *IntegrationTestSuite) TestGetZoneValidatorsCmd() { + val := s.network.Validators[0] + + tests := []struct { + name string + args []string + expectErr bool + respType proto.Message + expected proto.Message + }{ + { + "no args", + []string{}, + true, + &types.QueryZoneValidatorsResponse{}, + &types.QueryZoneValidatorsResponse{}, + }, + { + "empty args", + []string{""}, + true, + &types.QueryZoneValidatorsResponse{}, + &types.QueryZoneValidatorsResponse{}, + }, + { + "invalid chainID", + []string{"boguschainid"}, + false, + &types.QueryZoneValidatorsResponse{}, + &types.QueryZoneValidatorsResponse{ + Validators: []types.Validator{}, + Pagination: &query.PageResponse{ + Total: 0, + }, + }, + }, + // Not work, need to fix + { + "valid", + []string{s.zones[0].ChainId}, + false, + &types.QueryZoneValidatorsResponse{}, + &types.QueryZoneValidatorsResponse{ + // Convert from []*types.Validator to []types.Validator + Validators: func() []types.Validator { + var validators []types.Validator + for _, val := range s.zones[0].Validators { + validators = append(validators, *val) + } + return validators + }(), + Pagination: &query.PageResponse{ + Total: 5, + }, + }, + }, + } + for _, tt := range tests { + tt := tt + + s.Run(tt.name, func() { + clientCtx := val.ClientCtx + + runFlags := []string{ + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + } + tt.args = append(tt.args, runFlags...) + + cmd := cli.GetZoneValidatorsCmd() + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tt.args) + if tt.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tt.respType), out.String()) + s.Require().Equal(tt.expected, tt.respType) + } + }) + } +} + +func (s *IntegrationTestSuite) TestGetTxStatusCmd() { + val := s.network.Validators[0] + + tests := []struct { + name string + args []string + expectErr bool + respType proto.Message + }{ + { + "no args", + []string{}, + true, + &sdk.TxResponse{}, + }, + { + "empty args", + []string{""}, + true, + &sdk.TxResponse{}, + }, + { + "only one arg", + []string{"boguschainid"}, + true, + &sdk.TxResponse{}, + }, + // TODO: Add a test for a valid tx hash + // { + // "valid", + // []string{"chainid", "0"}, + // false, + // &sdk.TxResponse{}, + // }, + } + for _, tt := range tests { + tt := tt + + s.Run(tt.name, func() { + clientCtx := val.ClientCtx + + runFlags := []string{ + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + } + tt.args = append(tt.args, runFlags...) + + cmd := cli.GetTxStatusCmd() + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tt.args) + if tt.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tt.respType), out.String()) + } + }) + } +} + +func (s *IntegrationTestSuite) TestGetReceiptsCmd() { + val := s.network.Validators[0] + + tests := []struct { + name string + args []string + expectErr bool + respType proto.Message + expectedLen int + }{ + { + "no args", + []string{}, + true, + &types.QueryReceiptsResponse{}, + 0, + }, + { + "empty args", + []string{""}, + true, + &types.QueryReceiptsResponse{}, + 0, + }, + { + "invalid chainID", + []string{"boguschainid"}, + true, + &types.QueryReceiptsResponse{}, + 0, + }, + { + "valid", + []string{s.zones[0].ChainId}, + false, + &types.QueryReceiptsResponse{}, + 1, + }, + } + for _, tt := range tests { + tt := tt + + s.Run(tt.name, func() { + clientCtx := val.ClientCtx + + runFlags := []string{ + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + } + tt.args = append(tt.args, runFlags...) + + cmd := cli.GetReceiptsCmd() + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tt.args) + if tt.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tt.respType), out.String()) + } + }) + } +} func TestIntegrationTestSuite(t *testing.T) { suite.Run(t, new(IntegrationTestSuite)) } diff --git a/x/interchainstaking/client/cli/query.go b/x/interchainstaking/client/cli/query.go index e7719a448..9c90ebb73 100644 --- a/x/interchainstaking/client/cli/query.go +++ b/x/interchainstaking/client/cli/query.go @@ -32,7 +32,7 @@ func GetQueryCmd() *cobra.Command { GetMappedAccountsCmd(), GetWithdrawalRecordsCmd(), GetUserWithdrawalRecordsCmd(), - GetZoneWithdrawalRecords(), + GetZoneWithdrawalRecordsCmd(), GetUnbondingRecordsCmd(), GetReceiptsCmd(), GetTxStatusCmd(), @@ -260,7 +260,7 @@ func GetUserWithdrawalRecordsCmd() *cobra.Command { return cmd } -func GetZoneWithdrawalRecords() *cobra.Command { +func GetZoneWithdrawalRecordsCmd() *cobra.Command { cmd := &cobra.Command{ Use: "zone-withdrawal-records [chain-id]", Short: "Query withdrawal records for a given zone.", @@ -336,8 +336,8 @@ func GetReceiptsCmd() *cobra.Command { fmt.Sprintf(`$ %s query interchainstaking receipts`, version.AppName, )), - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, _ []string) error { + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { return err @@ -348,8 +348,9 @@ func GetReceiptsCmd() *cobra.Command { if err != nil { return err } - + chainID := args[0] req := &types.QueryReceiptsRequest{ + ChainId: chainID, Pagination: pageReq, } @@ -437,18 +438,24 @@ func GetZoneValidatorsCmd() *cobra.Command { Use: "zone-validators", Short: "Query validators for a given zone.", Example: strings.TrimSpace( - fmt.Sprintf(`$ %s query interchainstaking zone-validators`, + fmt.Sprintf(`$ %s query interchainstaking zone-validators [zone-id]`, version.AppName, )), - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, _ []string) error { + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { return err } queryClient := types.NewQueryClient(clientCtx) - req := &types.QueryZoneValidatorsRequest{} + chainID := args[0] + if chainID == "" { + return fmt.Errorf("chain-id cannot be empty") + } + req := &types.QueryZoneValidatorsRequest{ + ChainId: chainID, + } res, err := queryClient.ZoneValidators(cmd.Context(), req) if err != nil { From a6d349082f95616fd67c0e5fe8b79b53b23626fd Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Fri, 8 Mar 2024 16:15:41 +0700 Subject: [PATCH 07/14] Add some notes --- x/interchainstaking/client/cli/cli_test.go | 41 +++++++++++----------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/x/interchainstaking/client/cli/cli_test.go b/x/interchainstaking/client/cli/cli_test.go index e687f4852..7061f3979 100644 --- a/x/interchainstaking/client/cli/cli_test.go +++ b/x/interchainstaking/client/cli/cli_test.go @@ -68,6 +68,7 @@ func (s *IntegrationTestSuite) SetupSuite() { Is_118: true, } + // TODO: I think setting validators here isn't enough, we need to set them in the store by using the keeper zone.Validators = append(zone.Validators, &types.Validator{ValoperAddress: "cosmosvaloper1sjllsnramtg3ewxqwwrwjxfgc4n4ef9u2lcnj0", CommissionRate: sdk.MustNewDecFromStr("0.2"), VotingPower: sdk.NewInt(2000), DelegatorShares: sdk.NewDec(2000), Score: sdk.ZeroDec(), ValidatorBondShares: sdk.ZeroDec(), LiquidShares: sdk.ZeroDec()}, &types.Validator{ValoperAddress: "cosmosvaloper156gqf9837u7d4c4678yt3rl4ls9c5vuursrrzf", CommissionRate: sdk.MustNewDecFromStr("0.2"), VotingPower: sdk.NewInt(2000), DelegatorShares: sdk.NewDec(2000), Score: sdk.ZeroDec(), ValidatorBondShares: sdk.ZeroDec(), LiquidShares: sdk.ZeroDec()}, @@ -700,26 +701,26 @@ func (s *IntegrationTestSuite) TestGetZoneValidatorsCmd() { }, }, }, - // Not work, need to fix - { - "valid", - []string{s.zones[0].ChainId}, - false, - &types.QueryZoneValidatorsResponse{}, - &types.QueryZoneValidatorsResponse{ - // Convert from []*types.Validator to []types.Validator - Validators: func() []types.Validator { - var validators []types.Validator - for _, val := range s.zones[0].Validators { - validators = append(validators, *val) - } - return validators - }(), - Pagination: &query.PageResponse{ - Total: 5, - }, - }, - }, + // Not work because of the validator is not set in the store(SetValidatorForZone) + // { + // "valid", + // []string{s.zones[0].ChainId}, + // false, + // &types.QueryZoneValidatorsResponse{}, + // &types.QueryZoneValidatorsResponse{ + // // Convert from []*types.Validator to []types.Validator + // Validators: func() []types.Validator { + // var validators []types.Validator + // for _, val := range s.zones[0].Validators { + // validators = append(validators, *val) + // } + // return validators + // }(), + // Pagination: &query.PageResponse{ + // Total: 5, + // }, + // }, + // }, } for _, tt := range tests { tt := tt From e6ce40bc4e451922171aba3113cfd9dc79b3c5d8 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Fri, 8 Mar 2024 16:16:42 +0700 Subject: [PATCH 08/14] linting --- x/interchainstaking/client/cli/cli_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/interchainstaking/client/cli/cli_test.go b/x/interchainstaking/client/cli/cli_test.go index 7061f3979..06de86f47 100644 --- a/x/interchainstaking/client/cli/cli_test.go +++ b/x/interchainstaking/client/cli/cli_test.go @@ -479,7 +479,6 @@ func (s *IntegrationTestSuite) TestGetWithdrawalRecordsCmd() { } }) } - } func (s *IntegrationTestSuite) TestGetUserWithdrawalRecords() { @@ -865,6 +864,7 @@ func (s *IntegrationTestSuite) TestGetReceiptsCmd() { }) } } + func TestIntegrationTestSuite(t *testing.T) { suite.Run(t, new(IntegrationTestSuite)) } From 730daf7b3639886b14afc178b6f718b9848a75d9 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Fri, 8 Mar 2024 22:13:36 +0700 Subject: [PATCH 09/14] refactor tests --- x/interchainstaking/client/cli/cli_test.go | 89 +++++++++++++--------- x/interchainstaking/client/cli/query.go | 1 - 2 files changed, 55 insertions(+), 35 deletions(-) diff --git a/x/interchainstaking/client/cli/cli_test.go b/x/interchainstaking/client/cli/cli_test.go index 06de86f47..cba29e959 100644 --- a/x/interchainstaking/client/cli/cli_test.go +++ b/x/interchainstaking/client/cli/cli_test.go @@ -433,33 +433,21 @@ func (s *IntegrationTestSuite) TestGetWithdrawalRecordsCmd() { expected proto.Message }{ { - "no args", + "valid", []string{}, - true, - &types.QueryWithdrawalRecordsResponse{}, - &types.QueryWithdrawalRecordsResponse{}, - }, - { - "empty args", - []string{""}, - true, - &types.QueryWithdrawalRecordsResponse{}, + false, &types.QueryWithdrawalRecordsResponse{}, + &types.QueryWithdrawalRecordsResponse{ + Withdrawals: []types.WithdrawalRecord{}, + }, }, { - "invalid chainID", - []string{"boguschainid"}, + "invalid", + []string{"bogus"}, true, &types.QueryWithdrawalRecordsResponse{}, &types.QueryWithdrawalRecordsResponse{}, }, - /* { - "valid", - []string{s.cfg.ChainID}, - false, - &types.QueryWithdrawalRecordsResponse{}, - &types.QueryWithdrawalRecordsResponse{}, - }, */ } for _, tt := range tests { tt := tt @@ -467,6 +455,10 @@ func (s *IntegrationTestSuite) TestGetWithdrawalRecordsCmd() { s.Run(tt.name, func() { clientCtx := val.ClientCtx + runFlags := []string{ + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + } + tt.args = append(tt.args, runFlags...) cmd := cli.GetWithdrawalRecordsCmd() out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tt.args) @@ -512,13 +504,17 @@ func (s *IntegrationTestSuite) TestGetUserWithdrawalRecords() { &types.QueryWithdrawalRecordsResponse{}, &types.QueryWithdrawalRecordsResponse{}, }, - // { - // "valid", - // []string{}, - // false, - // &types.QueryWithdrawalRecordsResponse{}, - // &types.QueryWithdrawalRecordsResponse{}, - // }, + { + "valid", + []string{ + "cosmos1r2dthxctqzhwg299e7aaeqwfkgcc9hg8n9scjg", + }, + false, + &types.QueryWithdrawalRecordsResponse{}, + &types.QueryWithdrawalRecordsResponse{ + Withdrawals: []types.WithdrawalRecord{}, + }, + }, } for _, tt := range tests { tt := tt @@ -526,6 +522,10 @@ func (s *IntegrationTestSuite) TestGetUserWithdrawalRecords() { s.Run(tt.name, func() { clientCtx := val.ClientCtx + runFlags := []string{ + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + } + tt.args = append(tt.args, runFlags...) cmd := cli.GetUserWithdrawalRecordsCmd() out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tt.args) @@ -620,23 +620,44 @@ func (s *IntegrationTestSuite) TestGetZoneRedelegationRecordsCmd() { { "empty args", []string{""}, - true, - &types.QueryRedelegationRecordsResponse{}, - &types.QueryRedelegationRecordsResponse{}, + false, + &types.QueryRedelegationRecordsResponse{ + Pagination: &query.PageResponse{}, + }, + &types.QueryRedelegationRecordsResponse{ + Redelegations: []types.RedelegationRecord{}, + Pagination: &query.PageResponse{ + Total: 0, + }, + }, }, { "invalid chainID", []string{"boguschainid"}, - true, - &types.QueryRedelegationRecordsResponse{}, - &types.QueryRedelegationRecordsResponse{}, + false, + &types.QueryRedelegationRecordsResponse{ + Pagination: &query.PageResponse{}, + }, + &types.QueryRedelegationRecordsResponse{ + Redelegations: []types.RedelegationRecord{}, + Pagination: &query.PageResponse{ + Total: 0, + }, + }, }, { "valid", []string{s.cfg.ChainID}, false, - &types.QueryRedelegationRecordsResponse{}, - &types.QueryRedelegationRecordsResponse{}, + &types.QueryRedelegationRecordsResponse{ + Pagination: &query.PageResponse{}, + }, + &types.QueryRedelegationRecordsResponse{ + Redelegations: []types.RedelegationRecord{}, + Pagination: &query.PageResponse{ + Total: 0, + }, + }, }, } for _, tt := range tests { diff --git a/x/interchainstaking/client/cli/query.go b/x/interchainstaking/client/cli/query.go index 9c90ebb73..b6cf62838 100644 --- a/x/interchainstaking/client/cli/query.go +++ b/x/interchainstaking/client/cli/query.go @@ -419,7 +419,6 @@ func GetZoneRedelegationRecordsCmd() *cobra.Command { ChainId: chainID, } - // TODO: refactor this. Should be RedelegationRecords res, err := queryClient.RedelegationRecords(cmd.Context(), req) if err != nil { return err From 73734324cb2ebe335be09686676b72487acc64f3 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Fri, 8 Mar 2024 23:15:14 +0700 Subject: [PATCH 10/14] add test for get unbonding --- x/interchainstaking/client/cli/cli_test.go | 45 ++++++++++++++++++++++ x/interchainstaking/client/cli/query.go | 6 ++- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/x/interchainstaking/client/cli/cli_test.go b/x/interchainstaking/client/cli/cli_test.go index cba29e959..dce4edbc5 100644 --- a/x/interchainstaking/client/cli/cli_test.go +++ b/x/interchainstaking/client/cli/cli_test.go @@ -886,6 +886,51 @@ func (s *IntegrationTestSuite) TestGetReceiptsCmd() { } } +func (s *IntegrationTestSuite) TestGetUnbondingRecordsCmd() { + val := s.network.Validators[0] + + tests := []struct { + name string + args []string + expectErr bool + respType proto.Message + }{ + { + "no args", + []string{}, + true, + &types.QueryUnbondingRecordsResponse{}, + }, + { + "valid", + []string{s.zones[0].ChainId}, + false, + &types.QueryUnbondingRecordsResponse{}, + }, + } + for _, tt := range tests { + tt := tt + + s.Run(tt.name, func() { + clientCtx := val.ClientCtx + + runFlags := []string{ + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + } + tt.args = append(tt.args, runFlags...) + + cmd := cli.GetUnbondingRecordsCmd() + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tt.args) + if tt.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tt.respType), out.String()) + } + }) + } +} + func TestIntegrationTestSuite(t *testing.T) { suite.Run(t, new(IntegrationTestSuite)) } diff --git a/x/interchainstaking/client/cli/query.go b/x/interchainstaking/client/cli/query.go index b6cf62838..52586038e 100644 --- a/x/interchainstaking/client/cli/query.go +++ b/x/interchainstaking/client/cli/query.go @@ -299,20 +299,22 @@ func GetUnbondingRecordsCmd() *cobra.Command { fmt.Sprintf(`$ %s query interchainstaking unbonding-records`, version.AppName, )), - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, _ []string) error { + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { return err } queryClient := types.NewQueryClient(clientCtx) + chainID := args[0] pageReq, err := client.ReadPageRequest(cmd.Flags()) if err != nil { return err } req := &types.QueryUnbondingRecordsRequest{ + ChainId: chainID, Pagination: pageReq, } From e2f56f2e6772d497da4419add6548a5361133eec Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Sat, 9 Mar 2024 00:33:48 +0700 Subject: [PATCH 11/14] add test for get zone --- x/interchainstaking/client/cli/cli_test.go | 61 ++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/x/interchainstaking/client/cli/cli_test.go b/x/interchainstaking/client/cli/cli_test.go index dce4edbc5..c4c4e702b 100644 --- a/x/interchainstaking/client/cli/cli_test.go +++ b/x/interchainstaking/client/cli/cli_test.go @@ -931,6 +931,67 @@ func (s *IntegrationTestSuite) TestGetUnbondingRecordsCmd() { } } +func (s *IntegrationTestSuite) TestGetZoneCmd() { + val := s.network.Validators[0] + + tests := []struct { + name string + args []string + expectErr bool + respType proto.Message + }{ + { + "no args", + []string{}, + true, + &types.QueryZoneResponse{}, + }, + { + "empty args", + []string{""}, + true, + &types.QueryZoneResponse{}, + }, + { + "invalid chainID", + []string{"boguschainid"}, + true, + &types.QueryZoneResponse{}, + }, + { + "valid", + []string{s.zones[0].ChainId}, + false, + &types.QueryZoneResponse{ + Zone: s.zones[0], + Stats: &types.Statistics{}, + }, + }, + } + for _, tt := range tests { + tt := tt + + s.Run(tt.name, func() { + clientCtx := val.ClientCtx + + runFlags := []string{ + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + } + tt.args = append(tt.args, runFlags...) + + cmd := cli.GetZoneCmd() + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tt.args) + if tt.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tt.respType), out.String()) + + } + }) + } +} + func TestIntegrationTestSuite(t *testing.T) { suite.Run(t, new(IntegrationTestSuite)) } From 6a201f58d432724ce9101384545ab2c913fe4ed4 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Sat, 16 Mar 2024 21:30:58 +0700 Subject: [PATCH 12/14] add UserZoneWithdrawalRecords and test --- x/interchainstaking/keeper/grpc_query.go | 24 ++++ x/interchainstaking/keeper/grpc_query_test.go | 127 ++++++++++++++++++ 2 files changed, 151 insertions(+) diff --git a/x/interchainstaking/keeper/grpc_query.go b/x/interchainstaking/keeper/grpc_query.go index b96dcf78e..3df764ac7 100644 --- a/x/interchainstaking/keeper/grpc_query.go +++ b/x/interchainstaking/keeper/grpc_query.go @@ -267,6 +267,30 @@ func (k *Keeper) WithdrawalRecords(c context.Context, req *types.QueryWithdrawal return &types.QueryWithdrawalRecordsResponse{Withdrawals: withdrawalrecords}, nil } +func (k *Keeper) UserZoneWithdrawalRecords(c context.Context, req *types.QueryWithdrawalRecordsRequest) (*types.QueryWithdrawalRecordsResponse, error) { + // TODO: implement pagination + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c) + + zone, found := k.GetZone(ctx, req.GetChainId()) + if !found { + return nil, status.Error(codes.NotFound, fmt.Sprintf("no zone found matching %s", req.GetChainId())) + } + + withdrawalrecords := make([]types.WithdrawalRecord, 0) + k.IterateZoneWithdrawalRecords(ctx, zone.ChainId, func(index int64, record types.WithdrawalRecord) (stop bool) { + if record.Delegator == req.DelegatorAddress { + withdrawalrecords = append(withdrawalrecords, record) + } + return false + }) + + return &types.QueryWithdrawalRecordsResponse{Withdrawals: withdrawalrecords}, nil +} + func (k *Keeper) UserWithdrawalRecords(c context.Context, req *types.QueryUserWithdrawalRecordsRequest) (*types.QueryWithdrawalRecordsResponse, error) { // TODO: implement pagination if req == nil { diff --git a/x/interchainstaking/keeper/grpc_query_test.go b/x/interchainstaking/keeper/grpc_query_test.go index c7ce5e104..53bed3e7a 100644 --- a/x/interchainstaking/keeper/grpc_query_test.go +++ b/x/interchainstaking/keeper/grpc_query_test.go @@ -1346,3 +1346,130 @@ func (suite *KeeperTestSuite) TestKeeper_Zone() { }) } } + +func (suite *KeeperTestSuite) TestKeeper_UserZoneWithdrawalRecords() { + icsKeeper := suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper + ctx := suite.chainA.GetContext() + + tests := []struct { + name string + malleate func() + req *types.QueryWithdrawalRecordsRequest + wantErr bool + expectLength int + }{ + { + "UserZoneWithdrawalRecords_Nil_Request", + func() {}, + nil, + true, + 0, + }, + { + "UserZoneWithdrawalRecords_Invalid_Address", + func() { + // setup zones + suite.setupTestZones() + }, + &types.QueryWithdrawalRecordsRequest{ + ChainId: "boguschain", + DelegatorAddress: "incorrect address", + }, + true, + 0, + }, + { + "UserZoneWithdrawalRecords_No_Withdrawal_Records", + func() { + zone, found := icsKeeper.GetZone(ctx, suite.chainB.ChainID) + tempAddr := addressutils.GenerateAccAddressForTest().String() + suite.True(found) + + distributions := []*types.Distribution{ + { + Valoper: icsKeeper.GetValidators(ctx, suite.chainB.ChainID)[0].ValoperAddress, + Amount: 10000000, + }, + { + Valoper: icsKeeper.GetValidators(ctx, suite.chainB.ChainID)[1].ValoperAddress, + Amount: 20000000, + }, + } + + // set records + icsKeeper.AddWithdrawalRecord( + ctx, + zone.ChainId, + delegatorAddress, + distributions, + tempAddr, + sdk.NewCoin(zone.LocalDenom, math.NewInt(15000000)), + "ABC012", + types.WithdrawStatusQueued, + time.Time{}, + icsKeeper.EpochsKeeper.GetEpochInfo(ctx, epochstypes.EpochIdentifierEpoch).CurrentEpoch, + ) + }, + &types.QueryWithdrawalRecordsRequest{ + ChainId: suite.chainB.ChainID, + DelegatorAddress: testAddress, + }, + false, + 0, + }, + { + "UserZoneWithdrawalRecords_Valid_Records", + func() { + zone, found := icsKeeper.GetZone(ctx, suite.chainB.ChainID) + suite.True(found) + + distributions := []*types.Distribution{ + { + Valoper: icsKeeper.GetValidators(ctx, suite.chainB.ChainID)[0].ValoperAddress, + Amount: 10000000, + }, + { + Valoper: icsKeeper.GetValidators(ctx, suite.chainB.ChainID)[1].ValoperAddress, + Amount: 20000000, + }, + } + + // set records + icsKeeper.AddWithdrawalRecord( + ctx, + zone.ChainId, + delegatorAddress, + distributions, + testAddress, + sdk.NewCoin(zone.LocalDenom, math.NewInt(15000000)), + "ABC012", + types.WithdrawStatusQueued, + time.Time{}, + icsKeeper.EpochsKeeper.GetEpochInfo(ctx, epochstypes.EpochIdentifierEpoch).CurrentEpoch, + ) + }, + &types.QueryWithdrawalRecordsRequest{ + ChainId: suite.chainB.ChainID, + DelegatorAddress: testAddress, + }, + false, + 1, + }, + } + for _, tc := range tests { + suite.Run(tc.name, func() { + tc.malleate() + icsKeeper := suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper + ctx := suite.chainA.GetContext() + + resp, err := icsKeeper.UserZoneWithdrawalRecords(ctx, tc.req) + if tc.wantErr { + suite.T().Logf("Error:\n%v\n", err) + suite.Error(err) + } else { + suite.NoError(err) + suite.NotNil(resp) + } + }) + } +} From adee5604b443d5ebba87f36542b49e2005ffe0e2 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Sun, 17 Mar 2024 22:11:13 +0700 Subject: [PATCH 13/14] remove TODO --- x/interchainstaking/keeper/grpc_query.go | 1 - 1 file changed, 1 deletion(-) diff --git a/x/interchainstaking/keeper/grpc_query.go b/x/interchainstaking/keeper/grpc_query.go index 3df764ac7..12ebb2346 100644 --- a/x/interchainstaking/keeper/grpc_query.go +++ b/x/interchainstaking/keeper/grpc_query.go @@ -321,7 +321,6 @@ func (k *Keeper) UnbondingRecords(c context.Context, req *types.QueryUnbondingRe return &types.QueryUnbondingRecordsResponse{Unbondings: unbondings}, nil } -// TODO: refactor this. Should be ZoneRedelegationRecords since it's only for a specific zone func (k *Keeper) RedelegationRecords(c context.Context, req *types.QueryRedelegationRecordsRequest) (*types.QueryRedelegationRecordsResponse, error) { // TODO: implement pagination if req == nil { From f1b7c1134770838be4d7d88b13246a0861374560 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Tue, 26 Mar 2024 15:23:20 +0700 Subject: [PATCH 14/14] test(ics): add valid test case for query delegator intent integration test --- x/interchainstaking/client/cli/cli_test.go | 50 ++++++++++++++++--- x/interchainstaking/keeper/grpc_query_test.go | 8 +-- .../keeper/ibc_packet_handlers.go | 2 +- 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/x/interchainstaking/client/cli/cli_test.go b/x/interchainstaking/client/cli/cli_test.go index c4c4e702b..d151caa8c 100644 --- a/x/interchainstaking/client/cli/cli_test.go +++ b/x/interchainstaking/client/cli/cli_test.go @@ -19,6 +19,10 @@ import ( "github.com/quicksilver-zone/quicksilver/x/interchainstaking/types" ) +const ( + testDelegator = "cosmos1r2dthxctqzhwg299e7aaeqwfkgcc9hg8n9scjg" +) + type IntegrationTestSuite struct { suite.Suite @@ -68,7 +72,6 @@ func (s *IntegrationTestSuite) SetupSuite() { Is_118: true, } - // TODO: I think setting validators here isn't enough, we need to set them in the store by using the keeper zone.Validators = append(zone.Validators, &types.Validator{ValoperAddress: "cosmosvaloper1sjllsnramtg3ewxqwwrwjxfgc4n4ef9u2lcnj0", CommissionRate: sdk.MustNewDecFromStr("0.2"), VotingPower: sdk.NewInt(2000), DelegatorShares: sdk.NewDec(2000), Score: sdk.ZeroDec(), ValidatorBondShares: sdk.ZeroDec(), LiquidShares: sdk.ZeroDec()}, &types.Validator{ValoperAddress: "cosmosvaloper156gqf9837u7d4c4678yt3rl4ls9c5vuursrrzf", CommissionRate: sdk.MustNewDecFromStr("0.2"), VotingPower: sdk.NewInt(2000), DelegatorShares: sdk.NewDec(2000), Score: sdk.ZeroDec(), ValidatorBondShares: sdk.ZeroDec(), LiquidShares: sdk.ZeroDec()}, @@ -77,9 +80,30 @@ func (s *IntegrationTestSuite) SetupSuite() { &types.Validator{ValoperAddress: "cosmosvaloper1z8zjv3lntpwxua0rtpvgrcwl0nm0tltgpgs6l7", CommissionRate: sdk.MustNewDecFromStr("0.2"), VotingPower: sdk.NewInt(2000), DelegatorShares: sdk.NewDec(2000), Score: sdk.ZeroDec(), ValidatorBondShares: sdk.ZeroDec(), LiquidShares: sdk.ZeroDec()}, ) + delegationIntents := []types.DelegatorIntentsForZone{ + { + ChainId: zone.ChainId, + DelegationIntent: []*types.DelegatorIntent{ + { + Delegator: testDelegator, + Intents: types.ValidatorIntents{ + { + ValoperAddress: zone.Validators[0].ValoperAddress, + Weight: sdk.NewDec(1), + }, + { + ValoperAddress: zone.Validators[1].ValoperAddress, + Weight: sdk.NewDec(1), + }, + }, + }, + }, + }, + } // setup basic genesis state newGenesis := types.DefaultGenesis() newGenesis.Zones = []types.Zone{zone} + newGenesis.DelegatorIntents = delegationIntents updateGenesisConfigState(types.ModuleName, newGenesis) s.zones = []types.Zone{zone} @@ -175,7 +199,6 @@ func (s *IntegrationTestSuite) ZonesEqual(zoneA, zoneB types.Zone) bool { func (s *IntegrationTestSuite) TestGetDelegatorIntentCmd() { val := s.network.Validators[0] - tests := []struct { name string args []string @@ -204,20 +227,33 @@ func (s *IntegrationTestSuite) TestGetDelegatorIntentCmd() { &types.QueryDelegatorIntentResponse{}, &types.QueryDelegatorIntentResponse{}, }, - /* { + { "valid", - []string{s.cfg.ChainID, ""}, + []string{s.zones[0].ChainId, testDelegator}, false, &types.QueryDelegatorIntentResponse{}, - &types.QueryDelegatorIntentResponse{}, - }, */ + &types.QueryDelegatorIntentResponse{ + Intent: &types.DelegatorIntent{ + Delegator: testDelegator, + Intents: types.ValidatorIntents{ + { + ValoperAddress: s.zones[0].Validators[0].ValoperAddress, + Weight: sdk.NewDec(1), + }, + { + ValoperAddress: s.zones[0].Validators[1].ValoperAddress, + Weight: sdk.NewDec(1), + }, + }, + }, + }, + }, } for _, tt := range tests { tt := tt s.Run(tt.name, func() { clientCtx := val.ClientCtx - runFlags := []string{ fmt.Sprintf("--%s=json", tmcli.OutputFlag), } diff --git a/x/interchainstaking/keeper/grpc_query_test.go b/x/interchainstaking/keeper/grpc_query_test.go index caf0549f9..e20ed6bad 100644 --- a/x/interchainstaking/keeper/grpc_query_test.go +++ b/x/interchainstaking/keeper/grpc_query_test.go @@ -1453,11 +1453,11 @@ func (suite *KeeperTestSuite) TestKeeper_UserZoneWithdrawalRecords() { distributions := []*types.Distribution{ { Valoper: icsKeeper.GetValidators(ctx, suite.chainB.ChainID)[0].ValoperAddress, - Amount: 10000000, + Amount: sdk.NewInt(10000000), }, { Valoper: icsKeeper.GetValidators(ctx, suite.chainB.ChainID)[1].ValoperAddress, - Amount: 20000000, + Amount: sdk.NewInt(20000000), }, } @@ -1491,11 +1491,11 @@ func (suite *KeeperTestSuite) TestKeeper_UserZoneWithdrawalRecords() { distributions := []*types.Distribution{ { Valoper: icsKeeper.GetValidators(ctx, suite.chainB.ChainID)[0].ValoperAddress, - Amount: 10000000, + Amount: sdk.NewInt(10000000), }, { Valoper: icsKeeper.GetValidators(ctx, suite.chainB.ChainID)[1].ValoperAddress, - Amount: 20000000, + Amount: sdk.NewInt(20000000), }, } diff --git a/x/interchainstaking/keeper/ibc_packet_handlers.go b/x/interchainstaking/keeper/ibc_packet_handlers.go index e34d1ab35..ba254401c 100644 --- a/x/interchainstaking/keeper/ibc_packet_handlers.go +++ b/x/interchainstaking/keeper/ibc_packet_handlers.go @@ -1450,7 +1450,7 @@ func isNumericString(in string) bool { // and to parse numeric values, say in the smallest unit of uqck // MaxInt64: (1<<63)-1 = 9_223_372_036_854_775_807 uqck aka // 9_223_372_036_854.775 (9.223 Trillion) qck - // so the function is appropriate as its range won't be exceeded. + // so the function is appropriate as its range won't be exceeded. _, err := strconv.ParseInt(in, 10, 64) return err == nil }