From 942b19614dfe7455b5bec30ab82a39acda74868c Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Fri, 26 Sep 2025 15:32:06 +0700 Subject: [PATCH 1/4] handle zero share case --- x/multi-staking/keeper/proposal.go | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/x/multi-staking/keeper/proposal.go b/x/multi-staking/keeper/proposal.go index a2d8389..581be96 100644 --- a/x/multi-staking/keeper/proposal.go +++ b/x/multi-staking/keeper/proposal.go @@ -130,8 +130,29 @@ func (k Keeper) RemoveMultiStakingCoinProposal( if stakingLock.LockedCoin.Denom != p.Denom { return false } + // Check if lock have enough share to undelegate + unbondAmount := stakingLock.LockedCoin.BondValue() + valAcc, err := sdk.ValAddressFromBech32(stakingLock.LockID.ValAddr) + if err != nil { + return true + } + delAcc, err := sdk.AccAddressFromBech32(stakingLock.LockID.MultiStakerAddr) + if err != nil { + return true + } + unbondAmount, err = k.AdjustUnbondAmount(ctx, delAcc, valAcc, unbondAmount) + if err != nil { + return true + } + if unbondAmount.IsZero() { + // Remove multistaking-lock and burn corresponding amount + k.RemoveMultiStakingLock(ctx, stakingLock.LockID) + k.bankKeeper.BurnCoins(ctx, types.ModuleName, sdk.NewCoins(stakingLock.LockedCoin.ToCoin())) + return false + } + // Call the Keeper method directly instead of going through MsgServer - _, err := k.Undelegate(ctx, &stakingtypes.MsgUndelegate{ + _, err = k.Undelegate(ctx, &stakingtypes.MsgUndelegate{ DelegatorAddress: stakingLock.LockID.MultiStakerAddr, ValidatorAddress: stakingLock.LockID.ValAddr, Amount: stakingLock.LockedCoin.ToCoin(), From 39aa799c5a67462a3bb60827808bd43578e75b1c Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Fri, 26 Sep 2025 15:32:22 +0700 Subject: [PATCH 2/4] impove invariant --- x/multi-staking/keeper/invariants.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/multi-staking/keeper/invariants.go b/x/multi-staking/keeper/invariants.go index 8bad847..83ffda6 100644 --- a/x/multi-staking/keeper/invariants.go +++ b/x/multi-staking/keeper/invariants.go @@ -41,7 +41,7 @@ func ModuleAccountInvariants(k Keeper) sdk.Invariant { moduleAccount := authtypes.NewModuleAddress(types.ModuleName) escrowBalances := k.bankKeeper.GetAllBalances(ctx, moduleAccount) - broken := !escrowBalances.Equal(totalLockCoinAmount) + broken := !escrowBalances.IsAllGTE(totalLockCoinAmount) return sdk.FormatInvariant( types.ModuleName, From 7778c6f692ccc9aa92d9625bbf4783757ceaf3ec Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Fri, 26 Sep 2025 19:57:34 +0700 Subject: [PATCH 3/4] err check --- x/multi-staking/keeper/proposal.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/x/multi-staking/keeper/proposal.go b/x/multi-staking/keeper/proposal.go index 581be96..a358774 100644 --- a/x/multi-staking/keeper/proposal.go +++ b/x/multi-staking/keeper/proposal.go @@ -147,7 +147,11 @@ func (k Keeper) RemoveMultiStakingCoinProposal( if unbondAmount.IsZero() { // Remove multistaking-lock and burn corresponding amount k.RemoveMultiStakingLock(ctx, stakingLock.LockID) - k.bankKeeper.BurnCoins(ctx, types.ModuleName, sdk.NewCoins(stakingLock.LockedCoin.ToCoin())) + err := k.bankKeeper.BurnCoins(ctx, types.ModuleName, sdk.NewCoins(stakingLock.LockedCoin.ToCoin())) + if err != nil { + ubdErr = err + return true + } return false } From 41ba1efcbf85a60fae62e4f680d57883db4cf72a Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Fri, 26 Sep 2025 20:31:49 +0700 Subject: [PATCH 4/4] refactor loop & return err directly --- x/multi-staking/keeper/proposal.go | 35 +++++++++++++----------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/x/multi-staking/keeper/proposal.go b/x/multi-staking/keeper/proposal.go index a358774..c5ffe7c 100644 --- a/x/multi-staking/keeper/proposal.go +++ b/x/multi-staking/keeper/proposal.go @@ -125,34 +125,35 @@ func (k Keeper) RemoveMultiStakingCoinProposal( return err } - var ubdErr error + locks := []types.MultiStakingLock{} k.MultiStakingLockIterator(ctx, func(stakingLock types.MultiStakingLock) bool { - if stakingLock.LockedCoin.Denom != p.Denom { - return false + if stakingLock.LockedCoin.Denom == p.Denom { + locks = append(locks, stakingLock) } - // Check if lock have enough share to undelegate + return false + }) + + for _, stakingLock := range locks { unbondAmount := stakingLock.LockedCoin.BondValue() valAcc, err := sdk.ValAddressFromBech32(stakingLock.LockID.ValAddr) if err != nil { - return true + return err } delAcc, err := sdk.AccAddressFromBech32(stakingLock.LockID.MultiStakerAddr) if err != nil { - return true + return err } unbondAmount, err = k.AdjustUnbondAmount(ctx, delAcc, valAcc, unbondAmount) - if err != nil { - return true - } - if unbondAmount.IsZero() { + // Incase no delegation or zero share amount + // Remove multistaking-lock and burn corresponding amount + if err != nil || unbondAmount.IsZero() { // Remove multistaking-lock and burn corresponding amount k.RemoveMultiStakingLock(ctx, stakingLock.LockID) err := k.bankKeeper.BurnCoins(ctx, types.ModuleName, sdk.NewCoins(stakingLock.LockedCoin.ToCoin())) if err != nil { - ubdErr = err - return true + return err } - return false + continue } // Call the Keeper method directly instead of going through MsgServer @@ -162,14 +163,8 @@ func (k Keeper) RemoveMultiStakingCoinProposal( Amount: stakingLock.LockedCoin.ToCoin(), }) if err != nil { - ubdErr = err - return true + return err } - - return false - }) - if ubdErr != nil { - return ubdErr } k.RemoveBondWeight(ctx, p.Denom)