diff --git a/tests/e2e/slashing_test.go b/tests/e2e/slashing_test.go index af3152f0..83999268 100644 --- a/tests/e2e/slashing_test.go +++ b/tests/e2e/slashing_test.go @@ -302,8 +302,6 @@ func TestSlasingImmediateUnbond(t *testing.T) { base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf(`{"validator": "%s"}`, myLocalValidatorAddr)))) providerCli.MustExecVault(execLocalStakingMsg) - assert.Equal(t, 100_000_000, providerCli.QueryVaultFreeBalance()) - // Check slashable amount require.Equal(t, 20_000_000, providerCli.QuerySlashableAmount()) // Check free collateral diff --git a/tests/testdata/mesh_converter.wasm.gz b/tests/testdata/mesh_converter.wasm.gz index a41ea36a..5c6f203c 100644 Binary files a/tests/testdata/mesh_converter.wasm.gz and b/tests/testdata/mesh_converter.wasm.gz differ diff --git a/tests/testdata/mesh_external_staking.wasm.gz b/tests/testdata/mesh_external_staking.wasm.gz index 7ae90b5b..63fff499 100644 Binary files a/tests/testdata/mesh_external_staking.wasm.gz and b/tests/testdata/mesh_external_staking.wasm.gz differ diff --git a/tests/testdata/mesh_native_staking.wasm.gz b/tests/testdata/mesh_native_staking.wasm.gz index aab4a86e..d1ea0c42 100644 Binary files a/tests/testdata/mesh_native_staking.wasm.gz and b/tests/testdata/mesh_native_staking.wasm.gz differ diff --git a/tests/testdata/mesh_native_staking_proxy.wasm.gz b/tests/testdata/mesh_native_staking_proxy.wasm.gz index a702a620..76169a9b 100644 Binary files a/tests/testdata/mesh_native_staking_proxy.wasm.gz and b/tests/testdata/mesh_native_staking_proxy.wasm.gz differ diff --git a/tests/testdata/mesh_osmosis_price_provider.wasm.gz b/tests/testdata/mesh_osmosis_price_provider.wasm.gz index ff1a327e..c3b28763 100644 Binary files a/tests/testdata/mesh_osmosis_price_provider.wasm.gz and b/tests/testdata/mesh_osmosis_price_provider.wasm.gz differ diff --git a/tests/testdata/mesh_remote_price_feed.wasm.gz b/tests/testdata/mesh_remote_price_feed.wasm.gz index 8d30589e..722f16e3 100644 Binary files a/tests/testdata/mesh_remote_price_feed.wasm.gz and b/tests/testdata/mesh_remote_price_feed.wasm.gz differ diff --git a/tests/testdata/mesh_simple_price_feed.wasm.gz b/tests/testdata/mesh_simple_price_feed.wasm.gz index 9a2aca20..c7afaa3d 100644 Binary files a/tests/testdata/mesh_simple_price_feed.wasm.gz and b/tests/testdata/mesh_simple_price_feed.wasm.gz differ diff --git a/tests/testdata/mesh_vault.wasm.gz b/tests/testdata/mesh_vault.wasm.gz index fb470f66..e3761fea 100644 Binary files a/tests/testdata/mesh_vault.wasm.gz and b/tests/testdata/mesh_vault.wasm.gz differ diff --git a/tests/testdata/mesh_virtual_staking.wasm.gz b/tests/testdata/mesh_virtual_staking.wasm.gz index 69e5bb42..8583b035 100644 Binary files a/tests/testdata/mesh_virtual_staking.wasm.gz and b/tests/testdata/mesh_virtual_staking.wasm.gz differ diff --git a/tests/testdata/version.txt b/tests/testdata/version.txt index 94427d4e..4a1ca376 100644 --- a/tests/testdata/version.txt +++ b/tests/testdata/version.txt @@ -1 +1 @@ -d9e27c854aaf3bb604d32f5fa8e6c3e42b686edf +8292d43b7f2bb59dfa884d3b0b1509ce659b0793 diff --git a/x/meshsecurityprovider/contract/in_message.go b/x/meshsecurityprovider/contract/in_message.go index 3cd5348a..bf3a992a 100644 --- a/x/meshsecurityprovider/contract/in_message.go +++ b/x/meshsecurityprovider/contract/in_message.go @@ -10,6 +10,7 @@ type ( Bond *BondMsg `json:"bond,omitempty"` Unbond *UnbondMsg `json:"unbond,omitempty"` Unstake *UnstakeMsg `json:"unstake,omitempty"` + Restake *RestakeMsg `json:"restake,omitempty"` } BondMsg struct { Amount wasmvmtypes.Coin `json:"amount"` @@ -24,4 +25,9 @@ type ( Validator string `json:"validator"` Delegator string `json:"delegator"` } + RestakeMsg struct { + Amount wasmvmtypes.Coin `json:"amount"` + Delegator string `json:"delegator"` + Validator string `json:"validator"` + } ) diff --git a/x/meshsecurityprovider/keeper/handle_plugin.go b/x/meshsecurityprovider/keeper/handle_plugin.go index 923d4fa2..2a05490e 100644 --- a/x/meshsecurityprovider/keeper/handle_plugin.go +++ b/x/meshsecurityprovider/keeper/handle_plugin.go @@ -47,6 +47,8 @@ func (h CustomMessenger) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddres return h.k.HandleUnbondMsg(ctx, contractAddr, customMsg.Provider.Unbond) case customMsg.Provider.Unstake != nil: return h.k.HandleUnstakeMsg(ctx, contractAddr, customMsg.Provider.Unstake) + case customMsg.Provider.Restake != nil: + return h.k.HandleRestakeMsg(ctx, contractAddr, customMsg.Provider.Restake) } return nil, nil, wasmtypes.ErrUnknownMsg diff --git a/x/meshsecurityprovider/keeper/keeper.go b/x/meshsecurityprovider/keeper/keeper.go index 9eda5798..b8815835 100644 --- a/x/meshsecurityprovider/keeper/keeper.go +++ b/x/meshsecurityprovider/keeper/keeper.go @@ -204,6 +204,60 @@ func (k Keeper) HandleUnstakeMsg(ctx sdk.Context, actor sdk.AccAddress, unstakeM )}, nil, nil } +func (k Keeper) HandleRestakeMsg(ctx sdk.Context, actor sdk.AccAddress, restakeMsg *contract.RestakeMsg) ([]sdk.Event, [][]byte, error) { + if actor.String() != k.VaultAddress(ctx) { + return nil, nil, sdkerrors.ErrUnauthorized.Wrapf("contract has no permission for mesh security operations") + } + + coin, err := wasmkeeper.ConvertWasmCoinToSdkCoin(restakeMsg.Amount) + if err != nil { + return nil, nil, err + } + bondDenom := k.stakingKeeper.BondDenom(ctx) + if coin.Denom != bondDenom { + return nil, nil, sdkerrors.ErrInvalidRequest.Wrapf("invalid coin denomination: got %s, expected %s", coin.Denom, bondDenom) + } + + delAddr, err := sdk.AccAddressFromBech32(restakeMsg.Delegator) + if err != nil { + return nil, nil, err + } + valAddr, err := sdk.ValAddressFromBech32(restakeMsg.Validator) + if err != nil { + return nil, nil, err + } + + validatorInfo, found := k.stakingKeeper.GetValidator(ctx, valAddr) + if !found { + return nil, nil, sdkerrors.ErrNotFound.Wrapf("can not found validator with address: %s", restakeMsg.Validator) + } + + shares, err := k.stakingKeeper.ValidateUnbondAmount(ctx, actor, valAddr, coin.Amount) + if err == stakingtypes.ErrNoDelegation { + return nil, nil, sdkerrors.ErrNotFound.Wrapf("can not found delegation with address: %s", restakeMsg.Delegator) + } else if err != nil { + return nil, nil, err + } + unbondAmt, err := k.InstantUndelegate(ctx, delAddr, validatorInfo, shares) + if err != nil { + return nil, nil, err + } + if !unbondAmt.Equal(coin) { + return nil, nil, sdkerrors.ErrInvalidRequest.Wrapf("Delegation has been slashed") + } + err = k.bankKeeper.DelegateCoins(ctx, delAddr, actor, sdk.NewCoins(unbondAmt)) + if err != nil { + return nil, nil, err + } + + return []sdk.Event{sdk.NewEvent( + types.EventTypeUnbond, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeyAmount, coin.String()), + sdk.NewAttribute(types.AttributeKeyDelegator, delAddr.String()), + )}, nil, nil +} + func (k Keeper) unstake(ctx sdk.Context, proxyContract sdk.AccAddress, validator sdk.ValAddress, coin sdk.Coin) error { if coin.Amount.IsNil() || coin.Amount.IsZero() || coin.Amount.IsNegative() { return sdkerrors.ErrInvalidRequest.Wrap("amount") @@ -236,13 +290,14 @@ func (k Keeper) unstake(ctx sdk.Context, proxyContract sdk.AccAddress, validator return nil } - return k.InstantUndelegate(ctx, proxyContract, validator, shares) + _, err = k.InstantUndelegate(ctx, proxyContract, validatorInfo, shares) + return err } -func (k Keeper) InstantUndelegate(ctx sdk.Context, delAddr sdk.AccAddress, validator sdk.ValAddress, sharesAmount sdk.Dec) error { - returnAmount, err := k.stakingKeeper.Unbond(ctx, delAddr, validator, sharesAmount) +func (k Keeper) InstantUndelegate(ctx sdk.Context, delAddr sdk.AccAddress, validator stakingtypes.Validator, sharesAmount sdk.Dec) (sdk.Coin, error) { + returnAmount, err := k.stakingKeeper.Unbond(ctx, delAddr, validator.GetOperator(), sharesAmount) if err != nil { - return err + return sdk.Coin{}, err } bondDenom := k.stakingKeeper.BondDenom(ctx) @@ -250,5 +305,9 @@ func (k Keeper) InstantUndelegate(ctx sdk.Context, delAddr sdk.AccAddress, valid amt := sdk.NewCoin(bondDenom, returnAmount) res := sdk.NewCoins(amt) - return k.bankKeeper.UndelegateCoinsFromModuleToAccount(ctx, stakingtypes.NotBondedPoolName, delAddr, res) + err = k.bankKeeper.UndelegateCoinsFromModuleToAccount(ctx, stakingtypes.NotBondedPoolName, delAddr, res) + if err != nil { + return sdk.Coin{}, err + } + return amt, nil }