Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 37 additions & 3 deletions x/dex/keeper/msgserver/msg_server_cancel_orders.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package msgserver
import (
"context"
"errors"
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/sei-protocol/sei-chain/x/dex/types"
Expand All @@ -13,6 +14,11 @@ import (
func (k msgServer) CancelOrders(goCtx context.Context, msg *types.MsgCancelOrders) (*types.MsgCancelOrdersResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

// validate cancellation requests
if err := k.validateCancels(msg); err != nil {
return nil, err
}

for _, cancellation := range msg.GetCancellations() {
var allocation *types.Allocation
var found bool
Expand Down Expand Up @@ -40,13 +46,41 @@ func (k msgServer) CancelOrders(goCtx context.Context, msg *types.MsgCancelOrder
if !cancelledInCurrentBlock {
// only cancel if it's not cancelled in a previous tx in the same block
cancel := types.Cancellation{
Id: cancellation.Id,
Initiator: types.CancellationInitiator_USER,
Creator: msg.Creator,
Id: cancellation.Id,
Initiator: types.CancellationInitiator_USER,
Creator: msg.Creator,
ContractAddr: msg.ContractAddr,
Price: cancellation.Price,
AssetDenom: cancellation.AssetDenom,
PriceDenom: cancellation.PriceDenom,
PositionDirection: cancellation.PositionDirection,
}
pairBlockCancellations.Add(&cancel)
}
}

return &types.MsgCancelOrdersResponse{}, nil
}

func (k msgServer) validateCancels(cancels *types.MsgCancelOrders) error {
if len(cancels.Creator) == 0 {
return fmt.Errorf("invalid cancellation, creator cannot be empty")
}
if len(cancels.ContractAddr) == 0 {
return fmt.Errorf("invalid cancellation, contract address cannot be empty")
}

for _, cancellation := range cancels.GetCancellations() {
if cancellation.Price.IsNil() {
return fmt.Errorf("invalid cancellation price: %s", cancellation.Price)
}
if len(cancellation.AssetDenom) == 0 {
return fmt.Errorf("invalid cancellation, asset denom is empty")
}
if len(cancellation.PriceDenom) == 0 {
return fmt.Errorf("invalid cancellation, price denom is empty")
}
}

return nil
}
151 changes: 151 additions & 0 deletions x/dex/keeper/msgserver/msg_server_cancel_orders_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package msgserver_test

import (
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
keepertest "github.com/sei-protocol/sei-chain/testutil/keeper"
"github.com/sei-protocol/sei-chain/x/dex/keeper/msgserver"
"github.com/sei-protocol/sei-chain/x/dex/types"
typesutils "github.com/sei-protocol/sei-chain/x/dex/types/utils"
dexutils "github.com/sei-protocol/sei-chain/x/dex/utils"
"github.com/stretchr/testify/require"
)

func TestCancelOrder(t *testing.T) {
// store a long limit order to the orderbook
keeper, ctx := keepertest.DexKeeper(t)
keeper.SetLongBook(ctx, keepertest.TestContract, types.LongBook{
Price: sdk.OneDec(),
Entry: &types.OrderEntry{
Price: sdk.OneDec(),
Quantity: sdk.MustNewDecFromStr("2"),
PriceDenom: keepertest.TestPriceDenom,
AssetDenom: keepertest.TestAssetDenom,
Allocations: []*types.Allocation{
{
Account: keepertest.TestAccount,
OrderId: 1,
Quantity: sdk.MustNewDecFromStr("2"),
},
},
},
})

// cancel order
msg := &types.MsgCancelOrders{
Creator: keepertest.TestAccount,
ContractAddr: keepertest.TestContract,
Cancellations: []*types.Cancellation{
{
Price: sdk.OneDec(),
PositionDirection: types.PositionDirection_LONG,
PriceDenom: keepertest.TestPriceDenom,
AssetDenom: keepertest.TestAssetDenom,
Id: 1,
},
},
}
keeper.AddRegisteredPair(ctx, keepertest.TestContract, keepertest.TestPair)
keeper.SetTickSizeForPair(ctx, keepertest.TestContract, keepertest.TestPair, *keepertest.TestPair.Ticksize)
wctx := sdk.WrapSDKContext(ctx)
server := msgserver.NewMsgServerImpl(*keeper)
_, err := server.CancelOrders(wctx, msg)

pairBlockCancellations := dexutils.GetMemState(ctx.Context()).GetBlockCancels(ctx, keepertest.TestContract, typesutils.GetPairString(&keepertest.TestPair))
require.Nil(t, err)
require.Equal(t, 1, len(pairBlockCancellations.Get()))
require.Equal(t, uint64(1), pairBlockCancellations.Get()[0].Id)
require.Equal(t, sdk.OneDec(), pairBlockCancellations.Get()[0].Price)
require.Equal(t, "atom", pairBlockCancellations.Get()[0].AssetDenom)
require.Equal(t, "usdc", pairBlockCancellations.Get()[0].PriceDenom)
require.Equal(t, keepertest.TestAccount, pairBlockCancellations.Get()[0].Creator)
require.Equal(t, keepertest.TestContract, pairBlockCancellations.Get()[0].ContractAddr)
}

func TestInvalidCancels(t *testing.T) {
// nil cancel price
keeper, ctx := keepertest.DexKeeper(t)
msg := &types.MsgCancelOrders{
Creator: keepertest.TestAccount,
ContractAddr: keepertest.TestContract,
Cancellations: []*types.Cancellation{
{
PositionDirection: types.PositionDirection_LONG,
PriceDenom: keepertest.TestPriceDenom,
AssetDenom: keepertest.TestAssetDenom,
Id: 1,
},
},
}
keeper.AddRegisteredPair(ctx, keepertest.TestContract, keepertest.TestPair)
keeper.SetTickSizeForPair(ctx, keepertest.TestContract, keepertest.TestPair, *keepertest.TestPair.Ticksize)
wctx := sdk.WrapSDKContext(ctx)
server := msgserver.NewMsgServerImpl(*keeper)
_, err := server.CancelOrders(wctx, msg)
require.NotNil(t, err)

// nil creator
msg = &types.MsgCancelOrders{
ContractAddr: keepertest.TestContract,
Cancellations: []*types.Cancellation{
{
PositionDirection: types.PositionDirection_LONG,
PriceDenom: keepertest.TestPriceDenom,
AssetDenom: keepertest.TestAssetDenom,
Id: 1,
Price: sdk.OneDec(),
},
},
}
_, err = server.CancelOrders(wctx, msg)
require.NotNil(t, err)

// nil contract address
msg = &types.MsgCancelOrders{
Creator: keepertest.TestAccount,
Cancellations: []*types.Cancellation{
{
Price: sdk.OneDec(),
PositionDirection: types.PositionDirection_LONG,
PriceDenom: keepertest.TestPriceDenom,
AssetDenom: keepertest.TestAssetDenom,
Id: 1,
},
},
}
_, err = server.CancelOrders(wctx, msg)
require.NotNil(t, err)

// nil price denom
msg = &types.MsgCancelOrders{
Creator: keepertest.TestAccount,
ContractAddr: keepertest.TestContract,
Cancellations: []*types.Cancellation{
{
Price: sdk.OneDec(),
PositionDirection: types.PositionDirection_LONG,
AssetDenom: keepertest.TestAssetDenom,
Id: 1,
},
},
}
_, err = server.CancelOrders(wctx, msg)
require.NotNil(t, err)

// nil asset denom
msg = &types.MsgCancelOrders{
Creator: keepertest.TestAccount,
ContractAddr: keepertest.TestContract,
Cancellations: []*types.Cancellation{
{
Price: sdk.OneDec(),
PositionDirection: types.PositionDirection_LONG,
PriceDenom: keepertest.TestPriceDenom,
Id: 1,
},
},
}
_, err = server.CancelOrders(wctx, msg)
require.NotNil(t, err)
}