diff --git a/protocol/daemons/liquidation/client/grpc_helper.go b/protocol/daemons/liquidation/client/grpc_helper.go new file mode 100644 index 0000000000..3b3134b568 --- /dev/null +++ b/protocol/daemons/liquidation/client/grpc_helper.go @@ -0,0 +1,155 @@ +package client + +import ( + "context" + "time" + + gometrics "github.com/armon/go-metrics" + "github.com/cosmos/cosmos-sdk/telemetry" + "github.com/cosmos/cosmos-sdk/types/query" + "github.com/dydxprotocol/v4-chain/protocol/daemons/liquidation/api" + "github.com/dydxprotocol/v4-chain/protocol/lib/metrics" + clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" + satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" +) + +// GetAllSubaccounts queries a gRPC server and returns a list of subaccounts and +// their balances and open positions. +func GetAllSubaccounts( + daemon *Client, + ctx context.Context, + client satypes.QueryClient, + limit uint64, +) ( + subaccounts []satypes.Subaccount, + err error, +) { + defer telemetry.ModuleMeasureSince(metrics.LiquidationDaemon, time.Now(), metrics.GetAllSubaccounts, metrics.Latency) + subaccounts = make([]satypes.Subaccount, 0) + + var nextKey []byte + for { + subaccountsFromKey, next, err := getSubaccountsFromKey( + ctx, + client, + limit, + nextKey, + ) + + if err != nil { + return nil, err + } + + subaccounts = append(subaccounts, subaccountsFromKey...) + nextKey = next + + if len(nextKey) == 0 { + break + } + } + + telemetry.ModuleSetGauge( + metrics.LiquidationDaemon, + float32(len(subaccounts)), + metrics.GetAllSubaccounts, + metrics.Count, + ) + + return subaccounts, nil +} + +// CheckCollateralizationForSubaccounts queries a gRPC server using `AreSubaccountsLiquidatable` +// and returns a list of collateralization statuses for the given list of subaccount ids. +func CheckCollateralizationForSubaccounts( + daemon *Client, + ctx context.Context, + client clobtypes.QueryClient, + subaccountIds []satypes.SubaccountId, +) ( + results []clobtypes.AreSubaccountsLiquidatableResponse_Result, + err error, +) { + defer telemetry.ModuleMeasureSince( + metrics.LiquidationDaemon, + time.Now(), + metrics.CheckCollateralizationForSubaccounts, + metrics.Latency, + ) + + query := &clobtypes.AreSubaccountsLiquidatableRequest{ + SubaccountIds: subaccountIds, + } + response, err := client.AreSubaccountsLiquidatable(ctx, query) + if err != nil { + return nil, err + } + + return response.Results, nil +} + +// SendLiquidatableSubaccountIds sends a list of unique and potentially liquidatable +// subaccount ids to a gRPC server via `LiquidateSubaccounts`. +func SendLiquidatableSubaccountIds( + ctx context.Context, + client api.LiquidationServiceClient, + subaccountIds []satypes.SubaccountId, +) error { + defer telemetry.ModuleMeasureSince( + metrics.LiquidationDaemon, + time.Now(), + metrics.SendLiquidatableSubaccountIds, + metrics.Latency, + ) + + telemetry.ModuleSetGauge( + metrics.LiquidationDaemon, + float32(len(subaccountIds)), + metrics.LiquidatableSubaccountIds, + metrics.Count, + ) + + request := &api.LiquidateSubaccountsRequest{ + SubaccountIds: subaccountIds, + } + + if _, err := client.LiquidateSubaccounts(ctx, request); err != nil { + return err + } + return nil +} + +func getSubaccountsFromKey( + ctx context.Context, + client satypes.QueryClient, + limit uint64, + pageRequestKey []byte, +) ( + subaccounts []satypes.Subaccount, + nextKey []byte, + err error, +) { + defer metrics.ModuleMeasureSinceWithLabels( + metrics.LiquidationDaemon, + []string{metrics.GetSubaccountsFromKey, metrics.Latency}, + time.Now(), + []gometrics.Label{ + metrics.GetLabelForIntValue(metrics.PageLimit, int(limit)), + }, + ) + + query := &satypes.QueryAllSubaccountRequest{ + Pagination: &query.PageRequest{ + Key: pageRequestKey, + Limit: limit, + }, + } + + response, err := client.SubaccountAll(ctx, query) + if err != nil { + return nil, nil, err + } + if response.Pagination != nil { + nextKey = response.Pagination.NextKey + } + return response.Subaccount, nextKey, nil +} diff --git a/protocol/daemons/liquidation/client/sub_task_runner_test.go b/protocol/daemons/liquidation/client/grpc_helper_test.go similarity index 99% rename from protocol/daemons/liquidation/client/sub_task_runner_test.go rename to protocol/daemons/liquidation/client/grpc_helper_test.go index 74dc257d20..48cb39ba92 100644 --- a/protocol/daemons/liquidation/client/sub_task_runner_test.go +++ b/protocol/daemons/liquidation/client/grpc_helper_test.go @@ -3,6 +3,8 @@ package client_test import ( "context" "errors" + "testing" + "github.com/cometbft/cometbft/libs/log" "github.com/cosmos/cosmos-sdk/types/query" "github.com/dydxprotocol/v4-chain/protocol/daemons/flags" @@ -14,7 +16,6 @@ import ( clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" "github.com/stretchr/testify/require" - "testing" ) func TestGetAllSubaccounts(t *testing.T) { diff --git a/protocol/daemons/liquidation/client/sub_task_runner.go b/protocol/daemons/liquidation/client/sub_task_runner.go index db8b92b321..62495401ac 100644 --- a/protocol/daemons/liquidation/client/sub_task_runner.go +++ b/protocol/daemons/liquidation/client/sub_task_runner.go @@ -2,16 +2,15 @@ package client import ( "context" - gometrics "github.com/armon/go-metrics" + "time" + "github.com/cosmos/cosmos-sdk/telemetry" - "github.com/cosmos/cosmos-sdk/types/query" "github.com/dydxprotocol/v4-chain/protocol/daemons/flags" "github.com/dydxprotocol/v4-chain/protocol/daemons/liquidation/api" "github.com/dydxprotocol/v4-chain/protocol/lib" "github.com/dydxprotocol/v4-chain/protocol/lib/metrics" clobtypes "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" - "time" ) // SubTaskRunner provides an interface that encapsulates the liquidations daemon logic to gather and report @@ -50,12 +49,7 @@ func (s *SubTaskRunnerImpl) RunLiquidationDaemonTaskLoop( ) // 1. Fetch all subaccounts from query service. - subaccounts, err := GetAllSubaccounts( - client, - ctx, - subaccountQueryClient, - liqFlags.SubaccountPageLimit, - ) + subaccounts, err := GetAllSubaccounts(client, ctx, subaccountQueryClient, liqFlags.SubaccountPageLimit) if err != nil { return err } @@ -85,147 +79,6 @@ func (s *SubTaskRunnerImpl) RunLiquidationDaemonTaskLoop( return nil } -// CheckCollateralizationForSubaccounts queries a gRPC server using `AreSubaccountsLiquidatable` -// and returns a list of collateralization statuses for the given list of subaccount ids. -func CheckCollateralizationForSubaccounts( - daemon *Client, - ctx context.Context, - client clobtypes.QueryClient, - subaccountIds []satypes.SubaccountId, -) ( - results []clobtypes.AreSubaccountsLiquidatableResponse_Result, - err error, -) { - defer telemetry.ModuleMeasureSince( - metrics.LiquidationDaemon, - time.Now(), - metrics.CheckCollateralizationForSubaccounts, - metrics.Latency, - ) - - query := &clobtypes.AreSubaccountsLiquidatableRequest{ - SubaccountIds: subaccountIds, - } - response, err := client.AreSubaccountsLiquidatable(ctx, query) - if err != nil { - return nil, err - } - - return response.Results, nil -} - -// SendLiquidatableSubaccountIds sends a list of unique and potentially liquidatable -// subaccount ids to a gRPC server via `LiquidateSubaccounts`. -func SendLiquidatableSubaccountIds( - ctx context.Context, - client api.LiquidationServiceClient, - subaccountIds []satypes.SubaccountId, -) error { - defer telemetry.ModuleMeasureSince( - metrics.LiquidationDaemon, - time.Now(), - metrics.SendLiquidatableSubaccountIds, - metrics.Latency, - ) - - telemetry.ModuleSetGauge( - metrics.LiquidationDaemon, - float32(len(subaccountIds)), - metrics.LiquidatableSubaccountIds, - metrics.Count, - ) - - request := &api.LiquidateSubaccountsRequest{ - SubaccountIds: subaccountIds, - } - - if _, err := client.LiquidateSubaccounts(ctx, request); err != nil { - return err - } - return nil -} - -func getSubaccountsFromKey( - ctx context.Context, - client satypes.QueryClient, - limit uint64, - pageRequestKey []byte, -) ( - subaccounts []satypes.Subaccount, - nextKey []byte, - err error, -) { - defer metrics.ModuleMeasureSinceWithLabels( - metrics.LiquidationDaemon, - []string{metrics.GetSubaccountsFromKey, metrics.Latency}, - time.Now(), - []gometrics.Label{ - metrics.GetLabelForIntValue(metrics.PageLimit, int(limit)), - }, - ) - - query := &satypes.QueryAllSubaccountRequest{ - Pagination: &query.PageRequest{ - Key: pageRequestKey, - Limit: limit, - }, - } - - response, err := client.SubaccountAll(ctx, query) - if err != nil { - return nil, nil, err - } - if response.Pagination != nil { - nextKey = response.Pagination.NextKey - } - return response.Subaccount, nextKey, nil -} - -// GetAllSubaccounts queries a gRPC server and returns a list of subaccounts and -// their balances and open positions. -func GetAllSubaccounts( - daemon *Client, - ctx context.Context, - client satypes.QueryClient, - limit uint64, -) ( - subaccounts []satypes.Subaccount, - err error, -) { - defer telemetry.ModuleMeasureSince(metrics.LiquidationDaemon, time.Now(), metrics.GetAllSubaccounts, metrics.Latency) - subaccounts = make([]satypes.Subaccount, 0) - - var nextKey []byte - for { - subaccountsFromKey, next, err := getSubaccountsFromKey( - ctx, - client, - limit, - nextKey, - ) - - if err != nil { - return nil, err - } - - subaccounts = append(subaccounts, subaccountsFromKey...) - nextKey = next - - if len(nextKey) == 0 { - break - } - } - - telemetry.ModuleSetGauge( - metrics.LiquidationDaemon, - float32(len(subaccounts)), - metrics.GetAllSubaccounts, - metrics.Count, - ) - - return subaccounts, nil -} - // GetLiquidatableSubaccountIds verifies collateralization statuses of subaccounts with // at least one open position and returns a list of unique and potentially liquidatable subaccount ids. func GetLiquidatableSubaccountIds(