diff --git a/x/accountedpool/keeper/hooks_leveragelp.go b/x/accountedpool/keeper/hooks_leveragelp.go index 7e2463032..01b203bae 100644 --- a/x/accountedpool/keeper/hooks_leveragelp.go +++ b/x/accountedpool/keeper/hooks_leveragelp.go @@ -76,14 +76,14 @@ func (h LeverageLpHooks) AfterDisablingPool(ctx sdk.Context, ammPool ammtypes.Po return h.k.OnLeverageLpPoolDisable(ctx, ammPool) } -func (h LeverageLpHooks) AfterLeverageLpPositionOpen(ctx sdk.Context, sender sdk.AccAddress) error { +func (h LeverageLpHooks) AfterLeverageLpPositionOpen(ctx sdk.Context, sender sdk.AccAddress, ammPool ammtypes.Pool) error { return nil } -func (h LeverageLpHooks) AfterLeverageLpPositionClose(ctx sdk.Context, sender sdk.AccAddress) error { +func (h LeverageLpHooks) AfterLeverageLpPositionClose(ctx sdk.Context, sender sdk.AccAddress, ammPool ammtypes.Pool) error { return nil } -func (h LeverageLpHooks) AfterLeverageLpPositionOpenConsolidate(ctx sdk.Context, sender sdk.AccAddress) error { +func (h LeverageLpHooks) AfterLeverageLpPositionOpenConsolidate(ctx sdk.Context, sender sdk.AccAddress, ammPool ammtypes.Pool) error { return nil } diff --git a/x/accountedpool/migrations/v2_migration.go b/x/accountedpool/migrations/v2_migration.go index 66deeab07..11a1a1323 100644 --- a/x/accountedpool/migrations/v2_migration.go +++ b/x/accountedpool/migrations/v2_migration.go @@ -5,9 +5,5 @@ import ( ) func (m Migrator) V2Migration(ctx sdk.Context) error { - allAccountedPool := m.keeper.GetAllAccountedPool(ctx) - for _, accountedPool := range allAccountedPool { - m.keeper.RemoveAccountedPool(ctx, accountedPool.PoolId) - } return nil } diff --git a/x/leveragelp/keeper/hooks_amm.go b/x/leveragelp/keeper/hooks_amm.go index d75bd26c6..756772807 100644 --- a/x/leveragelp/keeper/hooks_amm.go +++ b/x/leveragelp/keeper/hooks_amm.go @@ -10,6 +10,7 @@ import ( func (k Keeper) CheckAmmPoolUsdcBalance(ctx sdk.Context, ammPool ammtypes.Pool) error { leveragePool, found := k.GetPool(ctx, ammPool.PoolId) if !found { + // It is possible that this pool haven't been enabled return nil } diff --git a/x/leveragelp/keeper/msg_server_claim_rewards_test.go b/x/leveragelp/keeper/msg_server_claim_rewards_test.go index 76c9df666..2308c045f 100644 --- a/x/leveragelp/keeper/msg_server_claim_rewards_test.go +++ b/x/leveragelp/keeper/msg_server_claim_rewards_test.go @@ -4,6 +4,7 @@ import ( "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/address" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" simapp "github.com/elys-network/elys/app" ammtypes "github.com/elys-network/elys/x/amm/types" @@ -59,11 +60,17 @@ func initializeForClaimRewards(suite *KeeperTestSuite, addresses []sdk.AccAddres } if createAmmPool { poolId, err := suite.app.AmmKeeper.CreatePool(suite.ctx, &msgCreatePool) - if err != nil { - panic(err) + suite.Require().NoError(err) + enablePoolMsg := types.MsgAddPool{ + Authority: authtypes.NewModuleAddress("gov").String(), + Pool: types.AddPool{ + AmmPoolId: poolId, + LeverageMax: math.LegacyNewDec(10), + }, } - - suite.app.LeveragelpKeeper.SetPool(suite.ctx, types.NewPool(poolId, math.LegacyMustNewDecFromStr("10"))) + msgServer := keeper.NewMsgServerImpl(*suite.app.LeveragelpKeeper) + _, err = msgServer.AddPool(suite.ctx, &enablePoolMsg) + suite.Require().NoError(err) } msgBond := stabletypes.MsgBond{ diff --git a/x/leveragelp/keeper/msg_server_close.go b/x/leveragelp/keeper/msg_server_close.go index 00852ec6f..559c30a97 100644 --- a/x/leveragelp/keeper/msg_server_close.go +++ b/x/leveragelp/keeper/msg_server_close.go @@ -21,7 +21,11 @@ func (k Keeper) Close(ctx sdk.Context, msg *types.MsgClose) (*types.MsgCloseResp } if k.hooks != nil { - err := k.hooks.AfterLeverageLpPositionClose(ctx, sdk.MustAccAddressFromBech32(msg.Creator)) + ammPool, err := k.GetAmmPool(ctx, closedPosition.AmmPoolId) + if err != nil { + return nil, err + } + err = k.hooks.AfterLeverageLpPositionClose(ctx, sdk.MustAccAddressFromBech32(msg.Creator), ammPool) if err != nil { return nil, err } diff --git a/x/leveragelp/keeper/msg_server_close_positions.go b/x/leveragelp/keeper/msg_server_close_positions.go index 8519a0ce8..c6d70f82f 100644 --- a/x/leveragelp/keeper/msg_server_close_positions.go +++ b/x/leveragelp/keeper/msg_server_close_positions.go @@ -2,6 +2,7 @@ package keeper import ( "context" + errorsmod "cosmossdk.io/errors" "fmt" "strings" @@ -34,6 +35,20 @@ func (k msgServer) ClosePositions(goCtx context.Context, msg *types.MsgClosePosi // Add log about error or not liquidated liqLog = append(liqLog, fmt.Sprintf("Position: Address:%s Id:%d cannot be liquidated due to err: %s", position.Address, position.Id, err.Error())) } + + if k.hooks != nil { + // ammPool will have updated values for opening position + found := false + ammPool, found = k.amm.GetPool(ctx, position.AmmPoolId) + if !found { + return nil, errorsmod.Wrap(types.ErrPoolDoesNotExist, fmt.Sprintf("poolId: %d", position.AmmPoolId)) + } + err = k.hooks.AfterLeverageLpPositionClose(ctx, position.GetOwnerAddress(), ammPool) + if err != nil { + return nil, err + } + } + } // Handle stop loss @@ -57,12 +72,18 @@ func (k msgServer) ClosePositions(goCtx context.Context, msg *types.MsgClosePosi // Add log about error or not closed closeLog = append(closeLog, fmt.Sprintf("Position: Address:%s Id:%d cannot be liquidated due to err: %s", position.Address, position.Id, err.Error())) } - } - if k.hooks != nil { - err := k.hooks.AfterLeverageLpPositionClose(ctx, sdk.MustAccAddressFromBech32(msg.Creator)) - if err != nil { - return nil, err + if k.hooks != nil { + // ammPool will have updated values for opening position + found := false + ammPool, found = k.amm.GetPool(ctx, position.AmmPoolId) + if !found { + return nil, errorsmod.Wrap(types.ErrPoolDoesNotExist, fmt.Sprintf("poolId: %d", position.AmmPoolId)) + } + err = k.hooks.AfterLeverageLpPositionClose(ctx, position.GetOwnerAddress(), ammPool) + if err != nil { + return nil, err + } } } diff --git a/x/leveragelp/keeper/msg_server_close_test.go b/x/leveragelp/keeper/msg_server_close_test.go index ce38d5a58..4db9f7a7f 100644 --- a/x/leveragelp/keeper/msg_server_close_test.go +++ b/x/leveragelp/keeper/msg_server_close_test.go @@ -1,6 +1,8 @@ package keeper_test import ( + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/elys-network/elys/x/leveragelp/keeper" "time" "cosmossdk.io/math" @@ -57,9 +59,17 @@ func initializeForClose(suite *KeeperTestSuite, addresses []sdk.AccAddress, asse }, } poolId, err := suite.app.AmmKeeper.CreatePool(suite.ctx, &msgCreatePool) - if err != nil { - panic(err) + suite.Require().NoError(err) + enablePoolMsg := types.MsgAddPool{ + Authority: authtypes.NewModuleAddress("gov").String(), + Pool: types.AddPool{ + AmmPoolId: poolId, + LeverageMax: math.LegacyNewDec(10), + }, } + msgServer := keeper.NewMsgServerImpl(*suite.app.LeveragelpKeeper) + _, err = msgServer.AddPool(suite.ctx, &enablePoolMsg) + suite.Require().NoError(err) suite.app.LeveragelpKeeper.SetPool(suite.ctx, types.NewPool(poolId, math.LegacyMustNewDecFromStr("10"))) msgBond := stabletypes.MsgBond{ Creator: addresses[1].String(), @@ -266,7 +276,7 @@ func (suite *KeeperTestSuite) TestClose() { }, func() { position, _ := suite.app.LeveragelpKeeper.GetPosition(suite.ctx, addresses[0], 1) - actualShares, ok := sdk.NewIntFromString("9999952380952380950") + actualShares, ok := sdk.NewIntFromString("9995950947287941390") suite.Require().True(ok) suite.Require().Equal(position.LeveragedLpAmount, actualShares) }, diff --git a/x/leveragelp/keeper/msg_server_open.go b/x/leveragelp/keeper/msg_server_open.go index 6e5bd6c7d..b492318f1 100644 --- a/x/leveragelp/keeper/msg_server_open.go +++ b/x/leveragelp/keeper/msg_server_open.go @@ -40,11 +40,11 @@ func (k Keeper) Open(ctx sdk.Context, msg *types.MsgOpen) (*types.MsgOpenRespons if !found { return nil, errorsmod.Wrap(types.ErrPoolDoesNotExist, fmt.Sprintf("poolId: %d", msg.AmmPoolId)) } - amm_pool, found := k.amm.GetPool(ctx, msg.AmmPoolId) + ammPool, found := k.amm.GetPool(ctx, msg.AmmPoolId) if !found { return nil, errorsmod.Wrap(types.ErrPoolDoesNotExist, fmt.Sprintf("poolId: %d", msg.AmmPoolId)) } - poolLeveragelpRatio = pool.LeveragedLpAmount.ToLegacyDec().Quo(amm_pool.TotalShares.Amount.ToLegacyDec()) + poolLeveragelpRatio = pool.LeveragedLpAmount.ToLegacyDec().Quo(ammPool.TotalShares.Amount.ToLegacyDec()) if poolLeveragelpRatio.GTE(pool.MaxLeveragelpRatio) || borrowRatio.GTE(params.MaxLeverageRatio) { return nil, errorsmod.Wrap(types.ErrMaxLeverageLpExists, "no new position can be open") @@ -79,7 +79,12 @@ func (k Keeper) Open(ctx sdk.Context, msg *types.MsgOpen) (*types.MsgOpenRespons } if k.hooks != nil { - err := k.hooks.AfterLeverageLpPositionOpen(ctx, sdk.MustAccAddressFromBech32(msg.Creator)) + // ammPool will have updated values for opening position + ammPool, found = k.amm.GetPool(ctx, msg.AmmPoolId) + if !found { + return nil, errorsmod.Wrap(types.ErrPoolDoesNotExist, fmt.Sprintf("poolId: %d", msg.AmmPoolId)) + } + err = k.hooks.AfterLeverageLpPositionOpen(ctx, sdk.MustAccAddressFromBech32(msg.Creator), ammPool) if err != nil { return nil, err } diff --git a/x/leveragelp/keeper/msg_server_update_stop_loss_test.go b/x/leveragelp/keeper/msg_server_update_stop_loss_test.go index de9b7f5c2..6b9c39896 100644 --- a/x/leveragelp/keeper/msg_server_update_stop_loss_test.go +++ b/x/leveragelp/keeper/msg_server_update_stop_loss_test.go @@ -3,6 +3,7 @@ package keeper_test import ( "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" simapp "github.com/elys-network/elys/app" ammtypes "github.com/elys-network/elys/x/amm/types" @@ -56,24 +57,27 @@ func initializeForUpdateStopLoss(suite *KeeperTestSuite, addresses []sdk.AccAddr }, } poolId, err := suite.app.AmmKeeper.CreatePool(suite.ctx, &msgCreatePool) - if err != nil { - panic(err) + suite.Require().NoError(err) + enablePoolMsg := types.MsgAddPool{ + Authority: authtypes.NewModuleAddress("gov").String(), + Pool: types.AddPool{ + AmmPoolId: poolId, + LeverageMax: math.LegacyNewDec(10), + }, } - suite.app.LeveragelpKeeper.SetPool(suite.ctx, types.NewPool(poolId, math.LegacyMustNewDecFromStr("10"))) + msgServer := keeper.NewMsgServerImpl(*suite.app.LeveragelpKeeper) + _, err = msgServer.AddPool(suite.ctx, &enablePoolMsg) + suite.Require().NoError(err) msgBond := stabletypes.MsgBond{ Creator: addresses[1].String(), Amount: issueAmount.QuoRaw(20), } stableStakeMsgServer := stablekeeper.NewMsgServerImpl(suite.app.StablestakeKeeper) _, err = stableStakeMsgServer.Bond(suite.ctx, &msgBond) - if err != nil { - panic(err) - } + suite.Require().NoError(err) msgBond.Creator = addresses[2].String() _, err = stableStakeMsgServer.Bond(suite.ctx, &msgBond) - if err != nil { - panic(err) - } + suite.Require().NoError(err) if openPosition { openMsg := &types.MsgOpen{ diff --git a/x/leveragelp/keeper/position_close.go b/x/leveragelp/keeper/position_close.go index c4fd21d1e..eabfadabb 100644 --- a/x/leveragelp/keeper/position_close.go +++ b/x/leveragelp/keeper/position_close.go @@ -75,7 +75,10 @@ func (k Keeper) ForceCloseLong(ctx sdk.Context, position types.Position, pool ty position.LeveragedLpAmount = position.LeveragedLpAmount.Sub(lpAmount) if position.LeveragedLpAmount.IsZero() { // As we have already exited the pool, we need to delete the position - k.masterchefKeeper.ClaimRewards(ctx, position.GetPositionAddress(), []uint64{position.AmmPoolId}, positionOwner) + err = k.masterchefKeeper.ClaimRewards(ctx, position.GetPositionAddress(), []uint64{position.AmmPoolId}, positionOwner) + if err != nil { + return math.Int{}, err + } err = k.DestroyPosition(ctx, positionOwner, position.Id) if err != nil { return sdk.ZeroInt(), err diff --git a/x/leveragelp/keeper/position_open.go b/x/leveragelp/keeper/position_open.go index ee4fc75a1..369ec6f53 100644 --- a/x/leveragelp/keeper/position_open.go +++ b/x/leveragelp/keeper/position_open.go @@ -43,7 +43,12 @@ func (k Keeper) OpenConsolidate(ctx sdk.Context, position *types.Position, msg * } if k.hooks != nil { - err := k.hooks.AfterLeverageLpPositionOpenConsolidate(ctx, sdk.MustAccAddressFromBech32(msg.Creator)) + // ammPool will have updated values for opening position + ammPool, found := k.amm.GetPool(ctx, msg.AmmPoolId) + if !found { + return nil, errorsmod.Wrap(types.ErrPoolDoesNotExist, fmt.Sprintf("poolId: %d", msg.AmmPoolId)) + } + err = k.hooks.AfterLeverageLpPositionOpenConsolidate(ctx, sdk.MustAccAddressFromBech32(msg.Creator), ammPool) if err != nil { return nil, err } diff --git a/x/leveragelp/keeper/position_open_test.go b/x/leveragelp/keeper/position_open_test.go index 55e33b736..82b358884 100644 --- a/x/leveragelp/keeper/position_open_test.go +++ b/x/leveragelp/keeper/position_open_test.go @@ -1,10 +1,13 @@ package keeper_test import ( + "cosmossdk.io/math" "github.com/cometbft/cometbft/crypto/ed25519" sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" ammtypes "github.com/elys-network/elys/x/amm/types" + "github.com/elys-network/elys/x/leveragelp/keeper" "github.com/elys-network/elys/x/leveragelp/types" stablestakekeeper "github.com/elys-network/elys/x/stablestake/keeper" stablestaketypes "github.com/elys-network/elys/x/stablestake/types" @@ -16,12 +19,6 @@ func (suite KeeperTestSuite) TestOpenLong() { addr := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address()) poolAddr := ammtypes.NewPoolAddress(uint64(1)) treasuryAddr := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address()) - pool := types.Pool{ - AmmPoolId: 1, - Health: sdk.ZeroDec(), - LeveragedLpAmount: sdk.ZeroInt(), - LeverageMax: sdk.OneDec().MulInt64(10), - } poolInit := sdk.Coins{sdk.NewInt64Coin("uusdc", 100000), sdk.NewInt64Coin("uusdt", 100000)} err := suite.app.BankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, poolInit) @@ -57,7 +54,17 @@ func (suite KeeperTestSuite) TestOpenLong() { }, TotalWeight: sdk.NewInt(20), }) - k.SetPool(suite.ctx, pool) + suite.Require().NoError(err) + enablePoolMsg := types.MsgAddPool{ + Authority: authtypes.NewModuleAddress("gov").String(), + Pool: types.AddPool{ + AmmPoolId: 1, + LeverageMax: math.LegacyNewDec(10), + }, + } + msgServer := keeper.NewMsgServerImpl(*suite.app.LeveragelpKeeper) + _, err = msgServer.AddPool(suite.ctx, &enablePoolMsg) + suite.Require().NoError(err) suite.app.AmmKeeper.SetDenomLiquidity(suite.ctx, ammtypes.DenomLiquidity{ Denom: "uusdc", Liquidity: sdk.NewInt(100000), diff --git a/x/leveragelp/migrations/v16_migration.go b/x/leveragelp/migrations/v16_migration.go index 151ddd45b..f13408634 100644 --- a/x/leveragelp/migrations/v16_migration.go +++ b/x/leveragelp/migrations/v16_migration.go @@ -5,22 +5,5 @@ import ( ) func (m Migrator) V16Migration(ctx sdk.Context) error { - allPools := m.keeper.GetAllPools(ctx) - - for _, pool := range allPools { - hooks := m.keeper.GetHooks() - - if hooks != nil { - ammPool, err := m.keeper.GetAmmPool(ctx, pool.AmmPoolId) - if err != nil { - return err - } - err = hooks.AfterEnablingPool(ctx, ammPool) - if err != nil { - return err - } - } - } - return nil } diff --git a/x/leveragelp/types/hooks.go b/x/leveragelp/types/hooks.go index 4d20d6487..711fd90c3 100644 --- a/x/leveragelp/types/hooks.go +++ b/x/leveragelp/types/hooks.go @@ -11,13 +11,13 @@ type LeverageLpHooks interface { AfterDisablingPool(ctx sdk.Context, ammPool ammtypes.Pool) error // AfterLeverageLpPositionOpen is called after Open position. - AfterLeverageLpPositionOpen(ctx sdk.Context, sender sdk.AccAddress) error + AfterLeverageLpPositionOpen(ctx sdk.Context, sender sdk.AccAddress, ammPool ammtypes.Pool) error // AfterLeverageLpPositionClose is called after a position gets closed. - AfterLeverageLpPositionClose(ctx sdk.Context, sender sdk.AccAddress) error + AfterLeverageLpPositionClose(ctx sdk.Context, sender sdk.AccAddress, ammPool ammtypes.Pool) error // AfterLeverageLpPositionConsolidate is called after a position gets closed. - AfterLeverageLpPositionOpenConsolidate(ctx sdk.Context, sender sdk.AccAddress) error + AfterLeverageLpPositionOpenConsolidate(ctx sdk.Context, sender sdk.AccAddress, ammPool ammtypes.Pool) error } var _ LeverageLpHooks = MultiLeverageLpHooks{} @@ -49,9 +49,9 @@ func (h MultiLeverageLpHooks) AfterDisablingPool(ctx sdk.Context, ammPool ammtyp return nil } -func (h MultiLeverageLpHooks) AfterLeverageLpPositionOpen(ctx sdk.Context, sender sdk.AccAddress) error { +func (h MultiLeverageLpHooks) AfterLeverageLpPositionOpen(ctx sdk.Context, sender sdk.AccAddress, ammPool ammtypes.Pool) error { for i := range h { - err := h[i].AfterLeverageLpPositionOpen(ctx, sender) + err := h[i].AfterLeverageLpPositionOpen(ctx, sender, ammPool) if err != nil { return err } @@ -59,9 +59,9 @@ func (h MultiLeverageLpHooks) AfterLeverageLpPositionOpen(ctx sdk.Context, sende return nil } -func (h MultiLeverageLpHooks) AfterLeverageLpPositionClose(ctx sdk.Context, sender sdk.AccAddress) error { +func (h MultiLeverageLpHooks) AfterLeverageLpPositionClose(ctx sdk.Context, sender sdk.AccAddress, ammPool ammtypes.Pool) error { for i := range h { - err := h[i].AfterLeverageLpPositionClose(ctx, sender) + err := h[i].AfterLeverageLpPositionClose(ctx, sender, ammPool) if err != nil { return err } @@ -69,9 +69,9 @@ func (h MultiLeverageLpHooks) AfterLeverageLpPositionClose(ctx sdk.Context, send return nil } -func (h MultiLeverageLpHooks) AfterLeverageLpPositionOpenConsolidate(ctx sdk.Context, sender sdk.AccAddress) error { +func (h MultiLeverageLpHooks) AfterLeverageLpPositionOpenConsolidate(ctx sdk.Context, sender sdk.AccAddress, ammPool ammtypes.Pool) error { for i := range h { - err := h[i].AfterLeverageLpPositionOpenConsolidate(ctx, sender) + err := h[i].AfterLeverageLpPositionOpenConsolidate(ctx, sender, ammPool) if err != nil { return err } diff --git a/x/perpetual/keeper/calc_total_liabilities_test.go b/x/perpetual/keeper/calc_total_liabilities_test.go index b2d149af8..9553a81a1 100644 --- a/x/perpetual/keeper/calc_total_liabilities_test.go +++ b/x/perpetual/keeper/calc_total_liabilities_test.go @@ -63,7 +63,7 @@ func (suite PerpetualKeeperTestSuite) TestCalcTotalLiabilities() { ptypes.ATOM, func() { amount := sdk.OneInt().MulRaw(1000_000) - ammPool = suite.SetAndGetAmmPool(addr[0], poolId, true, sdk.ZeroDec(), sdk.ZeroDec(), ptypes.ATOM, amount, amount) + ammPool = suite.CreateNewAmmPool(addr[0], true, sdk.ZeroDec(), sdk.ZeroDec(), ptypes.ATOM, amount, amount) poolAsset.Liabilities = amount.MulRaw(100) }, func(totalLiabilities sdk.Int) { diff --git a/x/perpetual/keeper/hooks_amm.go b/x/perpetual/keeper/hooks_amm.go index ff1732bc4..6ac2f3abb 100644 --- a/x/perpetual/keeper/hooks_amm.go +++ b/x/perpetual/keeper/hooks_amm.go @@ -30,7 +30,7 @@ func (h AmmHooks) AfterPoolCreated(ctx sdk.Context, sender sdk.AccAddress, pool func (h AmmHooks) AfterJoinPool(ctx sdk.Context, sender sdk.AccAddress, ammPool ammtypes.Pool, enterCoins sdk.Coins, shareOutAmount math.Int) error { perpetualPool, found := h.k.GetPool(ctx, ammPool.PoolId) if !found { - // It is possible no position have been open for this pool + // It is possible that this pool haven't been enabled return nil } @@ -39,7 +39,7 @@ func (h AmmHooks) AfterJoinPool(ctx sdk.Context, sender sdk.AccAddress, ammPool return err } - err = h.k.CheckLowPoolHealth(ctx, ammPool.PoolId) + err = h.k.CheckLowPoolHealthAndMinimumCustody(ctx, ammPool.PoolId) if err != nil { return err } @@ -52,7 +52,7 @@ func (h AmmHooks) AfterJoinPool(ctx sdk.Context, sender sdk.AccAddress, ammPool func (h AmmHooks) AfterExitPool(ctx sdk.Context, sender sdk.AccAddress, ammPool ammtypes.Pool, shareInAmount math.Int, exitCoins sdk.Coins) error { perpetualPool, found := h.k.GetPool(ctx, ammPool.PoolId) if !found { - // It is possible no position have been open for this pool + // It is possible that this pool haven't been enabled return nil } @@ -61,7 +61,7 @@ func (h AmmHooks) AfterExitPool(ctx sdk.Context, sender sdk.AccAddress, ammPool return err } - err = h.k.CheckLowPoolHealth(ctx, ammPool.PoolId) + err = h.k.CheckLowPoolHealthAndMinimumCustody(ctx, ammPool.PoolId) if err != nil { return err } @@ -73,7 +73,7 @@ func (h AmmHooks) AfterExitPool(ctx sdk.Context, sender sdk.AccAddress, ammPool func (h AmmHooks) AfterSwap(ctx sdk.Context, sender sdk.AccAddress, ammPool ammtypes.Pool, input sdk.Coins, output sdk.Coins) error { perpetualPool, found := h.k.GetPool(ctx, ammPool.PoolId) if !found { - // It is possible no position have been open for this pool + // It is possible that this pool haven't been enabled return nil } @@ -82,7 +82,7 @@ func (h AmmHooks) AfterSwap(ctx sdk.Context, sender sdk.AccAddress, ammPool ammt return err } - err = h.k.CheckLowPoolHealth(ctx, ammPool.PoolId) + err = h.k.CheckLowPoolHealthAndMinimumCustody(ctx, ammPool.PoolId) if err != nil { return err } diff --git a/x/perpetual/keeper/hooks_leveragelp.go b/x/perpetual/keeper/hooks_leveragelp.go index f93fabb60..4b245df76 100644 --- a/x/perpetual/keeper/hooks_leveragelp.go +++ b/x/perpetual/keeper/hooks_leveragelp.go @@ -1,6 +1,7 @@ package keeper import ( + "fmt" sdk "github.com/cosmos/cosmos-sdk/types" ammtypes "github.com/elys-network/elys/x/amm/types" leveragelptypes "github.com/elys-network/elys/x/leveragelp/types" @@ -40,14 +41,56 @@ func (h LeverageLpHooks) AfterDisablingPool(ctx sdk.Context, ammPool ammtypes.Po return h.k.OnLeverageLpDisablePool(ctx, ammPool) } -func (h LeverageLpHooks) AfterLeverageLpPositionOpen(ctx sdk.Context, sender sdk.AccAddress) error { +func (h LeverageLpHooks) AfterLeverageLpPositionOpen(ctx sdk.Context, sender sdk.AccAddress, ammPool ammtypes.Pool) error { + perpetualPool, found := h.k.GetPool(ctx, ammPool.PoolId) + if !found { + return fmt.Errorf("perpetual pool (id: %d) not found", ammPool.PoolId) + } + + err := h.k.UpdatePoolHealth(ctx, &perpetualPool) + if err != nil { + return err + } + + err = h.k.CheckLowPoolHealthAndMinimumCustody(ctx, ammPool.PoolId) + if err != nil { + return err + } return nil } -func (h LeverageLpHooks) AfterLeverageLpPositionClose(ctx sdk.Context, sender sdk.AccAddress) error { +func (h LeverageLpHooks) AfterLeverageLpPositionClose(ctx sdk.Context, sender sdk.AccAddress, ammPool ammtypes.Pool) error { + perpetualPool, found := h.k.GetPool(ctx, ammPool.PoolId) + if !found { + return fmt.Errorf("perpetual pool (id: %d) not found", ammPool.PoolId) + } + + err := h.k.UpdatePoolHealth(ctx, &perpetualPool) + if err != nil { + return err + } + + err = h.k.CheckLowPoolHealthAndMinimumCustody(ctx, ammPool.PoolId) + if err != nil { + return err + } return nil } -func (h LeverageLpHooks) AfterLeverageLpPositionOpenConsolidate(ctx sdk.Context, sender sdk.AccAddress) error { +func (h LeverageLpHooks) AfterLeverageLpPositionOpenConsolidate(ctx sdk.Context, sender sdk.AccAddress, ammPool ammtypes.Pool) error { + perpetualPool, found := h.k.GetPool(ctx, ammPool.PoolId) + if !found { + return fmt.Errorf("perpetual pool (id: %d) not found", ammPool.PoolId) + } + + err := h.k.UpdatePoolHealth(ctx, &perpetualPool) + if err != nil { + return err + } + + err = h.k.CheckLowPoolHealthAndMinimumCustody(ctx, ammPool.PoolId) + if err != nil { + return err + } return nil } diff --git a/x/perpetual/keeper/keeper_test.go b/x/perpetual/keeper/keeper_test.go index eaa4dd8b5..a5ef68252 100644 --- a/x/perpetual/keeper/keeper_test.go +++ b/x/perpetual/keeper/keeper_test.go @@ -82,12 +82,12 @@ func (suite *PerpetualKeeperTestSuite) ResetSuite() { suite.SetupTest() } -func (suite *PerpetualKeeperTestSuite) ResetAndSetSuite(addr []sdk.AccAddress, poolId uint64, useOracle bool, baseTokenAmount, assetAmount sdk.Int) (ammtypes.Pool, types.Pool) { +func (suite *PerpetualKeeperTestSuite) ResetAndSetSuite(addr []sdk.AccAddress, useOracle bool, baseTokenAmount, assetAmount sdk.Int) (ammtypes.Pool, types.Pool) { suite.ResetSuite() suite.SetupCoinPrices() suite.AddAccounts(len(addr), addr) poolCreator := addr[0] - ammPool := suite.SetAndGetAmmPool(poolCreator, poolId, useOracle, sdk.ZeroDec(), sdk.ZeroDec(), ptypes.ATOM, baseTokenAmount, assetAmount) + ammPool := suite.CreateNewAmmPool(poolCreator, useOracle, sdk.ZeroDec(), sdk.ZeroDec(), ptypes.ATOM, baseTokenAmount, assetAmount) pool := types.NewPool(ammPool) suite.app.PerpetualKeeper.SetPool(suite.ctx, pool) params := suite.app.PerpetualKeeper.GetParams(suite.ctx) @@ -184,7 +184,7 @@ func (suite *PerpetualKeeperTestSuite) AddAccounts(n int, given []sdk.AccAddress return addresses } -func (suite *PerpetualKeeperTestSuite) SetAndGetAmmPool(creator sdk.AccAddress, poolId uint64, useOracle bool, swapFee, exitFee sdk.Dec, asset2 string, baseTokenAmount, assetAmount sdk.Int) ammtypes.Pool { +func (suite *PerpetualKeeperTestSuite) CreateNewAmmPool(creator sdk.AccAddress, useOracle bool, swapFee, exitFee sdk.Dec, asset2 string, baseTokenAmount, assetAmount sdk.Int) ammtypes.Pool { poolAssets := []ammtypes.PoolAsset{ { Token: sdk.NewCoin(ptypes.BaseCurrency, baseTokenAmount), @@ -198,30 +198,28 @@ func (suite *PerpetualKeeperTestSuite) SetAndGetAmmPool(creator sdk.AccAddress, sort.Slice(poolAssets, func(i, j int) bool { return strings.Compare(poolAssets[i].Token.Denom, poolAssets[j].Token.Denom) <= 0 }) - ammPool := ammtypes.Pool{ - PoolId: poolId, - Address: ammtypes.NewPoolAddress(poolId).String(), - RebalanceTreasury: ammtypes.NewPoolRebalanceTreasury(poolId).String(), - PoolParams: ammtypes.PoolParams{ - UseOracle: useOracle, - ExternalLiquidityRatio: sdk.NewDec(2), - WeightBreakingFeeMultiplier: sdk.ZeroDec(), - WeightBreakingFeeExponent: sdk.NewDecWithPrec(25, 1), // 2.5 - WeightRecoveryFeePortion: sdk.NewDecWithPrec(10, 2), // 10% - ThresholdWeightDifference: sdk.ZeroDec(), - SwapFee: swapFee, - ExitFee: exitFee, - FeeDenom: ptypes.BaseCurrency, - }, - TotalShares: sdk.NewCoin("pool/1", sdk.NewInt(100)), - PoolAssets: poolAssets, - TotalWeight: sdk.ZeroInt(), + poolParams := ammtypes.PoolParams{ + UseOracle: useOracle, + ExternalLiquidityRatio: sdk.NewDec(2), + WeightBreakingFeeMultiplier: sdk.ZeroDec(), + WeightBreakingFeeExponent: sdk.NewDecWithPrec(25, 1), // 2.5 + WeightRecoveryFeePortion: sdk.NewDecWithPrec(10, 2), // 10% + ThresholdWeightDifference: sdk.ZeroDec(), + SwapFee: swapFee, + ExitFee: exitFee, + FeeDenom: ptypes.BaseCurrency, } - suite.app.AmmKeeper.SetPool(suite.ctx, ammPool) + createPoolMsg := &ammtypes.MsgCreatePool{ + Sender: creator.String(), + PoolParams: &poolParams, + PoolAssets: poolAssets, + } - err := suite.app.BankKeeper.SendCoins(suite.ctx, creator, ammtypes.NewPoolAddress(poolId), sdk.NewCoins(sdk.NewCoin(ptypes.BaseCurrency, baseTokenAmount), sdk.NewCoin(asset2, assetAmount))) + poolId, err := suite.app.AmmKeeper.CreatePool(suite.ctx, createPoolMsg) suite.Require().NoError(err) + ammPool, _ := suite.app.AmmKeeper.GetPool(suite.ctx, poolId) + return ammPool } diff --git a/x/perpetual/keeper/open.go b/x/perpetual/keeper/open.go index fd0b965a0..0234a9619 100644 --- a/x/perpetual/keeper/open.go +++ b/x/perpetual/keeper/open.go @@ -93,7 +93,7 @@ func (k Keeper) Open(ctx sdk.Context, msg *types.MsgOpen, isBroker bool) (*types return nil, errorsmod.Wrap(types.ErrPoolDoesNotExist, fmt.Sprintf("poolId: %d", poolId)) } - if err = k.CheckLowPoolHealth(ctx, poolId); err != nil { + if err = k.CheckLowPoolHealthAndMinimumCustody(ctx, poolId); err != nil { return nil, err } @@ -112,7 +112,7 @@ func (k Keeper) Open(ctx sdk.Context, msg *types.MsgOpen, isBroker bool) (*types return k.OpenConsolidate(ctx, existingMtp, mtp, msg, baseCurrency) } - if err = k.CheckLowPoolHealth(ctx, poolId); err != nil { + if err = k.CheckLowPoolHealthAndMinimumCustody(ctx, poolId); err != nil { return nil, err } diff --git a/x/perpetual/keeper/open_consolidate.go b/x/perpetual/keeper/open_consolidate.go index baba72a35..1c59c635e 100644 --- a/x/perpetual/keeper/open_consolidate.go +++ b/x/perpetual/keeper/open_consolidate.go @@ -72,7 +72,7 @@ func (k Keeper) OpenConsolidate(ctx sdk.Context, existingMtp *types.MTP, newMtp } } - if err = k.CheckLowPoolHealth(ctx, poolId); err != nil { + if err = k.CheckLowPoolHealthAndMinimumCustody(ctx, poolId); err != nil { return nil, err } diff --git a/x/perpetual/keeper/open_long_test.go b/x/perpetual/keeper/open_long_test.go index c7999ba9e..6afa7c629 100644 --- a/x/perpetual/keeper/open_long_test.go +++ b/x/perpetual/keeper/open_long_test.go @@ -51,7 +51,8 @@ func (suite *PerpetualKeeperTestSuite) TestOpenLong() { "pool does not exist", false, func() { - ammPool = suite.SetAndGetAmmPool(poolCreator, poolId, true, sdk.ZeroDec(), sdk.ZeroDec(), ptypes.ATOM, amount.MulRaw(10), amount.MulRaw(10)) + ammPool = suite.CreateNewAmmPool(poolCreator, true, sdk.ZeroDec(), sdk.ZeroDec(), ptypes.ATOM, amount.MulRaw(10), amount.MulRaw(10)) + poolId = ammPool.PoolId enablePoolMsg := leveragelpmoduletypes.MsgAddPool{ Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), Pool: leveragelpmoduletypes.AddPool{ @@ -155,7 +156,7 @@ func (suite *PerpetualKeeperTestSuite) TestOpenLong() { false, func() { - suite.ResetAndSetSuite(addr, poolId, true, amount.MulRaw(1000), sdk.NewInt(2)) + suite.ResetAndSetSuite(addr, true, amount.MulRaw(1000), sdk.NewInt(2)) msg.Collateral.Denom = ptypes.BaseCurrency msg.Collateral.Amount = amount diff --git a/x/perpetual/keeper/open_short_test.go b/x/perpetual/keeper/open_short_test.go index a482dd7ca..66521c692 100644 --- a/x/perpetual/keeper/open_short_test.go +++ b/x/perpetual/keeper/open_short_test.go @@ -54,7 +54,8 @@ func (suite *PerpetualKeeperTestSuite) TestOpenShort() { "pool does not exist", false, func() { - ammPool = suite.SetAndGetAmmPool(poolCreator, poolId, true, sdk.ZeroDec(), sdk.ZeroDec(), ptypes.ATOM, amount.MulRaw(10), amount.MulRaw(10)) + ammPool = suite.CreateNewAmmPool(poolCreator, true, sdk.ZeroDec(), sdk.ZeroDec(), ptypes.ATOM, amount.MulRaw(10), amount.MulRaw(10)) + poolId = ammPool.PoolId enablePoolMsg := leveragelpmoduletypes.MsgAddPool{ Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), Pool: leveragelpmoduletypes.AddPool{ @@ -150,8 +151,7 @@ func (suite *PerpetualKeeperTestSuite) TestOpenShort() { "amount too low", false, func() { - suite.ResetAndSetSuite(addr, poolId, true, amount.MulRaw(1000), sdk.NewInt(2)) - + suite.ResetAndSetSuite(addr, true, amount.MulRaw(1000), sdk.NewInt(2)) msg.Collateral.Denom = ptypes.BaseCurrency msg.Collateral.Amount = amount msg.TradingAsset = ptypes.ATOM diff --git a/x/perpetual/keeper/open_test.go b/x/perpetual/keeper/open_test.go index 536b06227..3ac40cb4e 100644 --- a/x/perpetual/keeper/open_test.go +++ b/x/perpetual/keeper/open_test.go @@ -74,7 +74,8 @@ func (suite *PerpetualKeeperTestSuite) TestOpen() { suite.app.PerpetualKeeper.WhitelistAddress(suite.ctx, account) } - ammPool = suite.SetAndGetAmmPool(poolCreator, poolId, true, sdk.ZeroDec(), sdk.ZeroDec(), ptypes.ATOM, amount.MulRaw(10), amount.MulRaw(10)) + ammPool = suite.CreateNewAmmPool(poolCreator, true, sdk.ZeroDec(), sdk.ZeroDec(), ptypes.ATOM, amount.MulRaw(10), amount.MulRaw(10)) + poolId = ammPool.PoolId enablePoolMsg := leveragelpmoduletypes.MsgAddPool{ Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), Pool: leveragelpmoduletypes.AddPool{ @@ -179,7 +180,7 @@ func (suite *PerpetualKeeperTestSuite) TestOpen() { "negative pool amount after swap", false, func() { - suite.ResetAndSetSuite(addr, 1, true, amount.MulRaw(1000), sdk.NewInt(2)) + suite.ResetAndSetSuite(addr, true, amount.MulRaw(1000), sdk.NewInt(2)) msg.Creator = positionCreator.String() msg.Collateral.Denom = ptypes.BaseCurrency diff --git a/x/perpetual/keeper/pool_health.go b/x/perpetual/keeper/pool_health.go index b3e0e08b0..439c8e35a 100644 --- a/x/perpetual/keeper/pool_health.go +++ b/x/perpetual/keeper/pool_health.go @@ -11,7 +11,7 @@ import ( "github.com/elys-network/elys/x/perpetual/types" ) -func (k Keeper) CheckLowPoolHealth(ctx sdk.Context, poolId uint64) error { +func (k Keeper) CheckLowPoolHealthAndMinimumCustody(ctx sdk.Context, poolId uint64) error { pool, found := k.GetPool(ctx, poolId) if !found { return errorsmod.Wrapf(types.ErrPoolDoesNotExist, "pool id %d", poolId) diff --git a/x/perpetual/keeper/pool_health_test.go b/x/perpetual/keeper/pool_health_test.go index c53931715..e45281e10 100644 --- a/x/perpetual/keeper/pool_health_test.go +++ b/x/perpetual/keeper/pool_health_test.go @@ -15,7 +15,8 @@ func (suite *PerpetualKeeperTestSuite) TestCheckLowPoolHealth() { addr := suite.AddAccounts(10, nil) amount := sdk.NewInt(1000) poolCreator := addr[0] - ammPool := suite.SetAndGetAmmPool(poolCreator, 1, true, sdk.ZeroDec(), sdk.ZeroDec(), ptypes.ATOM, amount.MulRaw(10), amount.MulRaw(10)) + suite.SetupCoinPrices() + ammPool := suite.CreateNewAmmPool(poolCreator, true, sdk.ZeroDec(), sdk.ZeroDec(), ptypes.ATOM, amount.MulRaw(10), amount.MulRaw(10)) testCases := []struct { name string expectErrMsg string @@ -42,7 +43,7 @@ func (suite *PerpetualKeeperTestSuite) TestCheckLowPoolHealth() { for _, tc := range testCases { suite.Run(tc.name, func() { tc.prerequisiteFunction() - err = suite.app.PerpetualKeeper.CheckLowPoolHealth(suite.ctx, 1) + err = suite.app.PerpetualKeeper.CheckLowPoolHealthAndMinimumCustody(suite.ctx, 1) if tc.expectErrMsg != "" { suite.Require().Error(err) suite.Require().Contains(err.Error(), tc.expectErrMsg) diff --git a/x/perpetual/keeper/query_pool.go b/x/perpetual/keeper/query_pool.go index f175a6d19..70b783b98 100644 --- a/x/perpetual/keeper/query_pool.go +++ b/x/perpetual/keeper/query_pool.go @@ -33,12 +33,13 @@ func (k Keeper) Pools(goCtx context.Context, req *types.QueryAllPoolRequest) (*t return types.ErrPoolDoesNotExist } - totalLiabilities, err := k.GetPoolTotalBaseCurrencyLiabilities(ctx, pool) - if err != nil { - return err - } - + // TODO remove this if condition. All pools in perpetual must use oracle. if ammPool.PoolParams.UseOracle { + totalLiabilities, err := k.GetPoolTotalBaseCurrencyLiabilities(ctx, pool) + if err != nil { + return err + } + longRate, shortRate := k.GetFundingPaymentRates(ctx, pool) pools = append(pools, types.PoolResponse{ AmmPoolId: pool.AmmPoolId, diff --git a/x/perpetual/types/types.go b/x/perpetual/types/types.go index be5ea09bf..27207b407 100644 --- a/x/perpetual/types/types.go +++ b/x/perpetual/types/types.go @@ -74,7 +74,10 @@ func (mtp *MTP) GetAndSetOpenPrice() { if mtp.Position == Position_LONG { if mtp.CollateralAsset == mtp.TradingAsset { // open price = liabilities / (custody - collateral) - openPrice = mtp.Liabilities.ToLegacyDec().Quo(mtp.Custody.Sub(mtp.Collateral).ToLegacyDec()) + denominator := mtp.Custody.Sub(mtp.Collateral).ToLegacyDec() + if !denominator.IsZero() { + openPrice = mtp.Liabilities.ToLegacyDec().Quo(denominator) + } } else { // open price = (collateral + liabilities) / custody openPrice = (mtp.Collateral.Add(mtp.Liabilities)).ToLegacyDec().Quo(mtp.Custody.ToLegacyDec()) diff --git a/x/tier/keeper/hooks_leveragelp.go b/x/tier/keeper/hooks_leveragelp.go index 63ac25a5b..ba9d7dcd0 100644 --- a/x/tier/keeper/hooks_leveragelp.go +++ b/x/tier/keeper/hooks_leveragelp.go @@ -25,17 +25,17 @@ func (h LeverageLpHooks) AfterDisablingPool(_ sdk.Context, _ ammtypes.Pool) erro return nil } -func (h LeverageLpHooks) AfterLeverageLpPositionOpen(ctx sdk.Context, sender sdk.AccAddress) error { +func (h LeverageLpHooks) AfterLeverageLpPositionOpen(ctx sdk.Context, sender sdk.AccAddress, _ ammtypes.Pool) error { h.k.RetrieveAllPortfolio(ctx, sender) return nil } -func (h LeverageLpHooks) AfterLeverageLpPositionClose(ctx sdk.Context, sender sdk.AccAddress) error { +func (h LeverageLpHooks) AfterLeverageLpPositionClose(ctx sdk.Context, sender sdk.AccAddress, _ ammtypes.Pool) error { h.k.RetrieveAllPortfolio(ctx, sender) return nil } -func (h LeverageLpHooks) AfterLeverageLpPositionOpenConsolidate(ctx sdk.Context, sender sdk.AccAddress) error { +func (h LeverageLpHooks) AfterLeverageLpPositionOpenConsolidate(ctx sdk.Context, sender sdk.AccAddress, _ ammtypes.Pool) error { h.k.RetrieveAllPortfolio(ctx, sender) return nil }