diff --git a/x/stakeibc/keeper/unbonding_records.go b/x/stakeibc/keeper/unbonding_records.go index d5b830612a..676f5fae77 100644 --- a/x/stakeibc/keeper/unbonding_records.go +++ b/x/stakeibc/keeper/unbonding_records.go @@ -267,7 +267,16 @@ func (k Keeper) UnbondFromHostZone(ctx sdk.Context, hostZone types.HostZone) err // Determine the ideal balanced delegation for each validator after the unbonding // (as if we were to unbond and then rebalance) // This will serve as the starting point for determining how much to unbond each validator - delegationAfterUnbonding := hostZone.TotalDelegations.Sub(totalUnbondAmount) + // first, get the total delegations _excluding_ validators with slash_query_in_progress + totalValidDelegationBeforeUnbonding := sdkmath.ZeroInt() + for _, validator := range hostZone.Validators { + if !validator.SlashQueryInProgress { + totalValidDelegationBeforeUnbonding = totalValidDelegationBeforeUnbonding.Add(validator.Delegation) + } + } + // then subtract out the amount to unbond + delegationAfterUnbonding := totalValidDelegationBeforeUnbonding.Sub(totalUnbondAmount) + balancedDelegationsAfterUnbonding, err := k.GetTargetValAmtsForHostZone(ctx, hostZone, delegationAfterUnbonding) if err != nil { return errorsmod.Wrapf(err, "unable to get target val amounts for host zone %s", hostZone.ChainId) diff --git a/x/stakeibc/keeper/unbonding_records_get_host_zone_unbondings_msgs_test.go b/x/stakeibc/keeper/unbonding_records_get_host_zone_unbondings_msgs_test.go index ba687aaa0c..4148b1ada8 100644 --- a/x/stakeibc/keeper/unbonding_records_get_host_zone_unbondings_msgs_test.go +++ b/x/stakeibc/keeper/unbonding_records_get_host_zone_unbondings_msgs_test.go @@ -201,6 +201,44 @@ func (s *KeeperTestSuite) TestUnbondFromHostZone_Successful_UnbondOnlyZeroWeight s.CheckUnbondingMessages(tc, expectedUnbondings) } +func (s *KeeperTestSuite) TestUnbondFromHostZone_Successful_UnbondIgnoresSlashQueryInProgress() { + // Native Stake: 100 + // LSM Stake: 0 + // Total Stake: 100 + // + // Slash Query In Progress Stake: 25 + // Eligible Stake: 75 + // + // Unbond Amount: 20 + // Stake After Unbond: 80 + // Eligible Stake After Unbond 45 + totalUnbondAmount := sdkmath.NewInt(20) + totalStake := sdkmath.NewInt(100) + totalWeight := int64(100) + + validators := []*types.Validator{ + // Current: 25, Weight: 15%, Balanced: (15/75) * 55= 11, Capacity: 25-11 = 14 > 0 + {Address: "valA", Weight: 15, Delegation: sdkmath.NewInt(25)}, + // Current: 25, Weight: 20%, Balanced: (20/75) * 55 = 14.66, Capacity: 25-14.66 = 10.44 > 0 + {Address: "valB", Weight: 20, Delegation: sdkmath.NewInt(25)}, + // Current: 25, Weight: 40%, Balanced: (40/75) * 55 = 29.33, Capacity: 25-29.33 < 0 + {Address: "valC", Weight: 40, Delegation: sdkmath.NewInt(25)}, + // Current: 25, Weight: 25%, Slash-Query-In-Progress so ignored + {Address: "valD", Weight: 25, Delegation: sdkmath.NewInt(25), SlashQueryInProgress: true}, + } + + expectedUnbondings := []ValidatorUnbonding{ + // valA has #1 priority - unbond up to 14 + {Validator: "valA", UnbondAmount: sdkmath.NewInt(14)}, + // 20 - 14 = 6 unbond remaining + // valB has #2 priority - unbond up to remaining + {Validator: "valB", UnbondAmount: sdkmath.NewInt(6)}, + } + + tc := s.SetupTestUnbondFromHostZone(totalWeight, totalStake, totalUnbondAmount, validators) + s.CheckUnbondingMessages(tc, expectedUnbondings) +} + func (s *KeeperTestSuite) TestUnbondFromHostZone_Successful_UnbondTotalLessThanTotalLSM() { // Native Stake: 1000 // LSM Stake: 250