Skip to content

Commit

Permalink
feat: add queries to new dbs created for redelegations (#687)
Browse files Browse the repository at this point in the history
* add queries to new dbs created for redelegations

* add CHANGELOG.md
  • Loading branch information
puneet2019 authored Dec 4, 2023
1 parent 05cf592 commit 4982e03
Show file tree
Hide file tree
Showing 9 changed files with 1,466 additions and 256 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ Ref: https://keepachangelog.com/en/1.0.0/

# Changelog

### Features

- [687](https://github.com/persistenceOne/pstake-native/pull/687) add queries for redelegations and redelegation txs.

### Bug Fixes

- [685](https://github.com/persistenceOne/pstake-native/pull/685) Fix rebalancing to happen outside of unbonding epochs
Expand Down
30 changes: 28 additions & 2 deletions proto/pstake/liquidstakeibc/v1beta1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@ service Query {
rpc ExchangeRate(QueryExchangeRateRequest) returns (QueryExchangeRateResponse) {
option (google.api.http).get = "/pstake/liquidstakeibc/v1beta1/exchange_rate/{chain_id}";
}

// Queries for a host chain redelegation entries on the host token delegation acct.
rpc Redelegations(QueryRedelegationsRequest) returns (QueryRedelegationsResponse) {
option (google.api.http).get = "/pstake/liquidstakeibc/v1beta1/redelegations/{chain_id}";
}

// Queries for a host chain redelegation-txs for the host token.
rpc RedelegationTx(QueryRedelegationTxRequest) returns (QueryRedelegationTxResponse) {
option (google.api.http).get = "/pstake/liquidstakeibc/v1beta1/redelegation_tx/{chain_id}";
}
}

message QueryParamsRequest {}
Expand All @@ -83,7 +93,7 @@ message QueryHostChainRequest {
}

message QueryHostChainResponse {
HostChain host_chain = 1 [ (gogoproto.nullable) = false ];
HostChain host_chain = 1 [(gogoproto.nullable) = false];
}

message QueryHostChainsRequest {
Expand Down Expand Up @@ -158,6 +168,22 @@ message QueryExchangeRateResponse {
string rate = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false,
(cosmos_proto.scalar) = "cosmos.Dec"
(cosmos_proto.scalar) = "cosmos.Dec"
];
}

message QueryRedelegationsRequest {
string chain_id = 1;
}

message QueryRedelegationsResponse {
liquidstakeibc.v1beta1.Redelegations redelegations = 1 ;
}

message QueryRedelegationTxRequest {
string chain_id = 1;
}

message QueryRedelegationTxResponse {
repeated liquidstakeibc.v1beta1.RedelegateTx redelegation_tx = 1 ;
}
70 changes: 70 additions & 0 deletions x/liquidstakeibc/client/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ func NewQueryCmd() *cobra.Command {
QueryDepositAccountBalanceCmd(),
QueryExchangeRateCmd(),
QueryUnbondingCmd(),
QueryRedelegationsCmd(),
QueryRedelegationTxCmd(),
)

return cmd
Expand Down Expand Up @@ -405,3 +407,71 @@ func QueryExchangeRateCmd() *cobra.Command {

return cmd
}

// QueryRedelegationsCmd returns the host chain redelegations
func QueryRedelegationsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "redelegations [chain-id]",
Short: "Query the redelegations of a host chain",
Args: cobra.ExactArgs(1),
Long: strings.TrimSpace(
fmt.Sprintf(
`Query the exchange rate of a host chain: $ %s query liquidstakeibc exchange-rate [chain-id]`,
version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}

queryClient := types.NewQueryClient(clientCtx)

res, err := queryClient.Redelegations(cmd.Context(), &types.QueryRedelegationsRequest{ChainId: args[0]})
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}

// QueryRedelegationTxCmd returns the host chain redelegation txs.
func QueryRedelegationTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "redelegation-tx [chain-id]",
Short: "Query the exchange rate of a host chain",
Args: cobra.ExactArgs(1),
Long: strings.TrimSpace(
fmt.Sprintf(
`Query the exchange rate of a host chain: $ %s query liquidstakeibc exchange-rate [chain-id]`,
version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}

queryClient := types.NewQueryClient(clientCtx)

res, err := queryClient.RedelegationTx(cmd.Context(), &types.QueryRedelegationTxRequest{ChainId: args[0]})
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}
37 changes: 37 additions & 0 deletions x/liquidstakeibc/keeper/grpc_querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,40 @@ func (k *Keeper) ExchangeRate(

return &types.QueryExchangeRateResponse{Rate: hc.CValue}, nil
}

func (k *Keeper) Redelegations(goCtx context.Context, request *types.QueryRedelegationsRequest) (*types.QueryRedelegationsResponse, error) {
if request == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if request.ChainId == "" {
return nil, status.Error(codes.InvalidArgument, "chain_id cannot be empty")
}

ctx := sdk.UnwrapSDKContext(goCtx)
hc, found := k.GetHostChain(ctx, request.ChainId)
if !found {
return nil, sdkerrors.ErrKeyNotFound
}
redels, _ := k.GetRedelegations(ctx, hc.ChainId)

return &types.QueryRedelegationsResponse{Redelegations: redels}, nil
}

func (k *Keeper) RedelegationTx(goCtx context.Context, request *types.QueryRedelegationTxRequest) (*types.QueryRedelegationTxResponse, error) {
if request == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if request.ChainId == "" {
return nil, status.Error(codes.InvalidArgument, "chain_id cannot be empty")
}

ctx := sdk.UnwrapSDKContext(goCtx)
hc, found := k.GetHostChain(ctx, request.ChainId)
if !found {
return nil, sdkerrors.ErrKeyNotFound
}
redelTxs := k.FilterRedelegationTx(ctx, func(d types.RedelegateTx) bool {
return d.ChainId == hc.ChainId
})
return &types.QueryRedelegationTxResponse{RedelegationTx: redelTxs}, nil
}
64 changes: 64 additions & 0 deletions x/liquidstakeibc/keeper/grpc_querier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -474,3 +474,67 @@ func (suite *IntegrationTestSuite) TestQueryExchangeRate() {
})
}
}

func (suite *IntegrationTestSuite) TestQueryRedelegations() {

tc := []struct {
name string
req *types.QueryRedelegationsRequest
resp *types.QueryRedelegationsResponse
err error
}{{
name: "Valid",
req: &types.QueryRedelegationsRequest{ChainId: suite.chainB.ChainID},
resp: &types.QueryRedelegationsResponse{Redelegations: nil},
err: nil,
}, {
name: "NotFound",
req: &types.QueryRedelegationsRequest{ChainId: "chain-1"},
err: sdkerrors.ErrKeyNotFound,
}, {
name: "InvalidRequest",
err: status.Error(codes.InvalidArgument, "empty request"),
}}

for _, t := range tc {
suite.Run(t.name, func() {

resp, err := suite.app.LiquidStakeIBCKeeper.Redelegations(suite.ctx, t.req)

suite.Require().Equal(err, t.err)
suite.Require().Equal(resp, t.resp)
})
}
}

func (suite *IntegrationTestSuite) TestQueryRedelegationTx() {

tc := []struct {
name string
req *types.QueryRedelegationTxRequest
resp *types.QueryRedelegationTxResponse
err error
}{{
name: "Valid",
req: &types.QueryRedelegationTxRequest{ChainId: suite.chainB.ChainID},
resp: &types.QueryRedelegationTxResponse{RedelegationTx: []*types.RedelegateTx{}},
err: nil,
}, {
name: "NotFound",
req: &types.QueryRedelegationTxRequest{ChainId: "chain-1"},
err: sdkerrors.ErrKeyNotFound,
}, {
name: "InvalidRequest",
err: status.Error(codes.InvalidArgument, "empty request"),
}}

for _, t := range tc {
suite.Run(t.name, func() {

resp, err := suite.app.LiquidStakeIBCKeeper.RedelegationTx(suite.ctx, t.req)

suite.Require().Equal(err, t.err)
suite.Require().Equal(resp, t.resp)
})
}
}
20 changes: 20 additions & 0 deletions x/liquidstakeibc/keeper/redelegation_txs.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,26 @@ func (k *Keeper) GetAllRedelegationTx(ctx sdk.Context) []*types.RedelegateTx {
return txs
}

func (k *Keeper) FilterRedelegationTx(
ctx sdk.Context,
filter func(d types.RedelegateTx) bool,
) []*types.RedelegateTx {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.RedelegationTxKey)
iterator := sdk.KVStorePrefixIterator(store, nil)
defer iterator.Close()

redelegationTxs := make([]*types.RedelegateTx, 0)
for ; iterator.Valid(); iterator.Next() {
deposit := types.RedelegateTx{}
k.cdc.MustUnmarshal(iterator.Value(), &deposit)
if filter(deposit) {
redelegationTxs = append(redelegationTxs, &deposit)
}
}

return redelegationTxs
}

func (k *Keeper) DeleteRedelegationTx(ctx sdk.Context, chainID string, ibcSequenceID string) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.RedelegationTxKey)
store.Delete(types.GetRedelegationTxStoreKey(chainID, ibcSequenceID))
Expand Down
3 changes: 3 additions & 0 deletions x/liquidstakeibc/keeper/redelegation_txs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ func (suite *IntegrationTestSuite) TestSetGetDeleteRedelegationTx() {
txs := suite.app.LiquidStakeIBCKeeper.GetAllRedelegationTx(suite.ctx)
suite.Require().Equal(len(txs), 1)

filteredTxs := suite.app.LiquidStakeIBCKeeper.FilterRedelegationTx(suite.ctx, func(redel types.RedelegateTx) bool { return true })
suite.Require().Equal(len(filteredTxs), 1)

suite.app.LiquidStakeIBCKeeper.DeleteRedelegationTx(suite.ctx, suite.chainB.ChainID, "channel-100-sequence-1")
txs2 := suite.app.LiquidStakeIBCKeeper.GetAllRedelegationTx(suite.ctx)
suite.Require().Equal(len(txs2), 0)
Expand Down
Loading

0 comments on commit 4982e03

Please sign in to comment.