From bf0a429fb978c464ca588284e0b43107bda56a3d Mon Sep 17 00:00:00 2001 From: puneetmahajan Date: Wed, 29 May 2024 16:14:42 +0400 Subject: [PATCH 1/3] add validator force update. --- x/liquidstakeibc/keeper/icq.go | 29 +++++++++++++- x/liquidstakeibc/keeper/icq_queries.go | 31 +++++++++++++++ x/liquidstakeibc/keeper/icq_queries_test.go | 42 +++++++++++++++++++++ x/liquidstakeibc/keeper/msg_server.go | 10 +++++ x/liquidstakeibc/keeper/msg_server_test.go | 26 ++++++++----- x/liquidstakeibc/types/keys.go | 1 + 6 files changed, 129 insertions(+), 10 deletions(-) diff --git a/x/liquidstakeibc/keeper/icq.go b/x/liquidstakeibc/keeper/icq.go index fbabc39f0..8e6127acd 100644 --- a/x/liquidstakeibc/keeper/icq.go +++ b/x/liquidstakeibc/keeper/icq.go @@ -17,6 +17,7 @@ import ( const ( Validator = "validator" Delegation = "validator-delegation" + DelegationUpdate = "validator-delegation-update" RewardAccountBalances = "reward-balances" NonCompoundableRewardAccountBalances = "non-compoundable-reward-balances" DelegationAccountBalances = "delegation-balances" @@ -55,7 +56,8 @@ func (c Callbacks) RegisterCallbacks() icqtypes.QueryCallbacks { AddCallback(RewardAccountBalances, CallbackFn(RewardsAccountBalanceCallback)). AddCallback(NonCompoundableRewardAccountBalances, CallbackFn(NonCompoundableRewardsAccountBalanceCallback)). AddCallback(DelegationAccountBalances, CallbackFn(DelegationAccountBalanceCallback)). - AddCallback(Delegation, CallbackFn(DelegationCallback)) + AddCallback(Delegation, CallbackFn(DelegationCallback)). + AddCallback(DelegationUpdate, CallbackFn(DelegationUpdateCallback)) return a.(Callbacks) } @@ -240,3 +242,28 @@ func NonCompoundableRewardsAccountBalanceCallback(k Keeper, ctx sdk.Context, dat return nil } + +func DelegationUpdateCallback(k Keeper, ctx sdk.Context, data []byte, query icqtypes.Query) error { + hc, found := k.GetHostChain(ctx, query.ChainId) + if !found { + return fmt.Errorf("host chain with id %s is not registered", query.ChainId) + } + + delegation, err := stakingtypes.UnmarshalDelegation(k.cdc, data) + if err != nil { + return fmt.Errorf("could not unmarshall ICQ delegation response: %w", err) + } + + validator, found := hc.GetValidator(delegation.ValidatorAddress) + if !found { + return fmt.Errorf( + "validator %s for host chain %s not found", + delegation.ValidatorAddress, + query.ChainId, + ) + } + validator.DelegatedAmount = delegation.Shares.Mul(validator.ExchangeRate).TruncateInt() + + k.SetHostChainValidator(ctx, hc, validator) + return nil +} diff --git a/x/liquidstakeibc/keeper/icq_queries.go b/x/liquidstakeibc/keeper/icq_queries.go index bb4b6d6fa..d7e8862ea 100644 --- a/x/liquidstakeibc/keeper/icq_queries.go +++ b/x/liquidstakeibc/keeper/icq_queries.go @@ -66,6 +66,37 @@ func (k *Keeper) QueryValidatorDelegation( return nil } +// QueryValidatorDelegationUpdate sends an ICQ query to get a validator delegation +func (k *Keeper) QueryValidatorDelegationUpdate( + ctx sdk.Context, + hc *types.HostChain, + validator *types.Validator, +) error { + _, delegatorAddr, err := bech32.DecodeAndConvert(hc.DelegationAccount.Address) + if err != nil { + return err + } + + _, validatorAddr, err := bech32.DecodeAndConvert(validator.OperatorAddress) + if err != nil { + return err + } + + k.icqKeeper.MakeRequest( + ctx, + hc.ConnectionId, + hc.ChainId, + types.StakingStoreQuery, + stakingtypes.GetDelegationKey(delegatorAddr, validatorAddr), + sdk.NewInt(int64(-1)), + types.ModuleName, + DelegationUpdate, + 0, + ) + + return nil +} + // QueryDelegationHostChainAccountBalance sends an ICQ query to get the delegation host account balance func (k *Keeper) QueryDelegationHostChainAccountBalance( ctx sdk.Context, diff --git a/x/liquidstakeibc/keeper/icq_queries_test.go b/x/liquidstakeibc/keeper/icq_queries_test.go index 37ea19109..e14693e16 100644 --- a/x/liquidstakeibc/keeper/icq_queries_test.go +++ b/x/liquidstakeibc/keeper/icq_queries_test.go @@ -193,3 +193,45 @@ func (suite *IntegrationTestSuite) TestKeeper_QueryNonCompoundableRewardsHostCha }) } } + +func (suite *IntegrationTestSuite) TestKeeper_QueryValidatorDelegationUpdate() { + pstakeApp, ctx := suite.app, suite.ctx + k := pstakeApp.LiquidStakeIBCKeeper + hc, found := k.GetHostChain(ctx, suite.chainB.ChainID) + suite.Require().Equal(found, true) + + hc2 := types.HostChain{DelegationAccount: &types.ICAAccount{Address: "invalid"}} + + type args struct { + hc *types.HostChain + validator *types.Validator + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "Success", + args: args{ + hc: hc, + validator: hc.Validators[0], + }, + wantErr: false, + }, { + name: "Invalid delegator addr", + args: args{ + hc: &hc2, + validator: hc.Validators[0], + }, + wantErr: true, + }, + } + for _, tt := range tests { + suite.Run(tt.name, func() { + if err := k.QueryValidatorDelegationUpdate(ctx, tt.args.hc, tt.args.validator); (err != nil) != tt.wantErr { + suite.T().Errorf("QueryValidatorDelegationUpdate() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/x/liquidstakeibc/keeper/msg_server.go b/x/liquidstakeibc/keeper/msg_server.go index 459f06928..3467c5f71 100644 --- a/x/liquidstakeibc/keeper/msg_server.go +++ b/x/liquidstakeibc/keeper/msg_server.go @@ -322,6 +322,16 @@ func (k msgServer) UpdateHostChain( hc.RewardParams = ¶ms k.SetHostChain(ctx, hc) + case types.KeyForceUpdateValidator: + val, found := hc.GetValidator(update.Value) + if !found { + return nil, types.ErrValidatorNotFound + } + + if err := k.QueryValidatorDelegationUpdate(ctx, hc, val); err != nil { + return nil, fmt.Errorf("unable to send ICQ query for validator delegation update") + } + default: return nil, fmt.Errorf("invalid or unexpected update key: %s", update.Key) } diff --git a/x/liquidstakeibc/keeper/msg_server_test.go b/x/liquidstakeibc/keeper/msg_server_test.go index 18b898301..5b26838a6 100644 --- a/x/liquidstakeibc/keeper/msg_server_test.go +++ b/x/liquidstakeibc/keeper/msg_server_test.go @@ -3,11 +3,11 @@ package keeper_test import ( "context" "fmt" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "reflect" "testing" sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ibctfrtypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" @@ -166,7 +166,8 @@ func (suite *IntegrationTestSuite) Test_msgServer_LiquidStakeLSM() { }, want: &types.MsgLiquidStakeLSMResponse{}, wantErr: false, - }, { + }, + { name: "Invalid IBC denom", args: args{ goCtx: ctx, @@ -180,7 +181,8 @@ func (suite *IntegrationTestSuite) Test_msgServer_LiquidStakeLSM() { }, want: nil, wantErr: true, - }, { + }, + { name: "Invalid IBC hex hash", args: args{ goCtx: ctx, @@ -194,7 +196,8 @@ func (suite *IntegrationTestSuite) Test_msgServer_LiquidStakeLSM() { }, want: nil, wantErr: true, - }, { + }, + { name: "No IBC denom trace", args: args{ goCtx: ctx, @@ -208,7 +211,8 @@ func (suite *IntegrationTestSuite) Test_msgServer_LiquidStakeLSM() { }, want: nil, wantErr: true, - }, { + }, + { name: "Host chain not active", args: args{ goCtx: ctx, @@ -222,7 +226,8 @@ func (suite *IntegrationTestSuite) Test_msgServer_LiquidStakeLSM() { }, want: nil, wantErr: true, - }, { + }, + { name: "Host chain LSM flag not active", args: args{ goCtx: ctx, @@ -236,7 +241,8 @@ func (suite *IntegrationTestSuite) Test_msgServer_LiquidStakeLSM() { }, want: nil, wantErr: true, - }, { + }, + { name: "Not enough balance", args: args{ goCtx: ctx, @@ -250,7 +256,8 @@ func (suite *IntegrationTestSuite) Test_msgServer_LiquidStakeLSM() { }, want: nil, wantErr: true, - }, { + }, + { name: "Deposit already exists", args: args{ goCtx: ctx, @@ -264,7 +271,8 @@ func (suite *IntegrationTestSuite) Test_msgServer_LiquidStakeLSM() { }, want: nil, wantErr: true, - }, { + }, + { name: "Less than min amount", args: args{ goCtx: ctx, diff --git a/x/liquidstakeibc/types/keys.go b/x/liquidstakeibc/types/keys.go index 3af705b82..a7f730e9d 100644 --- a/x/liquidstakeibc/types/keys.go +++ b/x/liquidstakeibc/types/keys.go @@ -86,6 +86,7 @@ const ( KeyAutocompoundFactor string = "autocompound_factor" KeyFlags string = "flags" KeyRewardParams string = "reward_params" + KeyForceUpdateValidator string = "force_update_validator" ) var ( From 25795a15c043426e3e345033379a61eb7100b5a6 Mon Sep 17 00:00:00 2001 From: puneetmahajan Date: Wed, 29 May 2024 18:39:30 +0400 Subject: [PATCH 2/3] add CHANGELOG.md --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32cd90ac4..6fcc341d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,12 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## Unreleased +### Improvements + +- [831](https://github.com/persistenceOne/pstake-native/pull/831) Add amino tags for protobuf msgs for compiling in js using telescope +- [841](https://github.com/persistenceOne/pstake-native/pull/841) add type ForceUpdateValidatorDelegations to MsgUpdateHostChain + + ## [v2.13.0] - 2024-05-01 ### Bug Fixes From 405f3e61bbe8b1f73a620a9310c52a8bcc0cbe6f Mon Sep 17 00:00:00 2001 From: puneetmahajan Date: Thu, 30 May 2024 00:42:46 +0400 Subject: [PATCH 3/3] add update-validator to msg validation --- x/liquidstakeibc/keeper/icq.go | 2 +- x/liquidstakeibc/types/msgs.go | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/x/liquidstakeibc/keeper/icq.go b/x/liquidstakeibc/keeper/icq.go index 8e6127acd..5bb8759a5 100644 --- a/x/liquidstakeibc/keeper/icq.go +++ b/x/liquidstakeibc/keeper/icq.go @@ -257,7 +257,7 @@ func DelegationUpdateCallback(k Keeper, ctx sdk.Context, data []byte, query icqt validator, found := hc.GetValidator(delegation.ValidatorAddress) if !found { return fmt.Errorf( - "validator %s for host chain %s not found", + "delegation for validator %s for host chain %s not found", delegation.ValidatorAddress, query.ChainId, ) diff --git a/x/liquidstakeibc/types/msgs.go b/x/liquidstakeibc/types/msgs.go index bfeecf9f9..810ba9840 100644 --- a/x/liquidstakeibc/types/msgs.go +++ b/x/liquidstakeibc/types/msgs.go @@ -391,6 +391,11 @@ func (m *MsgUpdateHostChain) ValidateBasic() error { if err := sdk.ValidateDenom(params.Denom); err != nil { return fmt.Errorf("invalid rewards denom: %s", err.Error()) } + case KeyForceUpdateValidator: + _, _, err := bech32.DecodeAndConvert(update.Value) + if err != nil { + return err + } default: return fmt.Errorf("invalid or unexpected update key: %s", update.Key) }