Skip to content

Commit

Permalink
cancel existing orders when setting a vault to deactivated or stand-by (
Browse files Browse the repository at this point in the history
  • Loading branch information
tqin7 committed Sep 23, 2024
1 parent a01cb54 commit 53cca79
Show file tree
Hide file tree
Showing 4 changed files with 231 additions and 8 deletions.
41 changes: 34 additions & 7 deletions protocol/x/vault/keeper/orders.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,20 @@ func (k Keeper) RefreshVaultClobOrders(ctx sdk.Context, vaultId types.VaultId) (
return types.ErrVaultParamsNotFound
}
for i := len(ordersToPlace); i < len(mostRecentClientIds); i++ {
orderId := vaultId.GetClobOrderId(mostRecentClientIds[i])
_, exists := k.clobKeeper.GetLongTermOrderPlacement(ctx, *orderId)
if exists {
err := k.CancelVaultClobOrder(ctx, vaultId, orderId, quotingParams.OrderExpirationSeconds)
if err != nil {
log.ErrorLogWithError(ctx, "Failed to cancel vault clob order", err, "vaultId", vaultId)
}
_, err = k.TryToCancelVaultClobOrder(
ctx,
vaultId,
mostRecentClientIds[i],
quotingParams.OrderExpirationSeconds,
)
if err != nil {
log.ErrorLogWithError(
ctx,
"Failed to cancel no longer needed vault clob order",
err,
"vaultId",
vaultId,
)
}
}

Expand Down Expand Up @@ -473,6 +480,26 @@ func (k Keeper) CancelVaultClobOrder(
return err
}

// TryToCancelVaultClobOrder tries to cancel a vault CLOB order. Returns whether the order exists
// and whether cancellation errors.
func (k Keeper) TryToCancelVaultClobOrder(
ctx sdk.Context,
vaultId types.VaultId,
clientId uint32,
orderExpirationSeconds uint32,
) (
orderExists bool,
err error,
) {
orderId := vaultId.GetClobOrderId(clientId)
_, exists := k.clobKeeper.GetLongTermOrderPlacement(ctx, *orderId)
if exists {
err = k.CancelVaultClobOrder(ctx, vaultId, orderId, orderExpirationSeconds)
return true, err
}
return false, nil
}

// ReplaceVaultClobOrder replaces a vault CLOB order internal to the protocol and
// emits order replacement indexer event.
func (k Keeper) ReplaceVaultClobOrder(
Expand Down
94 changes: 94 additions & 0 deletions protocol/x/vault/keeper/orders_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,100 @@ func TestRefreshVaultClobOrders(t *testing.T) {
},
},
},
"Success - Orders refresh due to status changing to stand-by. No more orders": {
vaultId: constants.Vault_Clob0,
instances: []Instance{
{
advanceBlock: func(ctx sdk.Context, tApp *testapp.TestApp) sdk.Context {
msgSetVaultParams := vaulttypes.MsgSetVaultParams{
Authority: constants.AliceAccAddress.String(), // operator
VaultId: constants.Vault_Clob0,
VaultParams: vaulttypes.VaultParams{
Status: vaulttypes.VaultStatus_VAULT_STATUS_STAND_BY,
},
}
CheckTx_MsgSetVaultParams := testapp.MustMakeCheckTx(
ctx,
tApp.App,
testapp.MustMakeCheckTxOptions{
AccAddressForSigning: constants.AliceAccAddress.String(),
Gas: constants.TestGasLimit,
FeeAmt: constants.TestFeeCoins_5Cents,
},
&msgSetVaultParams,
)
checkTxResp := tApp.CheckTx(CheckTx_MsgSetVaultParams)
require.Conditionf(t, checkTxResp.IsOK, "Expected CheckTx to succeed. Response: %+v", checkTxResp)

return tApp.AdvanceToBlock(
uint32(tApp.GetBlockHeight())+1,
testapp.AdvanceToBlockOptions{
BlockTime: ctx.BlockTime().Add(time.Second * 2),
},
)
},
ordersRefreshed: []bool{}, // no orders
orderSides: []clobtypes.Order_Side{},
clientIdIsCanonical: []bool{},
},
},
},
"Success - Orders refresh due to retrieving to 0 equity and status changing to deactivated. No more orders": {
vaultId: constants.Vault_Clob0,
instances: []Instance{
{
advanceBlock: func(ctx sdk.Context, tApp *testapp.TestApp) sdk.Context {
msgRetrieveFromVault := vaulttypes.MsgRetrieveFromVault{
Authority: constants.AliceAccAddress.String(), // operator
VaultId: constants.Vault_Clob0,
QuoteQuantums: dtypes.NewInt(2_000_000_000), // retrieve all quote quantums the vault has.
}
CheckTx_MsgRetrieveFromVault := testapp.MustMakeCheckTx(
ctx,
tApp.App,
testapp.MustMakeCheckTxOptions{
AccAddressForSigning: constants.AliceAccAddress.String(),
Gas: constants.TestGasLimit,
FeeAmt: constants.TestFeeCoins_5Cents,
},
&msgRetrieveFromVault,
)
checkTxResp := tApp.CheckTx(CheckTx_MsgRetrieveFromVault)
require.Conditionf(t, checkTxResp.IsOK, "Expected CheckTx to succeed. Response: %+v", checkTxResp)

msgSetVaultParams := vaulttypes.MsgSetVaultParams{
Authority: constants.AliceAccAddress.String(), // operator
VaultId: constants.Vault_Clob0,
VaultParams: vaulttypes.VaultParams{
Status: vaulttypes.VaultStatus_VAULT_STATUS_DEACTIVATED,
},
}
CheckTx_MsgSetVaultParams := testapp.MustMakeCheckTx(
ctx,
tApp.App,
testapp.MustMakeCheckTxOptions{
AccAddressForSigning: constants.AliceAccAddress.String(),
Gas: constants.TestGasLimit,
FeeAmt: constants.TestFeeCoins_5Cents,
},
&msgSetVaultParams,
)
checkTxResp = tApp.CheckTx(CheckTx_MsgSetVaultParams)
require.Conditionf(t, checkTxResp.IsOK, "Expected CheckTx to succeed. Response: %+v", checkTxResp)

return tApp.AdvanceToBlock(
uint32(tApp.GetBlockHeight())+1,
testapp.AdvanceToBlockOptions{
BlockTime: ctx.BlockTime().Add(time.Second * 2),
},
)
},
ordersRefreshed: []bool{}, // no orders
orderSides: []clobtypes.Order_Side{},
clientIdIsCanonical: []bool{},
},
},
},
"Success - Vault for non-existent Clob Pair 4321": {
vaultId: vaulttypes.VaultId{
Type: vaulttypes.VaultType_VAULT_TYPE_CLOB,
Expand Down
19 changes: 19 additions & 0 deletions protocol/x/vault/keeper/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
indexerevents "github.com/dydxprotocol/v4-chain/protocol/indexer/events"
"github.com/dydxprotocol/v4-chain/protocol/indexer/indexer_manager"
"github.com/dydxprotocol/v4-chain/protocol/lib/log"
"github.com/dydxprotocol/v4-chain/protocol/x/vault/types"
)

Expand Down Expand Up @@ -78,6 +79,24 @@ func (k Keeper) SetVaultParams(
}
}

// When setting an existing vault to deactivated or stand-by, cancel any existing orders.
_, quotingParams, exists := k.GetVaultAndQuotingParams(ctx, vaultId)
if exists && (vaultParams.Status == types.VaultStatus_VAULT_STATUS_DEACTIVATED ||
vaultParams.Status == types.VaultStatus_VAULT_STATUS_STAND_BY) {
mostRecentClientIds := k.GetMostRecentClientIds(ctx, vaultId)
for _, clientId := range mostRecentClientIds {
_, err := k.TryToCancelVaultClobOrder(ctx, vaultId, clientId, quotingParams.OrderExpirationSeconds)
if err != nil {
log.ErrorLogWithError(
ctx,
"Failed to cancel vault clob order when setting existing vault to deactivated or stand-by",
err,
)
}
}
k.SetMostRecentClientIds(ctx, vaultId, []uint32{})
}

b := k.cdc.MustMarshal(&vaultParams)
store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.VaultParamsKeyPrefix))
store.Set(vaultId.ToStateKey(), b)
Expand Down
85 changes: 84 additions & 1 deletion protocol/x/vault/keeper/params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ func TestGetSetVaultParams(t *testing.T) {
positionBaseQuantums int64
// Vault params to set.
vaultParams *vaulttypes.VaultParams
// Number of vault orders before setting vault params.
numVaultOrdersPreSet uint32
// Number of vault orders after setting vault params.
numVaultOrdersPostSet uint32
// Expected on-chain indexer events
expectedIndexerEvents []*indexerevents.UpsertVaultEventV1
// Expected error.
Expand Down Expand Up @@ -97,6 +101,32 @@ func TestGetSetVaultParams(t *testing.T) {
},
},
},
"Success - Create a stand-by vault": {
vaultId: constants.Vault_Clob1,
vaultParams: &vaulttypes.VaultParams{
Status: vaulttypes.VaultStatus_VAULT_STATUS_STAND_BY,
},
expectedIndexerEvents: []*indexerevents.UpsertVaultEventV1{
{
Address: constants.Vault_Clob1.ToModuleAccountAddress(),
ClobPairId: constants.Vault_Clob1.Number,
Status: v1.VaultStatusToIndexerVaultStatus(vaulttypes.VaultStatus_VAULT_STATUS_STAND_BY),
},
},
},
"Success - Create a deactivated vault": {
vaultId: constants.Vault_Clob1,
vaultParams: &vaulttypes.VaultParams{
Status: vaulttypes.VaultStatus_VAULT_STATUS_DEACTIVATED,
},
expectedIndexerEvents: []*indexerevents.UpsertVaultEventV1{
{
Address: constants.Vault_Clob1.ToModuleAccountAddress(),
ClobPairId: constants.Vault_Clob1.Number,
Status: v1.VaultStatusToIndexerVaultStatus(vaulttypes.VaultStatus_VAULT_STATUS_DEACTIVATED),
},
},
},
"Success - Deactivate a vault with zero equity": {
vaultId: constants.Vault_Clob1,
existingVaultParams: &constants.VaultParams,
Expand Down Expand Up @@ -131,6 +161,27 @@ func TestGetSetVaultParams(t *testing.T) {
},
},
},
"Success - Put a quoting vault to stand-by should cancel all existing orders": {
vaultId: constants.Vault_Clob1,
existingVaultParams: &vaulttypes.VaultParams{
Status: vaulttypes.VaultStatus_VAULT_STATUS_QUOTING,
},
assetQuoteQuantums: 1_000_000_000,
vaultParams: &vaulttypes.VaultParams{
Status: vaulttypes.VaultStatus_VAULT_STATUS_STAND_BY,
},
numVaultOrdersPreSet: 4,
numVaultOrdersPostSet: 0,
expectedIndexerEvents: []*indexerevents.UpsertVaultEventV1{
{
Address: constants.Vault_Clob1.ToModuleAccountAddress(),
ClobPairId: constants.Vault_Clob1.Number,
Status: v1.VaultStatusToIndexerVaultStatus(
vaulttypes.VaultStatus_VAULT_STATUS_STAND_BY,
),
},
},
},
"Failure - Deactivate a vault with positive equity": {
vaultId: constants.Vault_Clob1,
existingVaultParams: &constants.VaultParams,
Expand Down Expand Up @@ -215,8 +266,18 @@ func TestGetSetVaultParams(t *testing.T) {
_, exists := k.GetVaultParams(ctx, tc.vaultId)
require.False(t, exists)
}
require.Len(
t,
tApp.App.ClobKeeper.GetAllStatefulOrders(ctx),
int(tc.numVaultOrdersPreSet),
)
require.Len(
t,
k.GetMostRecentClientIds(ctx, tc.vaultId),
int(tc.numVaultOrdersPreSet),
)

err := k.SetVaultParams(ctx, tc.vaultId, *tc.vaultParams)
err := k.SetVaultParams(ctx.WithIsCheckTx(false), tc.vaultId, *tc.vaultParams)
if tc.expectedErr != nil {
require.ErrorIs(t, err, tc.expectedErr)
v, exists := k.GetVaultParams(ctx, tc.vaultId)
Expand All @@ -226,11 +287,33 @@ func TestGetSetVaultParams(t *testing.T) {
require.True(t, exists)
require.Equal(t, *tc.existingVaultParams, v)
}

require.Len(
t,
tApp.App.ClobKeeper.GetAllStatefulOrders(ctx),
int(tc.numVaultOrdersPreSet),
)
require.Len(
t,
k.GetMostRecentClientIds(ctx, tc.vaultId),
int(tc.numVaultOrdersPreSet),
)
} else {
require.NoError(t, err)
p, exists := k.GetVaultParams(ctx, tc.vaultId)
require.True(t, exists)
require.Equal(t, *tc.vaultParams, p)

require.Len(
t,
tApp.App.ClobKeeper.GetAllStatefulOrders(ctx),
int(tc.numVaultOrdersPostSet),
)
require.Len(
t,
k.GetMostRecentClientIds(ctx, tc.vaultId),
int(tc.numVaultOrdersPostSet),
)
}

if tc.expectedErr == nil && tc.vaultParams != nil {
Expand Down

0 comments on commit 53cca79

Please sign in to comment.