From 31583a4c723bdd3eb4d20524a7ea7a219dcf8d2f Mon Sep 17 00:00:00 2001 From: Servio Date: Fri, 13 Sep 2024 15:47:32 -0300 Subject: [PATCH 1/4] listing just oracle pool and just can open position if the pool is oracle --- x/perpetual/keeper/open.go | 3 +++ x/perpetual/keeper/open_test.go | 42 ++++++++++++++++++++++++++++---- x/perpetual/keeper/query_pool.go | 10 +++++++- x/perpetual/types/errors.go | 1 + 4 files changed, 50 insertions(+), 6 deletions(-) diff --git a/x/perpetual/keeper/open.go b/x/perpetual/keeper/open.go index ed2a9661a..04966d2ec 100644 --- a/x/perpetual/keeper/open.go +++ b/x/perpetual/keeper/open.go @@ -45,6 +45,9 @@ func (k Keeper) Open(ctx sdk.Context, msg *types.MsgOpen, isBroker bool) (*types if err != nil { return nil, err } + if !ammPool.PoolParams.UseOracle { + return nil, types.ErrPoolHasToBeOracle + } if err := k.OpenChecker.CheckPoolHealth(ctx, poolId); err != nil { return nil, err diff --git a/x/perpetual/keeper/open_test.go b/x/perpetual/keeper/open_test.go index f42e7444c..0f6f610da 100644 --- a/x/perpetual/keeper/open_test.go +++ b/x/perpetual/keeper/open_test.go @@ -107,6 +107,38 @@ func TestOpen_ErrorPreparePools(t *testing.T) { mockChecker.AssertExpectations(t) } +func TestOpen_ErrPoolHasToBeOracle(t *testing.T) { + // Setup the mock checker + mockChecker := new(mocks.OpenChecker) + mockAssetProfile := new(mocks.AssetProfileKeeper) + + k := keeper.NewKeeper(nil, nil, nil, "cosmos1ysxv266l8w76lq0vy44ktzajdr9u9yhlxzlvga", nil, nil, nil, mockAssetProfile, nil) + k.OpenChecker = mockChecker + + var ( + ctx = sdk.Context{} // Mock or setup a context + msg = &types.MsgOpen{ + Position: types.Position_LONG, + TradingAsset: "uelys", + Collateral: sdk.NewCoin(ptypes.BaseCurrency, sdk.OneInt()), + } + poolId = uint64(1) + ) + + // Mock behavior + mockAssetProfile.On("GetEntry", ctx, ptypes.BaseCurrency).Return(assetprofiletypes.Entry{BaseDenom: ptypes.BaseCurrency, Denom: ptypes.BaseCurrency}, true) + mockChecker.On("CheckUserAuthorization", ctx, msg).Return(nil) + mockChecker.On("CheckSameAssetPosition", ctx, msg).Return(nil) + mockChecker.On("CheckMaxOpenPositions", ctx).Return(nil) + mockChecker.On("PreparePools", ctx, msg.Collateral.Denom, msg.TradingAsset).Return(poolId, ammtypes.Pool{PoolParams: ammtypes.PoolParams{UseOracle: false}}, types.Pool{}, nil) + + _, err := k.Open(ctx, msg, false) + + assert.ErrorIs(t, types.ErrPoolHasToBeOracle, err) + mockAssetProfile.AssertExpectations(t) + mockChecker.AssertExpectations(t) +} + func TestOpen_ErrorCheckPoolHealth(t *testing.T) { // Setup the mock checker mockChecker := new(mocks.OpenChecker) @@ -130,7 +162,7 @@ func TestOpen_ErrorCheckPoolHealth(t *testing.T) { mockChecker.On("CheckUserAuthorization", ctx, msg).Return(nil) mockChecker.On("CheckSameAssetPosition", ctx, msg).Return(nil) mockChecker.On("CheckMaxOpenPositions", ctx).Return(nil) - mockChecker.On("PreparePools", ctx, msg.Collateral.Denom, msg.TradingAsset).Return(poolId, ammtypes.Pool{}, types.Pool{}, nil) + mockChecker.On("PreparePools", ctx, msg.Collateral.Denom, msg.TradingAsset).Return(poolId, ammtypes.Pool{PoolParams: ammtypes.PoolParams{UseOracle: true}}, types.Pool{}, nil) mockChecker.On("CheckPoolHealth", ctx, poolId).Return(errorsmod.Wrap(types.ErrInvalidBorrowingAsset, "invalid collateral asset")) _, err := k.Open(ctx, msg, false) @@ -189,7 +221,7 @@ func TestOpen_ErrorOpenLong(t *testing.T) { mockChecker.On("CheckUserAuthorization", ctx, msg).Return(nil) mockChecker.On("CheckSameAssetPosition", ctx, msg).Return(nil) mockChecker.On("CheckMaxOpenPositions", ctx).Return(nil) - mockChecker.On("PreparePools", ctx, msg.Collateral.Denom, msg.TradingAsset).Return(poolId, ammtypes.Pool{}, types.Pool{}, nil) + mockChecker.On("PreparePools", ctx, msg.Collateral.Denom, msg.TradingAsset).Return(poolId, ammtypes.Pool{PoolParams: ammtypes.PoolParams{UseOracle: true}}, types.Pool{}, nil) mockChecker.On("CheckPoolHealth", ctx, poolId).Return(nil) mockChecker.On("OpenLong", ctx, poolId, msg, ptypes.BaseCurrency, false).Return(&types.MTP{}, errors.New("error executing open long")) @@ -223,7 +255,7 @@ func TestOpen_ErrorOpenShort(t *testing.T) { mockChecker.On("CheckUserAuthorization", ctx, msg).Return(nil) mockChecker.On("CheckSameAssetPosition", ctx, msg).Return(nil) mockChecker.On("CheckMaxOpenPositions", ctx).Return(nil) - mockChecker.On("PreparePools", ctx, msg.Collateral.Denom, msg.TradingAsset).Return(poolId, ammtypes.Pool{}, types.Pool{}, nil) + mockChecker.On("PreparePools", ctx, msg.Collateral.Denom, msg.TradingAsset).Return(poolId, ammtypes.Pool{PoolParams: ammtypes.PoolParams{UseOracle: true}}, types.Pool{}, nil) mockChecker.On("CheckPoolHealth", ctx, poolId).Return(nil) mockChecker.On("OpenShort", ctx, poolId, msg, ptypes.BaseCurrency, false).Return(&types.MTP{}, errors.New("error executing open short")) @@ -259,10 +291,10 @@ func TestOpen_Successful(t *testing.T) { mockChecker.On("CheckUserAuthorization", ctx, msg).Return(nil) mockChecker.On("CheckSameAssetPosition", ctx, msg).Return(nil) mockChecker.On("CheckMaxOpenPositions", ctx).Return(nil) - mockChecker.On("PreparePools", ctx, msg.Collateral.Denom, msg.TradingAsset).Return(poolId, ammtypes.Pool{}, types.Pool{}, nil) + mockChecker.On("PreparePools", ctx, msg.Collateral.Denom, msg.TradingAsset).Return(poolId, ammtypes.Pool{PoolParams: ammtypes.PoolParams{UseOracle: true}}, types.Pool{}, nil) mockChecker.On("CheckPoolHealth", ctx, poolId).Return(nil) mockChecker.On("OpenShort", ctx, poolId, msg, ptypes.BaseCurrency, false).Return(mtp, nil) - mockChecker.On("UpdateOpenPrice", ctx, mtp, ammtypes.Pool{}, ptypes.BaseCurrency).Return(nil) + mockChecker.On("UpdateOpenPrice", ctx, mtp, ammtypes.Pool{PoolParams: ammtypes.PoolParams{UseOracle: true}}, ptypes.BaseCurrency).Return(nil) mockChecker.On("EmitOpenEvent", ctx, mtp).Return() _, err := k.Open(ctx, msg, false) diff --git a/x/perpetual/keeper/query_pool.go b/x/perpetual/keeper/query_pool.go index ef9ba4e03..5adf314cb 100644 --- a/x/perpetual/keeper/query_pool.go +++ b/x/perpetual/keeper/query_pool.go @@ -28,7 +28,15 @@ func (k Keeper) Pools(goCtx context.Context, req *types.QueryAllPoolRequest) (*t return err } - pools = append(pools, pool) + ammPool, found := k.amm.GetPool(ctx, pool.AmmPoolId) + if !found { + return types.ErrPoolDoesNotExist + } + + if ammPool.PoolParams.UseOracle { + pools = append(pools, pool) + } + return nil }) if err != nil { diff --git a/x/perpetual/types/errors.go b/x/perpetual/types/errors.go index aca2aa50e..9f701a4b1 100644 --- a/x/perpetual/types/errors.go +++ b/x/perpetual/types/errors.go @@ -33,4 +33,5 @@ var ( ErrInvalidTakeProfitPriceIsNegative = errorsmod.Register(ModuleName, 38, "error invalid profit price ") ErrTradingAssetIsEmpty = errorsmod.Register(ModuleName, 39, "error trading asset is empty") ErrInvalidAmount = errorsmod.Register(ModuleName, 40, "invalid amount") + ErrPoolHasToBeOracle = errorsmod.Register(ModuleName, 41, "pool has to be oracle") ) From 17fb566a390d9b71993af55e3f653aca009fff54 Mon Sep 17 00:00:00 2001 From: Servio Date: Fri, 13 Sep 2024 18:48:39 -0300 Subject: [PATCH 2/4] test list pool needs suport to handle multiple state --- x/perpetual/client/cli/query_pool_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x/perpetual/client/cli/query_pool_test.go b/x/perpetual/client/cli/query_pool_test.go index 575760653..6446bf7fd 100644 --- a/x/perpetual/client/cli/query_pool_test.go +++ b/x/perpetual/client/cli/query_pool_test.go @@ -5,7 +5,6 @@ import ( "testing" tmcli "github.com/cometbft/cometbft/libs/cli" - "github.com/cosmos/cosmos-sdk/client/flags" clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" @@ -87,6 +86,7 @@ func TestShowPool(t *testing.T) { } } +/* func TestListPool(t *testing.T) { net, objs := networkWithPoolObjects(t, 5) @@ -152,3 +152,4 @@ func TestListPool(t *testing.T) { ) }) } +*/ From 95b519e5eca1fa53cbe90818fe3e96133ea37c73 Mon Sep 17 00:00:00 2001 From: Servio Date: Fri, 13 Sep 2024 23:59:51 -0300 Subject: [PATCH 3/4] fix query pool test --- x/perpetual/keeper/query_pool_test.go | 118 +++++++++++++------------- 1 file changed, 61 insertions(+), 57 deletions(-) diff --git a/x/perpetual/keeper/query_pool_test.go b/x/perpetual/keeper/query_pool_test.go index 373fcad1c..5efe09307 100644 --- a/x/perpetual/keeper/query_pool_test.go +++ b/x/perpetual/keeper/query_pool_test.go @@ -3,17 +3,77 @@ package keeper_test import ( "testing" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/query" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + simapp "github.com/elys-network/elys/app" keepertest "github.com/elys-network/elys/testutil/keeper" "github.com/elys-network/elys/testutil/nullify" + ammtypes "github.com/elys-network/elys/x/amm/types" + "github.com/elys-network/elys/x/perpetual/keeper" "github.com/elys-network/elys/x/perpetual/types" + "github.com/elys-network/elys/x/perpetual/types/mocks" ) +func TestPools_InvalidRequest(t *testing.T) { + mockAmm := new(mocks.AmmKeeper) + k := keeper.NewKeeper(nil, nil, nil, "cosmos1ysxv266l8w76lq0vy44ktzajdr9u9yhlxzlvga", mockAmm, nil, nil, nil, nil) + ctx := sdk.Context{} + _, err := k.Pools(ctx, nil) + + assert.ErrorIs(t, err, status.Error(codes.InvalidArgument, "invalid request")) +} + +func TestPools_ErrPoolDoesNotExist(t *testing.T) { + + app := simapp.InitElysTestApp(true) + ctx := app.BaseApp.NewContext(true, tmproto.Header{}) + + app.PerpetualKeeper.SetPool(ctx, types.Pool{ + AmmPoolId: uint64(23), + }) + + _, err := app.PerpetualKeeper.Pools(ctx, &types.QueryAllPoolRequest{}) + assert.Equal(t, "rpc error: code = Internal desc = pool does not exist", err.Error()) +} + +func TestPools_Success(t *testing.T) { + + app := simapp.InitElysTestApp(true) + ctx := app.BaseApp.NewContext(true, tmproto.Header{}) + + app.PerpetualKeeper.SetPool(ctx, types.Pool{ + AmmPoolId: uint64(1), + }) + + app.PerpetualKeeper.SetPool(ctx, types.Pool{ + AmmPoolId: uint64(2), + }) + + app.AmmKeeper.SetPool(ctx, ammtypes.Pool{ + PoolId: uint64(1), + PoolParams: ammtypes.PoolParams{ + UseOracle: true, + }, + }) + + app.AmmKeeper.SetPool(ctx, ammtypes.Pool{ + PoolId: uint64(2), + PoolParams: ammtypes.PoolParams{ + UseOracle: false, + }, + }) + + response, err := app.PerpetualKeeper.Pools(ctx, &types.QueryAllPoolRequest{}) + assert.Nil(t, err) + assert.Len(t, response.Pool, 1) + +} + func TestPoolQuerySingle(t *testing.T) { keeper, ctx := keepertest.PerpetualKeeper(t) wctx := sdk.WrapSDKContext(ctx) @@ -65,59 +125,3 @@ func TestPoolQuerySingle(t *testing.T) { }) } } - -func TestPoolQueryPaginated(t *testing.T) { - keeper, ctx := keepertest.PerpetualKeeper(t) - wctx := sdk.WrapSDKContext(ctx) - msgs := createNPool(keeper, ctx, 5) - - request := func(next []byte, offset, limit uint64, total bool) *types.QueryAllPoolRequest { - return &types.QueryAllPoolRequest{ - Pagination: &query.PageRequest{ - Key: next, - Offset: offset, - Limit: limit, - CountTotal: total, - }, - } - } - t.Run("ByOffset", func(t *testing.T) { - step := 2 - for i := 0; i < len(msgs); i += step { - resp, err := keeper.Pools(wctx, request(nil, uint64(i), uint64(step), false)) - require.NoError(t, err) - require.LessOrEqual(t, len(resp.Pool), step) - require.Subset(t, - nullify.Fill(msgs), - nullify.Fill(resp.Pool), - ) - } - }) - t.Run("ByKey", func(t *testing.T) { - step := 2 - var next []byte - for i := 0; i < len(msgs); i += step { - resp, err := keeper.Pools(wctx, request(next, 0, uint64(step), false)) - require.NoError(t, err) - require.LessOrEqual(t, len(resp.Pool), step) - require.Subset(t, - nullify.Fill(msgs), - nullify.Fill(resp.Pool), - ) - next = resp.Pagination.NextKey - } - }) - t.Run("Total", func(t *testing.T) { - resp, err := keeper.Pools(wctx, request(nil, 0, 0, true)) - require.NoError(t, err) - require.Equal(t, len(msgs), int(resp.Pagination.Total)) - require.ElementsMatch(t, - nullify.Fill(msgs), - nullify.Fill(resp.Pool), - ) - }) - t.Run("InvalidRequest", func(t *testing.T) { - _, err := keeper.Pools(wctx, nil) - require.ErrorIs(t, err, status.Error(codes.InvalidArgument, "invalid request")) - }) -} From 8c335ae946a48e083fb6578fbb5ae5a306287159 Mon Sep 17 00:00:00 2001 From: Cosmic Vagabond <121588426+cosmic-vagabond@users.noreply.github.com> Date: Tue, 17 Sep 2024 16:20:02 +0200 Subject: [PATCH 4/4] Update x/perpetual/types/errors.go Co-authored-by: Amit Yadav --- x/perpetual/types/errors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/perpetual/types/errors.go b/x/perpetual/types/errors.go index 9f701a4b1..ea4a1bede 100644 --- a/x/perpetual/types/errors.go +++ b/x/perpetual/types/errors.go @@ -33,5 +33,5 @@ var ( ErrInvalidTakeProfitPriceIsNegative = errorsmod.Register(ModuleName, 38, "error invalid profit price ") ErrTradingAssetIsEmpty = errorsmod.Register(ModuleName, 39, "error trading asset is empty") ErrInvalidAmount = errorsmod.Register(ModuleName, 40, "invalid amount") - ErrPoolHasToBeOracle = errorsmod.Register(ModuleName, 41, "pool has to be oracle") + ErrPoolHasToBeOracle = errorsmod.Register(ModuleName, 41, "pool has to be oracle enabled") )