Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CLOB-1046] populate negative tnc subaccounts in grpc request #890

Merged
merged 2 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
16 changes: 13 additions & 3 deletions protocol/daemons/liquidation/client/grpc_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,9 @@ func (c *Client) GetAllSubaccounts(
// subaccount ids to a gRPC server via `LiquidateSubaccounts`.
func (c *Client) SendLiquidatableSubaccountIds(
ctx context.Context,
subaccountIds []satypes.SubaccountId,
blockHeight uint32,
liquidatableSubaccountIds []satypes.SubaccountId,
negativeTncSubaccountIds []satypes.SubaccountId,
) error {
defer telemetry.ModuleMeasureSince(
metrics.LiquidationDaemon,
Expand All @@ -216,13 +218,21 @@ func (c *Client) SendLiquidatableSubaccountIds(

telemetry.ModuleSetGauge(
metrics.LiquidationDaemon,
float32(len(subaccountIds)),
float32(len(liquidatableSubaccountIds)),
metrics.LiquidatableSubaccountIds,
metrics.Count,
)
telemetry.ModuleSetGauge(
metrics.LiquidationDaemon,
float32(len(negativeTncSubaccountIds)),
metrics.NegativeTncSubaccountIds,
metrics.Count,
)

request := &api.LiquidateSubaccountsRequest{
LiquidatableSubaccountIds: subaccountIds,
BlockHeight: blockHeight,
LiquidatableSubaccountIds: liquidatableSubaccountIds,
NegativeTncSubaccountIds: negativeTncSubaccountIds,
}

if _, err := c.LiquidationServiceClient.LiquidateSubaccounts(ctx, request); err != nil {
Expand Down
74 changes: 60 additions & 14 deletions protocol/daemons/liquidation/client/grpc_helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,56 +452,102 @@ func TestGetAllMarketPrices(t *testing.T) {
func TestSendLiquidatableSubaccountIds(t *testing.T) {
tests := map[string]struct {
// mocks
setupMocks func(ctx context.Context, mck *mocks.QueryClient, ids []satypes.SubaccountId)
subaccountIds []satypes.SubaccountId
setupMocks func(
context.Context,
*mocks.QueryClient,
uint32,
[]satypes.SubaccountId,
[]satypes.SubaccountId,
)
liquidatableSubaccountIds []satypes.SubaccountId
negativeTncSubaccountIds []satypes.SubaccountId

// expectations
expectedError error
}{
"Success": {
setupMocks: func(ctx context.Context, mck *mocks.QueryClient, ids []satypes.SubaccountId) {
setupMocks: func(
ctx context.Context,
mck *mocks.QueryClient,
blockHeight uint32,
liquidatableSubaccountIds []satypes.SubaccountId,
negativeTncSubaccountIds []satypes.SubaccountId,
) {
req := &api.LiquidateSubaccountsRequest{
LiquidatableSubaccountIds: ids,
BlockHeight: blockHeight,
LiquidatableSubaccountIds: liquidatableSubaccountIds,
NegativeTncSubaccountIds: negativeTncSubaccountIds,
}
response := &api.LiquidateSubaccountsResponse{}
mck.On("LiquidateSubaccounts", ctx, req).Return(response, nil)
},
subaccountIds: []satypes.SubaccountId{
liquidatableSubaccountIds: []satypes.SubaccountId{
constants.Alice_Num0,
constants.Bob_Num0,
},
negativeTncSubaccountIds: []satypes.SubaccountId{
constants.Carl_Num0,
constants.Dave_Num0,
},
},
"Success Empty": {
setupMocks: func(ctx context.Context, mck *mocks.QueryClient, ids []satypes.SubaccountId) {
setupMocks: func(
ctx context.Context,
mck *mocks.QueryClient,
blockHeight uint32,
liquidatableSubaccountIds []satypes.SubaccountId,
negativeTncSubaccountIds []satypes.SubaccountId,
) {
req := &api.LiquidateSubaccountsRequest{
LiquidatableSubaccountIds: ids,
BlockHeight: blockHeight,
LiquidatableSubaccountIds: liquidatableSubaccountIds,
NegativeTncSubaccountIds: negativeTncSubaccountIds,
}
response := &api.LiquidateSubaccountsResponse{}
mck.On("LiquidateSubaccounts", ctx, req).Return(response, nil)
},
subaccountIds: []satypes.SubaccountId{},
liquidatableSubaccountIds: []satypes.SubaccountId{},
},
"Errors are propagated": {
setupMocks: func(ctx context.Context, mck *mocks.QueryClient, ids []satypes.SubaccountId) {
setupMocks: func(
ctx context.Context,
mck *mocks.QueryClient,
blockHeight uint32,
liquidatableSubaccountIds []satypes.SubaccountId,
negativeTncSubaccountIds []satypes.SubaccountId,
) {
req := &api.LiquidateSubaccountsRequest{
LiquidatableSubaccountIds: ids,
BlockHeight: blockHeight,
LiquidatableSubaccountIds: liquidatableSubaccountIds,
NegativeTncSubaccountIds: negativeTncSubaccountIds,
}
mck.On("LiquidateSubaccounts", ctx, req).Return(nil, errors.New("test error"))
},
subaccountIds: []satypes.SubaccountId{},
expectedError: errors.New("test error"),
liquidatableSubaccountIds: []satypes.SubaccountId{},
expectedError: errors.New("test error"),
},
}

for name, tc := range tests {
t.Run(name, func(t *testing.T) {
queryClientMock := &mocks.QueryClient{}
tc.setupMocks(grpc.Ctx, queryClientMock, tc.subaccountIds)
tc.setupMocks(
grpc.Ctx,
queryClientMock,
uint32(50),
tc.liquidatableSubaccountIds,
tc.negativeTncSubaccountIds,
)

daemon := client.NewClient(log.NewNopLogger())
daemon.LiquidationServiceClient = queryClientMock

err := daemon.SendLiquidatableSubaccountIds(grpc.Ctx, tc.subaccountIds)
err := daemon.SendLiquidatableSubaccountIds(
grpc.Ctx,
uint32(50),
tc.liquidatableSubaccountIds,
tc.negativeTncSubaccountIds,
)
require.Equal(t, tc.expectedError, err)
})
}
Expand Down
37 changes: 26 additions & 11 deletions protocol/daemons/liquidation/client/sub_task_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,9 @@ func (s *SubTaskRunnerImpl) RunLiquidationDaemonTaskLoop(
}

// 2. Check collateralization statuses of subaccounts with at least one open position.
liquidatableSubaccountIds, err := daemonClient.GetLiquidatableSubaccountIds(
liquidatableSubaccountIds,
negativeTncSubaccountIds,
err := daemonClient.GetLiquidatableSubaccountIds(
subaccounts,
marketPrices,
perpetuals,
Expand All @@ -79,7 +81,12 @@ func (s *SubTaskRunnerImpl) RunLiquidationDaemonTaskLoop(
}

// 3. Send the list of liquidatable subaccount ids to the daemon server.
err = daemonClient.SendLiquidatableSubaccountIds(ctx, liquidatableSubaccountIds)
err = daemonClient.SendLiquidatableSubaccountIds(
ctx,
lastCommittedBlockHeight,
liquidatableSubaccountIds,
negativeTncSubaccountIds,
)
if err != nil {
return err
}
Expand Down Expand Up @@ -159,6 +166,7 @@ func (c *Client) GetLiquidatableSubaccountIds(
liquidityTiers map[uint32]perptypes.LiquidityTier,
) (
liquidatableSubaccountIds []satypes.SubaccountId,
negativeTncSubaccountIds []satypes.SubaccountId,
err error,
) {
defer telemetry.ModuleMeasureSince(
Expand All @@ -170,27 +178,31 @@ func (c *Client) GetLiquidatableSubaccountIds(

numSubaccountsWithOpenPositions := 0
liquidatableSubaccountIds = make([]satypes.SubaccountId, 0)
negativeTncSubaccountIds = make([]satypes.SubaccountId, 0)
for _, subaccount := range subaccounts {
// Skip subaccounts with no open positions.
if len(subaccount.PerpetualPositions) == 0 {
continue
}

// Check if the subaccount is liquidatable.
isLiquidatable, err := c.CheckSubaccountCollateralization(
isLiquidatable, hasNegativeTnc, err := c.CheckSubaccountCollateralization(
subaccount,
marketPrices,
perpetuals,
liquidityTiers,
)
if err != nil {
c.logger.Error("Error checking collateralization status", "error", err)
return nil, err
return nil, nil, err
}

if isLiquidatable {
liquidatableSubaccountIds = append(liquidatableSubaccountIds, *subaccount.Id)
}
if hasNegativeTnc {
negativeTncSubaccountIds = append(negativeTncSubaccountIds, *subaccount.Id)
}
numSubaccountsWithOpenPositions++
}

Expand All @@ -201,7 +213,7 @@ func (c *Client) GetLiquidatableSubaccountIds(
metrics.Count,
)

return liquidatableSubaccountIds, nil
return liquidatableSubaccountIds, negativeTncSubaccountIds, nil
}

// CheckSubaccountCollateralization performs the same collateralization check as the application
Expand All @@ -216,6 +228,7 @@ func (c *Client) CheckSubaccountCollateralization(
liquidityTiers map[uint32]perptypes.LiquidityTier,
) (
isLiquidatable bool,
hasNegativeTnc bool,
err error,
) {
defer telemetry.ModuleMeasureSince(
Expand All @@ -232,7 +245,7 @@ func (c *Client) CheckSubaccountCollateralization(
perpetuals,
)
if err != nil {
return false, err
return false, false, err
}

bigTotalNetCollateral := big.NewInt(0)
Expand All @@ -242,7 +255,7 @@ func (c *Client) CheckSubaccountCollateralization(
// Note that we only expect USDC before multi-collateral support is added.
for _, assetPosition := range settledSubaccount.AssetPositions {
if assetPosition.AssetId != assetstypes.AssetUsdc.Id {
return false, errorsmod.Wrapf(
return false, false, errorsmod.Wrapf(
assetstypes.ErrNotImplementedMulticollateral,
"Asset %d is not supported",
assetPosition.AssetId,
Expand All @@ -257,7 +270,7 @@ func (c *Client) CheckSubaccountCollateralization(
for _, perpetualPosition := range settledSubaccount.PerpetualPositions {
perpetual, ok := perpetuals[perpetualPosition.PerpetualId]
if !ok {
return false, errorsmod.Wrapf(
return false, false, errorsmod.Wrapf(
perptypes.ErrPerpetualDoesNotExist,
"Perpetual not found for perpetual id %d",
perpetualPosition.PerpetualId,
Expand All @@ -266,7 +279,7 @@ func (c *Client) CheckSubaccountCollateralization(

marketPrice, ok := marketPrices[perpetual.Params.MarketId]
if !ok {
return false, errorsmod.Wrapf(
return false, false, errorsmod.Wrapf(
pricestypes.ErrMarketPriceDoesNotExist,
"MarketPrice not found for perpetual %+v",
perpetual,
Expand All @@ -281,7 +294,7 @@ func (c *Client) CheckSubaccountCollateralization(

liquidityTier, ok := liquidityTiers[perpetual.Params.LiquidityTier]
if !ok {
return false, errorsmod.Wrapf(
return false, false, errorsmod.Wrapf(
perptypes.ErrLiquidityTierDoesNotExist,
"LiquidityTier not found for perpetual %+v",
perpetual,
Expand All @@ -298,5 +311,7 @@ func (c *Client) CheckSubaccountCollateralization(
bigTotalMaintenanceMargin.Add(bigTotalMaintenanceMargin, bigMaintenanceMarginQuoteQuantums)
}

return clobkeeper.CanLiquidateSubaccount(bigTotalNetCollateral, bigTotalMaintenanceMargin), nil
return clobkeeper.CanLiquidateSubaccount(bigTotalNetCollateral, bigTotalMaintenanceMargin),
bigTotalNetCollateral.Sign() == -1,
nil
}
Loading
Loading