From 547b8dc4530cc16374a395ba923e2db917311730 Mon Sep 17 00:00:00 2001 From: Puneet <59960662+puneet2019@users.noreply.github.com> Date: Wed, 20 Mar 2024 20:40:25 +0400 Subject: [PATCH] refactor events emition, and msgresponse usage (#791) --- x/liquidstake/keeper/keeper_test.go | 13 +++- x/liquidstake/keeper/liquidstake.go | 87 +++++++++++++++--------- x/liquidstake/keeper/msg_server.go | 3 +- x/liquidstake/keeper/rebalancing.go | 2 +- x/liquidstake/keeper/rebalancing_test.go | 8 +-- 5 files changed, 70 insertions(+), 43 deletions(-) diff --git a/x/liquidstake/keeper/keeper_test.go b/x/liquidstake/keeper/keeper_test.go index de5df883..fbcc8c3b 100644 --- a/x/liquidstake/keeper/keeper_test.go +++ b/x/liquidstake/keeper/keeper_test.go @@ -78,10 +78,12 @@ func (s *KeeperTestSuite) TearDownTest() { func (s *KeeperTestSuite) CreateValidators(powers []int64) ([]sdk.AccAddress, []sdk.ValAddress, []cryptotypes.PubKey) { s.app.BeginBlocker(s.ctx, abci.RequestBeginBlock{}) num := len(powers) - addrs := testhelpers.AddTestAddrsIncremental(s.app, s.ctx, num, math.NewInt(1000000000)) + addrs := testhelpers.AddTestAddrsIncremental(s.app, s.ctx, num, math.NewInt(10000000000000)) valAddrs := testhelpers.ConvertAddrsToValAddrs(addrs) pks := testhelpers.CreateTestPubKeys(num) - + skParams := s.app.StakingKeeper.GetParams(s.ctx) + skParams.ValidatorLiquidStakingCap = sdk.OneDec() + s.app.StakingKeeper.SetParams(s.ctx, skParams) for i, power := range powers { val, err := stakingtypes.NewValidator(valAddrs[i], pks[i], stakingtypes.Description{}) s.Require().NoError(err) @@ -93,6 +95,13 @@ func (s *KeeperTestSuite) CreateValidators(powers []int64) ([]sdk.AccAddress, [] newShares, err := s.app.StakingKeeper.Delegate(s.ctx, addrs[i], math.NewInt(power), stakingtypes.Unbonded, val, true) s.Require().NoError(err) s.Require().Equal(newShares.TruncateInt(), math.NewInt(power)) + msgValidatorBond := &stakingtypes.MsgValidatorBond{ + DelegatorAddress: addrs[i].String(), + ValidatorAddress: val.OperatorAddress, + } + handler := s.app.MsgServiceRouter().Handler(msgValidatorBond) + _, err = handler(s.ctx, msgValidatorBond) + s.Require().NoError(err) } s.app.EndBlocker(s.ctx, abci.RequestEndBlock{}) diff --git a/x/liquidstake/keeper/liquidstake.go b/x/liquidstake/keeper/liquidstake.go index 3f9d40d3..c9d85dc7 100644 --- a/x/liquidstake/keeper/liquidstake.go +++ b/x/liquidstake/keeper/liquidstake.go @@ -2,6 +2,7 @@ package keeper import ( "encoding/json" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" "sort" "time" @@ -134,7 +135,7 @@ func (k Keeper) LiquidStake( // LockOnLP sends tokens to a CW contract (Superfluid LP) with time locking. // It performs a CosmWasm execution through global message handler and may fail. // Emits events on a successful call. -func (k Keeper) LockOnLP(ctx sdk.Context, delegator sdk.AccAddress, amount sdk.Coin) ([]byte, error) { +func (k Keeper) LockOnLP(ctx sdk.Context, delegator sdk.AccAddress, amount sdk.Coin) ([]*codectypes.Any, error) { params := k.GetParams(ctx) if len(params.CwLockedPoolAddress) == 0 { @@ -179,16 +180,9 @@ func (k Keeper) LockOnLP(ctx sdk.Context, delegator sdk.AccAddress, amount sdk.C } // emit the events from the dispatched actions - events := msgResp.Events - sdkEvents := make([]sdk.Event, 0, len(events)) - for _, event := range events { - e := event - sdkEvents = append(sdkEvents, sdk.Event(e)) - } - - ctx.EventManager().EmitEvents(sdkEvents) + ctx.EventManager().EmitEvents(msgResp.GetEvents()) - return msgResp.Data, nil + return msgResp.MsgResponses, nil } type ExecMsg struct { @@ -281,24 +275,24 @@ func (k Keeper) LSMDelegate( validator sdk.ValAddress, proxyAcc sdk.AccAddress, preLsmStake sdk.Coin, -) (newShares math.LegacyDec, stkXPRTMintAmount math.Int, err error) { +) (stkXPRTMintAmount math.Int, err error) { params := k.GetParams(ctx) if params.ModulePaused { - return sdk.ZeroDec(), sdk.ZeroInt(), types.ErrModulePaused + return sdk.ZeroInt(), types.ErrModulePaused } else if params.LsmDisabled { - return sdk.ZeroDec(), sdk.ZeroInt(), types.ErrDisabledLSM + return sdk.ZeroInt(), types.ErrDisabledLSM } // check minimum liquid stake amount if preLsmStake.Amount.LT(params.MinLiquidStakeAmount) { - return sdk.ZeroDec(), sdk.ZeroInt(), types.ErrLessThanMinLiquidStakeAmount + return sdk.ZeroInt(), types.ErrLessThanMinLiquidStakeAmount } // check bond denomination bondDenom := k.stakingKeeper.BondDenom(ctx) if preLsmStake.Denom != bondDenom { - return sdk.ZeroDec(), sdk.ZeroInt(), errorsmod.Wrapf( + return sdk.ZeroInt(), errorsmod.Wrapf( types.ErrInvalidBondDenom, "invalid coin denomination: got %s, expected %s", preLsmStake.Denom, bondDenom, ) } @@ -307,7 +301,7 @@ func (k Keeper) LSMDelegate( activeVals := k.GetActiveLiquidValidators(ctx, whitelistedValsMap) if activeVals.Len() == 0 { - return sdk.ZeroDec(), sdk.ZeroInt(), types.ErrActiveLiquidValidatorsNotExists + return sdk.ZeroInt(), types.ErrActiveLiquidValidatorsNotExists } totalActiveWeight := activeVals.TotalWeight(whitelistedValsMap) @@ -315,14 +309,14 @@ func (k Keeper) LSMDelegate( math.LegacyNewDecFromInt(types.TotalValidatorWeight), ) if activeWeightQuorum.LT(types.ActiveLiquidValidatorsWeightQuorum) { - return sdk.ZeroDec(), sdk.ZeroInt(), errorsmod.Wrapf( + return sdk.ZeroInt(), errorsmod.Wrapf( types.ErrActiveLiquidValidatorsWeightQuorumNotReached, "%s < %s", activeWeightQuorum.String(), types.ActiveLiquidValidatorsWeightQuorum.String(), ) } if !whitelistedValsMap.IsListed(validator.String()) { - return sdk.ZeroDec(), sdk.ZeroInt(), types.ErrLiquidValidatorsNotExists.Wrap("delegation from a non allowed validator") + return sdk.ZeroInt(), types.ErrLiquidValidatorsNotExists.Wrap("delegation from a non allowed validator") } // NetAmount must be calculated before send @@ -339,24 +333,37 @@ func (k Keeper) LSMDelegate( handler := k.router.Handler(lsmTokenizeMsg) if handler == nil { - return sdk.ZeroDec(), sdk.ZeroInt(), sdkerrors.ErrUnknownRequest.Wrapf("unrecognized message route: %s", sdk.MsgTypeURL(lsmTokenizeMsg)) + return sdk.ZeroInt(), sdkerrors.ErrUnknownRequest.Wrapf("unrecognized message route: %s", sdk.MsgTypeURL(lsmTokenizeMsg)) } // [1] tokenize delegation into LSM shares msgResp, err := handler(ctx, lsmTokenizeMsg) if err != nil { - return sdk.ZeroDec(), sdk.ZeroInt(), types.ErrLSMTokenizeFailed.Wrapf("error: %s; message: %v", err.Error(), lsmTokenizeMsg) + return sdk.ZeroInt(), types.ErrLSMTokenizeFailed.Wrapf("error: %s; message: %v", err.Error(), lsmTokenizeMsg) + } + ctx.EventManager().EmitEvents(msgResp.GetEvents()) + + if len(msgResp.MsgResponses) != 1 { + return sdk.ZeroInt(), errorsmod.Wrapf( + types.ErrInvalidResponse, + "expected msg response should be exactly 1, got: %v, responses: %v", + len(msgResp.MsgResponses), msgResp.MsgResponses, + ) } var lsmTokenizeResp stakingtypes.MsgTokenizeSharesResponse - if err := k.cdc.Unmarshal(msgResp.Data, &lsmTokenizeResp); err != nil { - panic("wrong data type: " + err.Error()) + if err = k.cdc.Unmarshal(msgResp.MsgResponses[0].Value, &lsmTokenizeResp); err != nil { + return sdk.ZeroInt(), errorsmod.Wrapf( + sdkerrors.ErrJSONUnmarshal, + "cannot unmarshal tokenize share tx response message: %v", + err, + ) } // [2] send LSM shares to proxyAcc err = k.bankKeeper.SendCoins(ctx, delegator, proxyAcc, sdk.NewCoins(lsmTokenizeResp.Amount)) if err != nil { - return sdk.ZeroDec(), stkXPRTMintAmount, err + return stkXPRTMintAmount, err } lsmRedeemMsg := &stakingtypes.MsgRedeemTokensForShares{ @@ -366,18 +373,31 @@ func (k Keeper) LSMDelegate( handler = k.router.Handler(lsmRedeemMsg) if handler == nil { - return sdk.ZeroDec(), sdk.ZeroInt(), sdkerrors.ErrUnknownRequest.Wrapf("unrecognized message route: %s", sdk.MsgTypeURL(lsmRedeemMsg)) + return sdk.ZeroInt(), sdkerrors.ErrUnknownRequest.Wrapf("unrecognized message route: %s", sdk.MsgTypeURL(lsmRedeemMsg)) } // [3] redeem LSM shares from proxyAcc, to obtain a delegation msgResp, err = handler(ctx, lsmRedeemMsg) if err != nil { - return sdk.ZeroDec(), sdk.ZeroInt(), types.ErrLSMRedeemFailed.Wrapf("error: %s; message: %v", err.Error(), lsmRedeemMsg) + return sdk.ZeroInt(), types.ErrLSMRedeemFailed.Wrapf("error: %s; message: %v", err.Error(), lsmRedeemMsg) + } + ctx.EventManager().EmitEvents(msgResp.GetEvents()) + + if len(msgResp.MsgResponses) != 1 { + return sdk.ZeroInt(), errorsmod.Wrapf( + types.ErrInvalidResponse, + "expected msg response should be exactly 1, got: %v, responses: %v", + len(msgResp.MsgResponses), msgResp.MsgResponses, + ) } var lsmRedeemResp stakingtypes.MsgRedeemTokensForSharesResponse - if err := k.cdc.Unmarshal(msgResp.Data, &lsmRedeemResp); err != nil { - panic("wrong data type: " + err.Error()) + if err = k.cdc.Unmarshal(msgResp.MsgResponses[0].Value, &lsmRedeemResp); err != nil { + return sdk.ZeroInt(), errorsmod.Wrapf( + sdkerrors.ErrJSONUnmarshal, + "cannot unmarshal redeem tokens for shares tx response message: %v", + err, + ) } // mint stkxprt, MintAmount = TotalSupply * StakeAmount/NetAmount @@ -393,30 +413,29 @@ func (k Keeper) LSMDelegate( } if !stkXPRTMintAmount.IsPositive() { - return sdk.ZeroDec(), sdk.ZeroInt(), types.ErrTooSmallLiquidStakeAmount + return sdk.ZeroInt(), types.ErrTooSmallLiquidStakeAmount } // mint stkXPRT on module acc mintCoin := sdk.NewCoins(sdk.NewCoin(liquidBondDenom, stkXPRTMintAmount)) err = k.bankKeeper.MintCoins(ctx, types.ModuleName, mintCoin) if err != nil { - return sdk.ZeroDec(), stkXPRTMintAmount, err + return stkXPRTMintAmount, err } // send stkXPRT to delegator acc err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, delegator, mintCoin) if err != nil { - return sdk.ZeroDec(), stkXPRTMintAmount, err + return stkXPRTMintAmount, err } // but immediately lock new stkXPRT into LP on behalf of the delegator _, err = k.LockOnLP(ctx, delegator, sdk.NewCoin(liquidBondDenom, stkXPRTMintAmount)) if err != nil { - return sdk.ZeroDec(), stkXPRTMintAmount, err + return stkXPRTMintAmount, err } - newShares = lsmTokenizeResp.Amount.Amount.ToLegacyDec() - return newShares, stkXPRTMintAmount, err + return stkXPRTMintAmount, err } // LiquidDelegate delegates staking amount to active validators by proxy account. @@ -662,7 +681,7 @@ func (k Keeper) CheckDelegationStates(ctx sdk.Context, proxyAcc sdk.AccAddress) totalDelShares = totalDelShares.Add(delShares) liquidTokens := val.TokensFromSharesTruncated(delShares).TruncateInt() totalLiquidTokens = totalLiquidTokens.Add(liquidTokens) - totalRewards = totalRewards.Add(delReward.AmountOf(bondDenom)) + totalRewards = totalRewards.Add(delReward.AmountOf(bondDenom).TruncateDec()) } return false }, diff --git a/x/liquidstake/keeper/msg_server.go b/x/liquidstake/keeper/msg_server.go index 489eebfc..e24083ee 100644 --- a/x/liquidstake/keeper/msg_server.go +++ b/x/liquidstake/keeper/msg_server.go @@ -65,7 +65,7 @@ func (k msgServer) LiquidStake(goCtx context.Context, msg *types.MsgLiquidStake) func (k msgServer) StakeToLP(goCtx context.Context, msg *types.MsgStakeToLP) (*types.MsgStakeToLPResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - newShares, stkXPRTMintAmount, err := k.LSMDelegate( + stkXPRTMintAmount, err := k.LSMDelegate( ctx, msg.GetDelegator(), msg.GetValidator(), @@ -96,7 +96,6 @@ func (k msgServer) StakeToLP(goCtx context.Context, msg *types.MsgStakeToLP) (*t types.EventTypeMsgStakeToLP, sdk.NewAttribute(types.AttributeKeyDelegator, msg.DelegatorAddress), sdk.NewAttribute(types.AttributeKeyStakedAmount, msg.StakedAmount.String()), - sdk.NewAttribute(types.AttributeKeyNewShares, newShares.String()), sdk.NewAttribute(types.AttributeKeyStkXPRTMintedAmount, stkXPRTMinted.String()), sdk.NewAttribute(types.AttributeKeyCValue, cValue.String()), ), diff --git a/x/liquidstake/keeper/rebalancing.go b/x/liquidstake/keeper/rebalancing.go index cfc5a762..99d09aa9 100644 --- a/x/liquidstake/keeper/rebalancing.go +++ b/x/liquidstake/keeper/rebalancing.go @@ -248,7 +248,7 @@ func (k Keeper) AutocompoundStakingRewards(ctx sdk.Context, whitelistedValsMap t // re-staking of the accumulated rewards cachedCtx, writeCache := ctx.CacheContext() delegableAmount := proxyAccBalance.Amount.Sub(autocompoundFee.Amount) - _, err := k.LiquidDelegate(cachedCtx, types.LiquidStakeProxyAcc, activeVals, delegableAmount, whitelistedValsMap) + err := k.LiquidDelegate(cachedCtx, types.LiquidStakeProxyAcc, activeVals, delegableAmount, whitelistedValsMap) if err != nil { logger := k.Logger(ctx) logger.Error("re-staking failed", "error", err) diff --git a/x/liquidstake/keeper/rebalancing_test.go b/x/liquidstake/keeper/rebalancing_test.go index 8d2d2233..3fac7811 100644 --- a/x/liquidstake/keeper/rebalancing_test.go +++ b/x/liquidstake/keeper/rebalancing_test.go @@ -276,9 +276,9 @@ func (s *KeeperTestSuite) TestRebalancingCase1() { func (s *KeeperTestSuite) TestRebalancingConsecutiveCase() { _, valOpers, _ := s.CreateValidators([]int64{ - 1000000, 1000000, 1000000, 1000000, 1000000, - 1000000, 1000000, 1000000, 1000000, 1000000, - 1000000, 1000000, 1000000, 1000000, 1000000, + 1000000000000, 1000000000000, 1000000000000, 1000000000000, 1000000000000, + 1000000000000, 1000000000000, 1000000000000, 1000000000000, 1000000000000, + 1000000000000, 1000000000000, 1000000000000, 1000000000000, 1000000000000, }) s.ctx = s.ctx.WithBlockHeight(100).WithBlockTime(testhelpers.ParseTime("2022-03-01T00:00:00Z")) params := s.keeper.GetParams(s.ctx) @@ -501,7 +501,7 @@ func (s *KeeperTestSuite) TestAutocompoundStakingRewards() { totalRewardsAfter, totalDelSharesAfter, totalLiquidTokensAfter := s.keeper.CheckDelegationStates(s.ctx, types.LiquidStakeProxyAcc) s.EqualValues(totalRewardsAfter, sdk.ZeroDec()) - autocompoundFee := params.AutocompoundFeeRate.Mul(totalRewards) + autocompoundFee := params.AutocompoundFeeRate.Mul(totalRewards).TruncateDec() s.EqualValues(totalDelSharesAfter, totalRewards.Sub(autocompoundFee).Add(totalDelShares).TruncateDec(), totalLiquidTokensAfter) stakingParams := s.app.StakingKeeper.GetParams(s.ctx)