Skip to content

Commit

Permalink
Merge pull request #900 from persistenceOne/puneet/forceunbonding
Browse files Browse the repository at this point in the history
feat: add force unbond and withdraw
  • Loading branch information
puneet2019 authored Dec 23, 2024
2 parents cb7935d + 859257d commit ed4cfc8
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Improvements

- [855](https://github.com/persistenceOne/pstake-native/pull/855) Add condition for not allowing zero delegation unbondings icq
- [900](https://github.com/persistenceOne/pstake-native/pull/900) Add feature to deprecate liquidstakeibc

## [v2.15.0] - 2024-05-30

Expand Down
9 changes: 3 additions & 6 deletions x/liquidstakeibc/keeper/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,14 @@ import (
func (k *Keeper) BeginBlock(ctx sdk.Context) {
// perform BeginBlocker tasks for each chain
for _, hc := range k.GetAllHostChains(ctx) {
if !hc.Active {
// don't do anything on inactive chains
continue
if hc.Active {
// attempt to delegate
k.DoDelegate(ctx, hc)
}

// attempt to recreate closed ICA channels
k.DoRecreateICA(ctx, hc)

// attempt to delegate
k.DoDelegate(ctx, hc)

// attempt to automatically claim matured undelegations
k.DoClaim(ctx, hc)

Expand Down
5 changes: 3 additions & 2 deletions x/liquidstakeibc/keeper/icq.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,9 @@ func DelegationCallback(k Keeper, ctx sdk.Context, data []byte, query icqtypes.Q
k.SetHostChainValidator(ctx, hc, validator)

// update the c value for the slashed chain
k.UpdateCValue(ctx, hc)

if hc.Active {
k.UpdateCValue(ctx, hc)
}
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeSlashing,
Expand Down
4 changes: 3 additions & 1 deletion x/liquidstakeibc/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,9 @@ func (k *Keeper) UpdateCValues(ctx sdk.Context) {
hostChains := k.GetAllHostChains(ctx)

for _, hc := range hostChains {
k.UpdateCValue(ctx, hc)
if hc.Active {
k.UpdateCValue(ctx, hc)
}
}
}

Expand Down
69 changes: 69 additions & 0 deletions x/liquidstakeibc/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/cosmos/gogoproto/proto"
transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types"

"github.com/persistenceOne/pstake-native/v2/x/liquidstakeibc/types"
Expand Down Expand Up @@ -331,7 +332,75 @@ func (k msgServer) UpdateHostChain(
if err := k.QueryValidatorDelegationUpdate(ctx, hc, val); err != nil {
return nil, fmt.Errorf("unable to send ICQ query for validator delegation update")
}
case types.KeyForceUnbond:
if hc.Active {
return nil, fmt.Errorf("cannot force unbond to active host chain")
}
validator, coin, valid := strings.Cut(update.Value, ",")
if !valid {
return nil, fmt.Errorf("invalid force unbond value, expected form \"cosmovaloperxx,123denom\" ")
}
val, found := hc.GetValidator(validator)
if !found {
return nil, types.ErrValidatorNotFound
}
amount, err := sdktypes.ParseCoinNormalized(coin)
if err != nil {
return nil, err
}
msgUnbond := &stakingtypes.MsgUndelegate{
DelegatorAddress: hc.DelegationAccount.Address,
ValidatorAddress: val.OperatorAddress,
Amount: amount,
}
_, err = k.GenerateAndExecuteICATx(ctx, hc.ConnectionId, hc.DelegationAccount.Owner, []proto.Message{msgUnbond})
if err != nil {
return nil, err
}

case types.KeyForceICATransfer:
amount, err := sdktypes.ParseCoinNormalized(update.Value)
if err != nil {
return nil, err
}
_, err = k.SendICATransfer(ctx, hc, amount, hc.DelegationAccount.Address, k.GetParams(ctx).AdminAddress, hc.DelegationAccount.Owner)
if err != nil {
return nil, err
}
case types.KeyForceICATransferRewards:
amount, err := sdktypes.ParseCoinNormalized(update.Value)
if err != nil {
return nil, err
}
_, err = k.SendICATransfer(ctx, hc, amount, hc.RewardsAccount.Address, k.GetParams(ctx).AdminAddress, hc.RewardsAccount.Owner)
if err != nil {
return nil, err
}
case types.KeyForceTransferDeposits:
amount := k.bankKeeper.GetBalance(ctx, k.GetDepositModuleAccount(ctx).GetAddress(), hc.IBCDenom())
if amount.IsPositive() {
err := k.bankKeeper.SendCoins(ctx, k.GetDepositModuleAccount(ctx).GetAddress(), sdktypes.MustAccAddressFromBech32(k.GetParams(ctx).AdminAddress), sdktypes.NewCoins(amount))
if err != nil {
return nil, err
}
}
case types.KeyForceTransferUnbonded:
amount := k.bankKeeper.GetBalance(ctx, k.GetUndelegationModuleAccount(ctx).GetAddress(), hc.IBCDenom())
if amount.IsPositive() {
err := k.bankKeeper.SendCoins(ctx, k.GetUndelegationModuleAccount(ctx).GetAddress(), sdktypes.MustAccAddressFromBech32(k.GetParams(ctx).AdminAddress), sdktypes.NewCoins(amount))
if err != nil {
return nil, err
}
}
case types.KeyForceFailUnbond:
epochNumber, err := strconv.ParseInt(update.Value, 10, 64)
if err != nil {
return nil, err
}
err = k.FailUnbondingsForEpoch(ctx, hc.ChainId, epochNumber)
if err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("invalid or unexpected update key: %s", update.Key)
}
Expand Down
10 changes: 10 additions & 0 deletions x/liquidstakeibc/keeper/unbonding.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,16 @@ func (k *Keeper) FailAllUnbondingsForSequenceID(ctx sdk.Context, sequenceID stri
}
}

func (k *Keeper) FailUnbondingsForEpoch(ctx sdk.Context, chainID string, epochNumber int64) error {
unbonding, found := k.GetUnbonding(ctx, chainID, epochNumber)
if !found {
return types.ErrUnbondingNotFound
}
unbonding.State = types.Unbonding_UNBONDING_FAILED
k.SetUnbonding(ctx, unbonding)
return nil
}

func (k *Keeper) RevertUnbondingsState(ctx sdk.Context, unbondings []*types.Unbonding) {
for _, unbonding := range unbondings {
unbonding.IbcSequenceId = ""
Expand Down
1 change: 1 addition & 0 deletions x/liquidstakeibc/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ var (
ErrLSMDepositProcessing = errorsmod.Register(ModuleName, 2020, "already processing LSM deposit")
ErrLSMValidatorInvalidState = errorsmod.Register(ModuleName, 2021, "validator invalid state")
ErrInsufficientDeposits = errorsmod.Register(ModuleName, 2022, "insufficient deposits")
ErrUnbondingNotFound = errorsmod.Register(ModuleName, 2023, "unbonding not found")
)
1 change: 1 addition & 0 deletions x/liquidstakeibc/types/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const (
EventTypeLiquidStakeLSM = "liquid_stake_lsm"
EventTypeLiquidUnstake = "liquid_unstake"
EventTypeRedeem = "redeem"
EventTypeRedeemDeprecated = "redeem_deprecated"
EventTypePacket = "ics27_packet"
EventTypeTimeout = "timeout"
EventTypeSlashing = "validator_slash"
Expand Down
6 changes: 6 additions & 0 deletions x/liquidstakeibc/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ const (
KeyFlags string = "flags"
KeyRewardParams string = "reward_params"
KeyForceUpdateValidator string = "force_update_validator"
KeyForceUnbond string = "force_unbond"
KeyForceICATransfer string = "force_ica_transfer"
KeyForceICATransferRewards string = "force_ica_transfer_rewards"
KeyForceTransferDeposits string = "force_transfer_deposits"
KeyForceTransferUnbonded string = "force_transfer_unbonded"
KeyForceFailUnbond string = "force_fail_unbond"
)

var (
Expand Down
43 changes: 43 additions & 0 deletions x/liquidstakeibc/types/msgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ var (
_ sdk.Msg = &MsgLiquidUnstake{}
_ sdk.Msg = &MsgRedeem{}
_ sdk.Msg = &MsgLiquidStakeLSM{}
_ sdk.Msg = &MsgUpdateParams{}
)

func NewMsgRegisterHostChain(
Expand Down Expand Up @@ -396,6 +397,48 @@ func (m *MsgUpdateHostChain) ValidateBasic() error {
if err != nil {
return err
}
case KeyForceUnbond:
// expected "chainvaloper1xxx,1234denom"
validator, coin, valid := strings.Cut(update.Value, ",")
if !valid {
return fmt.Errorf("invalid force unbond value, expected form \"cosmovaloperxx,123denom\" ")
}
_, _, err := bech32.DecodeAndConvert(validator)
if err != nil {
return err
}
_, err = sdk.ParseCoinNormalized(coin)
if err != nil {
return err
}
case KeyForceICATransfer:
// expected "1234denom"
_, err := sdk.ParseCoinNormalized(update.Value)
if err != nil {
return err
}
case KeyForceICATransferRewards:
// expected "1234denom"
_, err := sdk.ParseCoinNormalized(update.Value)
if err != nil {
return err
}
case KeyForceTransferDeposits:
// expected nothing, ""
if update.Value != "" {
return fmt.Errorf("invalid force transfer deposits, expected \"\" ")
}
case KeyForceTransferUnbonded:
// expected nothing, ""
if update.Value != "" {
return fmt.Errorf("invalid force transfer unbonded, expected \"\" ")
}
case KeyForceFailUnbond:
// expected , "123"
_, err := strconv.ParseInt(update.Value, 10, 64)
if err != nil {
return err
}
default:
return fmt.Errorf("invalid or unexpected update key: %s", update.Key)
}
Expand Down

0 comments on commit ed4cfc8

Please sign in to comment.