diff --git a/.github/workflows/indexer-api-documentation-check.yml b/.github/workflows/indexer-api-documentation-check.yml index f48aa9122c..976ee95002 100644 --- a/.github/workflows/indexer-api-documentation-check.yml +++ b/.github/workflows/indexer-api-documentation-check.yml @@ -6,7 +6,7 @@ on: # yamllint disable-line rule:truthy push: branches: - main - - 'release/indexer/v0.[0-9]+.x' # e.g. release/indexer/v0.1.x + - 'release/indexer/v[0-9]+.[0-9]+.x' # e.g. release/indexer/v0.1.x - 'release/indexer/v[0-9]+.x' # e.g. release/indexer/v1.x paths: - 'indexer/**' diff --git a/.github/workflows/indexer-build-and-push-dev-staging.yml b/.github/workflows/indexer-build-and-push-dev-staging.yml index 5017256872..5a98b72552 100644 --- a/.github/workflows/indexer-build-and-push-dev-staging.yml +++ b/.github/workflows/indexer-build-and-push-dev-staging.yml @@ -4,8 +4,8 @@ on: # yamllint disable-line rule:truthy push: branches: - main - - 'release/[a-z]+/v0.[0-9]+.x' # e.g. release/indexer/v0.1.x - - 'release/[a-z]+/v[0-9]+.x' # e.g. release/indexer/v1.x + - 'release/indexer/v[0-9]+.[0-9]+.x' # e.g. release/indexer/v0.1.x + - 'release/indexer/v[0-9]+.x' # e.g. release/indexer/v1.x # TODO(DEC-837): Customize github build and push to ECR by service with paths jobs: diff --git a/.github/workflows/indexer-build-and-push-mainnet.yml b/.github/workflows/indexer-build-and-push-mainnet.yml index 9d338322a4..78d54d2f68 100644 --- a/.github/workflows/indexer-build-and-push-mainnet.yml +++ b/.github/workflows/indexer-build-and-push-mainnet.yml @@ -4,8 +4,8 @@ on: # yamllint disable-line rule:truthy push: branches: - main - - 'release/[a-z]+/0.[0-9]+.x' # e.g. release/indexer/v0.1.x - - 'release/[a-z]+/v[0-9]+.x' # e.g. release/indexer/v1.x + - 'release/indexer/v[0-9]+.[0-9]+.x' # e.g. release/indexer/v0.1.x + - 'release/indexer/v[0-9]+.x' # e.g. release/indexer/v1.x # TODO(DEC-837): Customize github build and push to ECR by service with paths jobs: diff --git a/.github/workflows/indexer-build-and-push-testnet.yml b/.github/workflows/indexer-build-and-push-testnet.yml index 7d645adbbd..3cee1bf285 100644 --- a/.github/workflows/indexer-build-and-push-testnet.yml +++ b/.github/workflows/indexer-build-and-push-testnet.yml @@ -4,8 +4,8 @@ on: # yamllint disable-line rule:truthy push: branches: - main - - 'release/[a-z]+/v0.[0-9]+.x' # e.g. release/indexer/v0.1.x - - 'release/[a-z]+/v[0-9]+.x' # e.g. release/indexer/v1.x + - 'release/indexer/v[0-9]+.[0-9]+.x' # e.g. release/indexer/v0.1.x + - 'release/indexer/v[0-9]+.x' # e.g. release/indexer/v1.x # TODO(DEC-837): Customize github build and push to ECR by service with paths jobs: diff --git a/.github/workflows/indexer-build-docker-image-check.yml b/.github/workflows/indexer-build-docker-image-check.yml index 45b912b57d..f90233cb6f 100644 --- a/.github/workflows/indexer-build-docker-image-check.yml +++ b/.github/workflows/indexer-build-docker-image-check.yml @@ -7,7 +7,7 @@ on: # yamllint disable-line rule:truthy push: branches: - main - - 'release/indexer/v0.[0-9]+.x' # e.g. release/indexer/v0.1.x + - 'release/indexer/v[0-9]+.[0-9]+.x' # e.g. release/indexer/v0.1.x - 'release/indexer/v[0-9]+.x' # e.g. release/indexer/v1.x paths: - 'indexer/**' diff --git a/.github/workflows/indexer-build-test-coverage.yml b/.github/workflows/indexer-build-test-coverage.yml index c445ead932..c158f3e063 100644 --- a/.github/workflows/indexer-build-test-coverage.yml +++ b/.github/workflows/indexer-build-test-coverage.yml @@ -6,7 +6,7 @@ on: # yamllint disable-line rule:truthy push: branches: - main - - 'release/indexer/v0.[0-9]+.x' # e.g. release/indexer/v0.1.x + - 'release/indexer/v[0-9]+.[0-9]+.x' # e.g. release/indexer/v0.1.x - 'release/indexer/v[0-9]+.x' # e.g. release/indexer/v1.x paths: - 'indexer/**' diff --git a/.github/workflows/indexer-lint.yml b/.github/workflows/indexer-lint.yml index 4aab1a407d..978ae3fa4c 100644 --- a/.github/workflows/indexer-lint.yml +++ b/.github/workflows/indexer-lint.yml @@ -6,7 +6,7 @@ on: # yamllint disable-line rule:truthy push: branches: - main - - 'release/indexer/v0.[0-9]+.x' # e.g. release/indexer/v0.1.x + - 'release/indexer/v[0-9]+.[0-9]+.x' # e.g. release/indexer/v0.1.x - 'release/indexer/v[0-9]+.x' # e.g. release/indexer/v1.x paths: - 'indexer/**' diff --git a/.github/workflows/proto.yml b/.github/workflows/proto.yml index d84e84f29a..ec84ae15d5 100644 --- a/.github/workflows/proto.yml +++ b/.github/workflows/proto.yml @@ -18,7 +18,7 @@ on: # yamllint disable-line rule:truthy push: branches: - main - - 'release/protocol/v0.[0-9]+.x' # e.g. release/protocol/v0.1.x + - 'release/protocol/v[0-9]+.[0-9]+.x' # e.g. release/protocol/v0.1.x - 'release/protocol/v[0-9]+.x' # e.g. release/protocol/v1.x paths: # Keep in sync with above diff --git a/.github/workflows/protocol-build-and-push-snapshot.yml b/.github/workflows/protocol-build-and-push-snapshot.yml index 51ffb24193..e5ff2c8b05 100644 --- a/.github/workflows/protocol-build-and-push-snapshot.yml +++ b/.github/workflows/protocol-build-and-push-snapshot.yml @@ -4,8 +4,8 @@ on: # yamllint disable-line rule:truthy push: branches: - main - - 'release/[a-z]+/v0.[0-9]+.x' # e.g. release/protocol/v0.1.x - - 'release/[a-z]+/v[0-9]+.x' # e.g. release/protocol/v1.x + - 'release/protocol/v[0-9]+.[0-9]+.x' # e.g. release/protocol/v0.1.x + - 'release/protocol/v[0-9]+.x' # e.g. release/protocol/v1.x jobs: build-and-push-snapshot-dev: diff --git a/.github/workflows/protocol-build-and-push.yml b/.github/workflows/protocol-build-and-push.yml index b2463692f7..fc26dd6e69 100644 --- a/.github/workflows/protocol-build-and-push.yml +++ b/.github/workflows/protocol-build-and-push.yml @@ -4,8 +4,8 @@ on: # yamllint disable-line rule:truthy push: branches: - main - - 'release/[a-z]+/v0.[0-9]+.x' # e.g. release/protocol/v0.1.x - - 'release/[a-z]+/v[0-9]+.x' # e.g. release/protocol/v1.x + - 'release/protocol/v[0-9]+.[0-9]+.x' # e.g. release/protocol/v0.1.x + - 'release/protocol/v[0-9]+.x' # e.g. release/protocol/v1.x jobs: build-and-push-dev: diff --git a/.github/workflows/protocol-container-tests.yml b/.github/workflows/protocol-container-tests.yml index 4dcc68a4c5..ea0cda7610 100644 --- a/.github/workflows/protocol-container-tests.yml +++ b/.github/workflows/protocol-container-tests.yml @@ -6,7 +6,7 @@ on: # yamllint disable-line rule:truthy push: branches: - main - - 'release/protocol/v0.[0-9]+.x' # e.g. release/protocol/v0.1.x + - 'release/protocol/v[0-9]+.[0-9]+.x' # e.g. release/protocol/v0.1.x - 'release/protocol/v[0-9]+.x' # e.g. release/protocol/v1.x paths: - 'protocol/**' diff --git a/.github/workflows/protocol-exchange-tests.yml b/.github/workflows/protocol-exchange-tests.yml index 52c4f9de03..129f9cbc25 100644 --- a/.github/workflows/protocol-exchange-tests.yml +++ b/.github/workflows/protocol-exchange-tests.yml @@ -6,7 +6,7 @@ on: # yamllint disable-line rule:truthy push: branches: - main - - 'release/protocol/v0.[0-9]+.x' # e.g. release/protocol/v0.1.x + - 'release/protocol/v[0-9]+.[0-9]+.x' # e.g. release/protocol/v0.1.x - 'release/protocol/v[0-9]+.x' # e.g. release/protocol/v1.x paths: - 'protocol/daemons/**' diff --git a/.github/workflows/protocol-lint.yml b/.github/workflows/protocol-lint.yml index 88c7d8ce5c..350a34a43f 100644 --- a/.github/workflows/protocol-lint.yml +++ b/.github/workflows/protocol-lint.yml @@ -8,7 +8,7 @@ on: # yamllint disable-line rule:truthy push: branches: - main - - "release/protocol/v0.[0-9]+.x" # e.g. release/protocol/v0.1.x + - "release/protocol/v[0-9]+.[0-9]+.x" # e.g. release/protocol/v0.1.x - "release/protocol/v[0-9]+.x" # e.g. release/protocol/v1.x paths: - "protocol/**" diff --git a/.github/workflows/protocol-pregenesis.yml b/.github/workflows/protocol-pregenesis.yml index 44bbcd1430..691cdd1914 100644 --- a/.github/workflows/protocol-pregenesis.yml +++ b/.github/workflows/protocol-pregenesis.yml @@ -7,7 +7,7 @@ on: # yamllint disable-line rule:truthy push: branches: - main - - 'release/protocol/v0.[0-9]+.x' # e.g. release/protocol/v0.1.x + - 'release/protocol/v[0-9]+.[0-9]+.x' # e.g. release/protocol/v0.1.x - 'release/protocol/v[0-9]+.x' # e.g. release/protocol/v1.x paths: - protocol/** diff --git a/.github/workflows/protocol-sim.yml b/.github/workflows/protocol-sim.yml index 512c4164d8..dd4377b965 100644 --- a/.github/workflows/protocol-sim.yml +++ b/.github/workflows/protocol-sim.yml @@ -8,7 +8,7 @@ on: # yamllint disable-line rule:truthy push: branches: - main - - 'release/protocol/v0.[0-9]+.x' # e.g. release/protocol/v0.1.x + - 'release/protocol/v[0-9]+.[0-9]+.x' # e.g. release/protocol/v0.1.x - 'release/protocol/v[0-9]+.x' # e.g. release/protocol/v1.x paths: - 'protocol/**' diff --git a/.github/workflows/protocol-test.yml b/.github/workflows/protocol-test.yml index d831351324..3bc5d6ab3f 100644 --- a/.github/workflows/protocol-test.yml +++ b/.github/workflows/protocol-test.yml @@ -6,7 +6,7 @@ on: # yamllint disable-line rule:truthy push: branches: - main - - 'release/protocol/v0.[0-9]+.x' # e.g. release/protocol/v0.1.x + - 'release/protocol/v[0-9]+.[0-9]+.x' # e.g. release/protocol/v0.1.x - 'release/protocol/v[0-9]+.x' # e.g. release/protocol/v1.x paths: - 'protocol/**' diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/query.rpc.Query.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/query.rpc.Query.ts index 4b5ccc331b..03e7723538 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/query.rpc.Query.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/query.rpc.Query.ts @@ -1,7 +1,7 @@ import { Rpc } from "../../helpers"; import * as _m0 from "protobufjs/minimal"; import { QueryClient, createProtobufRpcClient } from "@cosmjs/stargate"; -import { QueryGetClobPairRequest, QueryClobPairResponse, QueryAllClobPairRequest, QueryClobPairAllResponse, MevNodeToNodeCalculationRequest, MevNodeToNodeCalculationResponse, QueryEquityTierLimitConfigurationRequest, QueryEquityTierLimitConfigurationResponse, QueryBlockRateLimitConfigurationRequest, QueryBlockRateLimitConfigurationResponse, QueryLiquidationsConfigurationRequest, QueryLiquidationsConfigurationResponse, StreamOrderbookUpdatesRequest, StreamOrderbookUpdatesResponse } from "./query"; +import { QueryGetClobPairRequest, QueryClobPairResponse, QueryAllClobPairRequest, QueryClobPairAllResponse, MevNodeToNodeCalculationRequest, MevNodeToNodeCalculationResponse, QueryEquityTierLimitConfigurationRequest, QueryEquityTierLimitConfigurationResponse, QueryBlockRateLimitConfigurationRequest, QueryBlockRateLimitConfigurationResponse, QueryLiquidationsConfigurationRequest, QueryLiquidationsConfigurationResponse, QueryStatefulOrderRequest, QueryStatefulOrderResponse, StreamOrderbookUpdatesRequest, StreamOrderbookUpdatesResponse } from "./query"; /** Query defines the gRPC querier service. */ export interface Query { @@ -22,6 +22,9 @@ export interface Query { /** Queries LiquidationsConfiguration. */ liquidationsConfiguration(request?: QueryLiquidationsConfigurationRequest): Promise; + /** Queries the stateful order for a given order id. */ + + statefulOrder(request: QueryStatefulOrderRequest): Promise; /** Streams orderbook updates. */ streamOrderbookUpdates(request: StreamOrderbookUpdatesRequest): Promise; @@ -37,6 +40,7 @@ export class QueryClientImpl implements Query { this.equityTierLimitConfiguration = this.equityTierLimitConfiguration.bind(this); this.blockRateLimitConfiguration = this.blockRateLimitConfiguration.bind(this); this.liquidationsConfiguration = this.liquidationsConfiguration.bind(this); + this.statefulOrder = this.statefulOrder.bind(this); this.streamOrderbookUpdates = this.streamOrderbookUpdates.bind(this); } @@ -78,6 +82,12 @@ export class QueryClientImpl implements Query { return promise.then(data => QueryLiquidationsConfigurationResponse.decode(new _m0.Reader(data))); } + statefulOrder(request: QueryStatefulOrderRequest): Promise { + const data = QueryStatefulOrderRequest.encode(request).finish(); + const promise = this.rpc.request("dydxprotocol.clob.Query", "StatefulOrder", data); + return promise.then(data => QueryStatefulOrderResponse.decode(new _m0.Reader(data))); + } + streamOrderbookUpdates(request: StreamOrderbookUpdatesRequest): Promise { const data = StreamOrderbookUpdatesRequest.encode(request).finish(); const promise = this.rpc.request("dydxprotocol.clob.Query", "StreamOrderbookUpdates", data); @@ -113,6 +123,10 @@ export const createRpcQueryExtension = (base: QueryClient) => { return queryService.liquidationsConfiguration(request); }, + statefulOrder(request: QueryStatefulOrderRequest): Promise { + return queryService.statefulOrder(request); + }, + streamOrderbookUpdates(request: StreamOrderbookUpdatesRequest): Promise { return queryService.streamOrderbookUpdates(request); } diff --git a/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/query.ts b/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/query.ts index aa31787820..938280147a 100644 --- a/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/query.ts +++ b/indexer/packages/v4-protos/src/codegen/dydxprotocol/clob/query.ts @@ -1,5 +1,6 @@ import { PageRequest, PageRequestSDKType, PageResponse, PageResponseSDKType } from "../../cosmos/base/query/v1beta1/pagination"; import { ValidatorMevMatches, ValidatorMevMatchesSDKType, MevNodeToNodeMetrics, MevNodeToNodeMetricsSDKType } from "./mev"; +import { OrderId, OrderIdSDKType, LongTermOrderPlacement, LongTermOrderPlacementSDKType } from "./order"; import { ClobPair, ClobPairSDKType } from "./clob_pair"; import { EquityTierLimitConfiguration, EquityTierLimitConfigurationSDKType } from "./equity_tier_limit_config"; import { BlockRateLimitConfiguration, BlockRateLimitConfigurationSDKType } from "./block_rate_limit_config"; @@ -171,6 +172,48 @@ export interface QueryBlockRateLimitConfigurationResponse { export interface QueryBlockRateLimitConfigurationResponseSDKType { block_rate_limit_config?: BlockRateLimitConfigurationSDKType; } +/** QueryStatefulOrderRequest is a request message for StatefulOrder. */ + +export interface QueryStatefulOrderRequest { + /** Order id to query. */ + orderId?: OrderId; +} +/** QueryStatefulOrderRequest is a request message for StatefulOrder. */ + +export interface QueryStatefulOrderRequestSDKType { + /** Order id to query. */ + order_id?: OrderIdSDKType; +} +/** + * QueryStatefulOrderResponse is a response message that contains the stateful + * order. + */ + +export interface QueryStatefulOrderResponse { + /** Stateful order placement. */ + orderPlacement?: LongTermOrderPlacement; + /** Fill amounts. */ + + fillAmount: Long; + /** Triggered status. */ + + triggered: boolean; +} +/** + * QueryStatefulOrderResponse is a response message that contains the stateful + * order. + */ + +export interface QueryStatefulOrderResponseSDKType { + /** Stateful order placement. */ + order_placement?: LongTermOrderPlacementSDKType; + /** Fill amounts. */ + + fill_amount: Long; + /** Triggered status. */ + + triggered: boolean; +} /** * QueryLiquidationsConfigurationRequest is a request message for * LiquidationsConfiguration. @@ -783,6 +826,116 @@ export const QueryBlockRateLimitConfigurationResponse = { }; +function createBaseQueryStatefulOrderRequest(): QueryStatefulOrderRequest { + return { + orderId: undefined + }; +} + +export const QueryStatefulOrderRequest = { + encode(message: QueryStatefulOrderRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.orderId !== undefined) { + OrderId.encode(message.orderId, writer.uint32(10).fork()).ldelim(); + } + + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): QueryStatefulOrderRequest { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseQueryStatefulOrderRequest(); + + while (reader.pos < end) { + const tag = reader.uint32(); + + switch (tag >>> 3) { + case 1: + message.orderId = OrderId.decode(reader, reader.uint32()); + break; + + default: + reader.skipType(tag & 7); + break; + } + } + + return message; + }, + + fromPartial(object: DeepPartial): QueryStatefulOrderRequest { + const message = createBaseQueryStatefulOrderRequest(); + message.orderId = object.orderId !== undefined && object.orderId !== null ? OrderId.fromPartial(object.orderId) : undefined; + return message; + } + +}; + +function createBaseQueryStatefulOrderResponse(): QueryStatefulOrderResponse { + return { + orderPlacement: undefined, + fillAmount: Long.UZERO, + triggered: false + }; +} + +export const QueryStatefulOrderResponse = { + encode(message: QueryStatefulOrderResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.orderPlacement !== undefined) { + LongTermOrderPlacement.encode(message.orderPlacement, writer.uint32(10).fork()).ldelim(); + } + + if (!message.fillAmount.isZero()) { + writer.uint32(16).uint64(message.fillAmount); + } + + if (message.triggered === true) { + writer.uint32(24).bool(message.triggered); + } + + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): QueryStatefulOrderResponse { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseQueryStatefulOrderResponse(); + + while (reader.pos < end) { + const tag = reader.uint32(); + + switch (tag >>> 3) { + case 1: + message.orderPlacement = LongTermOrderPlacement.decode(reader, reader.uint32()); + break; + + case 2: + message.fillAmount = (reader.uint64() as Long); + break; + + case 3: + message.triggered = reader.bool(); + break; + + default: + reader.skipType(tag & 7); + break; + } + } + + return message; + }, + + fromPartial(object: DeepPartial): QueryStatefulOrderResponse { + const message = createBaseQueryStatefulOrderResponse(); + message.orderPlacement = object.orderPlacement !== undefined && object.orderPlacement !== null ? LongTermOrderPlacement.fromPartial(object.orderPlacement) : undefined; + message.fillAmount = object.fillAmount !== undefined && object.fillAmount !== null ? Long.fromValue(object.fillAmount) : Long.UZERO; + message.triggered = object.triggered ?? false; + return message; + } + +}; + function createBaseQueryLiquidationsConfigurationRequest(): QueryLiquidationsConfigurationRequest { return {}; } diff --git a/proto/dydxprotocol/clob/query.proto b/proto/dydxprotocol/clob/query.proto index 3745756894..5151a838c6 100644 --- a/proto/dydxprotocol/clob/query.proto +++ b/proto/dydxprotocol/clob/query.proto @@ -9,6 +9,7 @@ import "dydxprotocol/clob/clob_pair.proto"; import "dydxprotocol/clob/equity_tier_limit_config.proto"; import "dydxprotocol/clob/liquidations_config.proto"; import "dydxprotocol/clob/mev.proto"; +import "dydxprotocol/clob/order.proto"; import "dydxprotocol/indexer/off_chain_updates/off_chain_updates.proto"; option go_package = "github.com/dydxprotocol/v4-chain/protocol/x/clob/types"; @@ -52,6 +53,10 @@ service Query { option (google.api.http).get = "/dydxprotocol/clob/liquidations_config"; } + // Queries the stateful order for a given order id. + rpc StatefulOrder(QueryStatefulOrderRequest) + returns (QueryStatefulOrderResponse) {} + // GRPC Streams // Streams orderbook updates. @@ -124,6 +129,25 @@ message QueryBlockRateLimitConfigurationResponse { [ (gogoproto.nullable) = false ]; } +// QueryStatefulOrderRequest is a request message for StatefulOrder. +message QueryStatefulOrderRequest { + // Order id to query. + OrderId order_id = 1 [ (gogoproto.nullable) = false ]; +} + +// QueryStatefulOrderResponse is a response message that contains the stateful +// order. +message QueryStatefulOrderResponse { + // Stateful order placement. + LongTermOrderPlacement order_placement = 1 [ (gogoproto.nullable) = false ]; + + // Fill amounts. + uint64 fill_amount = 2; + + // Triggered status. + bool triggered = 3; +} + // QueryLiquidationsConfigurationRequest is a request message for // LiquidationsConfiguration. message QueryLiquidationsConfigurationRequest {} diff --git a/protocol/app/app.go b/protocol/app/app.go index 20fd36d602..679f4e3e73 100644 --- a/protocol/app/app.go +++ b/protocol/app/app.go @@ -824,7 +824,8 @@ func New( appFlags, logger, ) - app.RegisterDaemonWithHealthMonitor(app.SlinkyClient, maxDaemonUnhealthyDuration) + app.RegisterDaemonWithHealthMonitor(app.SlinkyClient.GetMarketPairHC(), maxDaemonUnhealthyDuration) + app.RegisterDaemonWithHealthMonitor(app.SlinkyClient.GetPriceHC(), maxDaemonUnhealthyDuration) } } diff --git a/protocol/daemons/pricefeed/client/constants/logger.go b/protocol/daemons/pricefeed/client/constants/logger.go index c5fc4a1352..b417adb534 100644 --- a/protocol/daemons/pricefeed/client/constants/logger.go +++ b/protocol/daemons/pricefeed/client/constants/logger.go @@ -9,6 +9,7 @@ const ( ErrorLogKey = "error" ExchangeIdLogKey = "exchangeId" MarketIdLogKey = "marketId" + MarketIdsLogKey = "marketIds" PriceLogKey = "Price" ReasonLogKey = "reason" diff --git a/protocol/daemons/slinky/client/client.go b/protocol/daemons/slinky/client/client.go index eca04745c1..0f37a1a676 100644 --- a/protocol/daemons/slinky/client/client.go +++ b/protocol/daemons/slinky/client/client.go @@ -2,10 +2,11 @@ package client import ( "context" - "cosmossdk.io/errors" "sync" "time" + "cosmossdk.io/errors" + "cosmossdk.io/log" oracleclient "github.com/skip-mev/slinky/service/clients/oracle" @@ -17,16 +18,14 @@ import ( libtime "github.com/dydxprotocol/v4-chain/protocol/lib/time" ) -// Ensure Client is HealthCheckable -var _ daemontypes.HealthCheckable = (*Client)(nil) - // Client is the daemon implementation for pulling price data from the slinky sidecar. type Client struct { - daemontypes.HealthCheckable ctx context.Context cf context.CancelFunc marketPairFetcher MarketPairFetcher + marketPairHC daemontypes.HealthCheckable priceFetcher PriceFetcher + priceHC daemontypes.HealthCheckable wg sync.WaitGroup logger log.Logger } @@ -34,8 +33,13 @@ type Client struct { func newClient(ctx context.Context, logger log.Logger) *Client { logger = logger.With(log.ModuleKey, SlinkyClientDaemonModuleName) client := &Client{ - HealthCheckable: daemontypes.NewTimeBoundedHealthCheckable( - SlinkyClientDaemonModuleName, + marketPairHC: daemontypes.NewTimeBoundedHealthCheckable( + SlinkyClientMarketPairFetcherDaemonModuleName, + &libtime.TimeProviderImpl{}, + logger, + ), + priceHC: daemontypes.NewTimeBoundedHealthCheckable( + SlinkyClientPriceFetcherDaemonModuleName, &libtime.TimeProviderImpl{}, logger, ), @@ -45,6 +49,14 @@ func newClient(ctx context.Context, logger log.Logger) *Client { return client } +func (c *Client) GetMarketPairHC() daemontypes.HealthCheckable { + return c.marketPairHC +} + +func (c *Client) GetPriceHC() daemontypes.HealthCheckable { + return c.priceHC +} + // start creates the main goroutines of the Client. func (c *Client) start( slinky oracleclient.OracleClient, @@ -90,9 +102,9 @@ func (c *Client) RunPriceFetcher(ctx context.Context) { err := c.priceFetcher.FetchPrices(ctx) if err != nil { c.logger.Error("Failed to run fetch prices for slinky daemon", "error", err) - c.ReportFailure(errors.Wrap(err, "failed to run PriceFetcher for slinky daemon")) + c.priceHC.ReportFailure(errors.Wrap(err, "failed to run PriceFetcher for slinky daemon")) } else { - c.ReportSuccess() + c.priceHC.ReportSuccess() } case <-ctx.Done(): return @@ -124,9 +136,9 @@ func (c *Client) RunMarketPairFetcher(ctx context.Context, appFlags appflags.Fla err = c.marketPairFetcher.FetchIdMappings(ctx) if err != nil { c.logger.Error("Failed to run fetch id mappings for slinky daemon", "error", err) - c.ReportFailure(errors.Wrap(err, "failed to run FetchIdMappings for slinky daemon")) + c.marketPairHC.ReportFailure(errors.Wrap(err, "failed to run FetchIdMappings for slinky daemon")) } else { - c.ReportSuccess() + c.marketPairHC.ReportSuccess() } case <-ctx.Done(): return diff --git a/protocol/daemons/slinky/client/client_test.go b/protocol/daemons/slinky/client/client_test.go index 3c52eb339e..7f39835918 100644 --- a/protocol/daemons/slinky/client/client_test.go +++ b/protocol/daemons/slinky/client/client_test.go @@ -73,7 +73,7 @@ func TestClient(t *testing.T) { ) waitTime := time.Second * 5 require.Eventually(t, func() bool { - return cli.HealthCheck() == nil + return cli.GetMarketPairHC().HealthCheck() == nil && cli.GetPriceHC().HealthCheck() == nil }, waitTime, time.Millisecond*500, "Slinky daemon failed to become healthy within %s", waitTime) cli.Stop() } diff --git a/protocol/daemons/slinky/client/constants.go b/protocol/daemons/slinky/client/constants.go index f69c43c84e..aa711e69b9 100644 --- a/protocol/daemons/slinky/client/constants.go +++ b/protocol/daemons/slinky/client/constants.go @@ -16,5 +16,7 @@ var ( const ( // SlinkyClientDaemonModuleName is the module name used in logging. - SlinkyClientDaemonModuleName = "slinky-client-daemon" + SlinkyClientDaemonModuleName = "slinky-client-daemon" + SlinkyClientPriceFetcherDaemonModuleName = "slinky-client-price-fetcher-daemon" + SlinkyClientMarketPairFetcherDaemonModuleName = "slinky-client-market-pair-fetcher-daemon" ) diff --git a/protocol/daemons/types/health_checkable.go b/protocol/daemons/types/health_checkable.go index 92c283c2c4..b1d344fb2b 100644 --- a/protocol/daemons/types/health_checkable.go +++ b/protocol/daemons/types/health_checkable.go @@ -1,11 +1,12 @@ package types import ( - "cosmossdk.io/log" "fmt" - libtime "github.com/dydxprotocol/v4-chain/protocol/lib/time" "sync" "time" + + "cosmossdk.io/log" + libtime "github.com/dydxprotocol/v4-chain/protocol/lib/time" ) const ( diff --git a/protocol/go.mod b/protocol/go.mod index eab085922c..8d52693909 100644 --- a/protocol/go.mod +++ b/protocol/go.mod @@ -431,7 +431,7 @@ replace ( // Use dYdX fork of CometBFT github.com/cometbft/cometbft => github.com/dydxprotocol/cometbft v0.38.6-0.20240426214049-c8beeeada40a // Use dYdX fork of Cosmos SDK - github.com/cosmos/cosmos-sdk => github.com/dydxprotocol/cosmos-sdk v0.50.6-0.20240326192503-dd116391188d + github.com/cosmos/cosmos-sdk => github.com/dydxprotocol/cosmos-sdk v0.50.6-0.20240517185527-7330926cd9ad github.com/cosmos/iavl => github.com/dydxprotocol/iavl v1.1.1-0.20240509161911-1c8b8e787e85 ) diff --git a/protocol/go.sum b/protocol/go.sum index f8de67656b..32b744c64d 100644 --- a/protocol/go.sum +++ b/protocol/go.sum @@ -527,8 +527,8 @@ github.com/dvsekhvalnov/jose2go v1.6.0 h1:Y9gnSnP4qEI0+/uQkHvFXeD2PLPJeXEL+ySMEA github.com/dvsekhvalnov/jose2go v1.6.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/dydxprotocol/cometbft v0.38.6-0.20240426214049-c8beeeada40a h1:KeQZZsYJQ/AKQ6lbP5lL3N/6aOclxxYG8pIm8zerwZw= github.com/dydxprotocol/cometbft v0.38.6-0.20240426214049-c8beeeada40a/go.mod h1:EBEod7kZfNr4W0VooOrTEMSiXNrSyiQ/M2FL/rOcPCs= -github.com/dydxprotocol/cosmos-sdk v0.50.6-0.20240326192503-dd116391188d h1:kHT+xXpjwdKO2drqMEFSN1J6VjEoOweYPIH4RrQ3IWs= -github.com/dydxprotocol/cosmos-sdk v0.50.6-0.20240326192503-dd116391188d/go.mod h1:NruCXox2SOkVq2ZC5Bs8s2sT+jjVqBEU59wXyZOkCkM= +github.com/dydxprotocol/cosmos-sdk v0.50.6-0.20240517185527-7330926cd9ad h1:MSDTYJmDtN1q9MnwfH9l69yPdFAgCwEoBKbonKtjEVs= +github.com/dydxprotocol/cosmos-sdk v0.50.6-0.20240517185527-7330926cd9ad/go.mod h1:NruCXox2SOkVq2ZC5Bs8s2sT+jjVqBEU59wXyZOkCkM= github.com/dydxprotocol/cosmos-sdk/store v1.0.3-0.20240326192503-dd116391188d h1:HgLu1FD2oDFzlKW6/+SFXlH5Os8cwNTbplQIrQOWx8w= github.com/dydxprotocol/cosmos-sdk/store v1.0.3-0.20240326192503-dd116391188d/go.mod h1:zMcD3hfNwd0WMTpdRUhS3QxoCoEtBXWeoKsu3iaLBbQ= github.com/dydxprotocol/iavl v1.1.1-0.20240509161911-1c8b8e787e85 h1:5B/yGZyTBX/OZASQQMnk6Ms/TZja56MYd8OBaVc0Mho= diff --git a/protocol/indexer/shared/order_removal_reason.go b/protocol/indexer/shared/order_removal_reason.go index ce7f1f3570..866b527160 100644 --- a/protocol/indexer/shared/order_removal_reason.go +++ b/protocol/indexer/shared/order_removal_reason.go @@ -51,6 +51,8 @@ func GetOrderRemovalReason( return sharedtypes.OrderRemovalReason_ORDER_REMOVAL_REASON_FOK_ORDER_COULD_NOT_BE_FULLY_FULLED, nil case errors.Is(orderError, clobtypes.ErrOrderWouldExceedMaxOpenOrdersEquityTierLimit): return sharedtypes.OrderRemovalReason_ORDER_REMOVAL_REASON_EQUITY_TIER, nil + case errors.Is(orderError, clobtypes.ErrWouldViolateIsolatedSubaccountConstraints): + return sharedtypes.OrderRemovalReason_ORDER_REMOVAL_REASON_VIOLATES_ISOLATED_SUBACCOUNT_CONSTRAINTS, nil } switch orderStatus { diff --git a/protocol/indexer/shared/order_removal_reason_test.go b/protocol/indexer/shared/order_removal_reason_test.go index 9ad0d770dc..8ef6acd602 100644 --- a/protocol/indexer/shared/order_removal_reason_test.go +++ b/protocol/indexer/shared/order_removal_reason_test.go @@ -55,6 +55,11 @@ func TestGetOrderRemovalReason_Success(t *testing.T) { expectedReason: sharedtypes.OrderRemovalReason_ORDER_REMOVAL_REASON_REDUCE_ONLY_RESIZE, expectedErr: nil, }, + "Gets order removal reason for order error ErrWouldViolateIsolatedSubaccountConstraints": { + orderError: clobtypes.ErrWouldViolateIsolatedSubaccountConstraints, + expectedReason: sharedtypes.OrderRemovalReason_ORDER_REMOVAL_REASON_VIOLATES_ISOLATED_SUBACCOUNT_CONSTRAINTS, + expectedErr: nil, + }, "Returns error for order status Success": { orderStatus: clobtypes.Success, orderError: clobtypes.ErrNotImplemented, diff --git a/protocol/mocks/QueryClient.go b/protocol/mocks/QueryClient.go index 81b7f9a05f..68b73c59c3 100644 --- a/protocol/mocks/QueryClient.go +++ b/protocol/mocks/QueryClient.go @@ -881,6 +881,43 @@ func (_m *QueryClient) PreviousBlockInfo(ctx context.Context, in *types.QueryPre return r0, r1 } +// StatefulOrder provides a mock function with given fields: ctx, in, opts +func (_m *QueryClient) StatefulOrder(ctx context.Context, in *clobtypes.QueryStatefulOrderRequest, opts ...grpc.CallOption) (*clobtypes.QueryStatefulOrderResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for StatefulOrder") + } + + var r0 *clobtypes.QueryStatefulOrderResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *clobtypes.QueryStatefulOrderRequest, ...grpc.CallOption) (*clobtypes.QueryStatefulOrderResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *clobtypes.QueryStatefulOrderRequest, ...grpc.CallOption) *clobtypes.QueryStatefulOrderResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*clobtypes.QueryStatefulOrderResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *clobtypes.QueryStatefulOrderRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // StreamOrderbookUpdates provides a mock function with given fields: ctx, in, opts func (_m *QueryClient) StreamOrderbookUpdates(ctx context.Context, in *clobtypes.StreamOrderbookUpdatesRequest, opts ...grpc.CallOption) (clobtypes.Query_StreamOrderbookUpdatesClient, error) { _va := make([]interface{}, len(opts)) diff --git a/protocol/x/clob/client/cli/query.go b/protocol/x/clob/client/cli/query.go index d6dcb9025d..6c7a49f77c 100644 --- a/protocol/x/clob/client/cli/query.go +++ b/protocol/x/clob/client/cli/query.go @@ -26,6 +26,7 @@ func GetQueryCmd(queryRoute string) *cobra.Command { cmd.AddCommand(CmdGetBlockRateLimitConfiguration()) cmd.AddCommand(CmdGetEquityTierLimitConfig()) cmd.AddCommand(CmdGetLiquidationsConfiguration()) + cmd.AddCommand(CmdQueryStatefulOrder()) return cmd } diff --git a/protocol/x/clob/client/cli/query_stateful_order.go b/protocol/x/clob/client/cli/query_stateful_order.go new file mode 100644 index 0000000000..09cf30dc8e --- /dev/null +++ b/protocol/x/clob/client/cli/query_stateful_order.go @@ -0,0 +1,70 @@ +package cli + +import ( + "context" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" + satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" + "github.com/spf13/cast" + "github.com/spf13/cobra" +) + +func CmdQueryStatefulOrder() *cobra.Command { + cmd := &cobra.Command{ + Use: "stateful-order subaccount_owner subaccount_number client_id clob_pair_id order_flags", + Short: "queries a stateful order by id", + Args: cobra.ExactArgs(5), + RunE: func(cmd *cobra.Command, args []string) (err error) { + clientCtx := client.GetClientContextFromCmd(cmd) + + queryClient := types.NewQueryClient(clientCtx) + + owner := args[0] + + number, err := cast.ToUint32E(args[1]) + if err != nil { + return err + } + + clientId, err := cast.ToUint32E(args[2]) + if err != nil { + return err + } + + clobPairId, err := cast.ToUint32E(args[3]) + if err != nil { + return err + } + + orderFlag, err := cast.ToUint32E(args[4]) + if err != nil { + return err + } + + req := &types.QueryStatefulOrderRequest{ + OrderId: types.OrderId{ + SubaccountId: satypes.SubaccountId{ + Owner: owner, + Number: number, + }, + ClientId: clientId, + ClobPairId: clobPairId, + OrderFlags: orderFlag, + }, + } + + res, err := queryClient.StatefulOrder(context.Background(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/protocol/x/clob/e2e/equity_tier_limit_test.go b/protocol/x/clob/e2e/equity_tier_limit_test.go index b3189357db..ebd9360062 100644 --- a/protocol/x/clob/e2e/equity_tier_limit_test.go +++ b/protocol/x/clob/e2e/equity_tier_limit_test.go @@ -2,6 +2,9 @@ package clob_test import ( "fmt" + "testing" + "time" + "github.com/cometbft/cometbft/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/dydxprotocol/v4-chain/protocol/dtypes" @@ -11,8 +14,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" - "time" ) func TestPlaceOrder_EquityTierLimit(t *testing.T) { @@ -25,68 +26,6 @@ func TestPlaceOrder_EquityTierLimit(t *testing.T) { expectError bool crashingAppCheckTxNonDeterminsmChecksDisabled bool }{ - "Short-term order would exceed max open short-term orders in same block": { - allowedOrders: []clobtypes.Order{ - testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob0_Buy5_Price10_GTB20, - testapp.DefaultGenesis(), - ), - }, - limitedOrder: testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob1_Buy5_Price10_GTB15, - testapp.DefaultGenesis(), - ), - equityTierLimitConfiguration: clobtypes.EquityTierLimitConfiguration{ - ShortTermOrderEquityTiers: []clobtypes.EquityTierLimit{ - { - UsdTncRequired: dtypes.NewInt(0), - Limit: 0, - }, - { - UsdTncRequired: dtypes.NewInt(5_000_000_000), // $5,000 - Limit: 1, - }, - { - UsdTncRequired: dtypes.NewInt(70_000_000_000), // $70,000 - Limit: 100, - }, - }, - }, - expectError: true, - }, - "Short-term order would exceed max open short-term orders in same block with multiple orders": { - allowedOrders: []clobtypes.Order{ - testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob0_Buy5_Price10_GTB20, - testapp.DefaultGenesis(), - ), - testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob1_Buy5_Price10_GTB15, - testapp.DefaultGenesis(), - ), - }, - limitedOrder: testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob0_Buy6_Price10_GTB20, - testapp.DefaultGenesis(), - ), - equityTierLimitConfiguration: clobtypes.EquityTierLimitConfiguration{ - ShortTermOrderEquityTiers: []clobtypes.EquityTierLimit{ - { - UsdTncRequired: dtypes.NewInt(0), - Limit: 0, - }, - { - UsdTncRequired: dtypes.NewInt(5_000_000_000), // $5,000 - Limit: 2, - }, - { - UsdTncRequired: dtypes.NewInt(70_000_000_000), // $70,000 - Limit: 100, - }, - }, - }, - expectError: true, - }, "Long-term order would exceed max open stateful orders in same block": { allowedOrders: []clobtypes.Order{ testapp.MustScaleOrder( @@ -211,38 +150,6 @@ func TestPlaceOrder_EquityTierLimit(t *testing.T) { }, expectError: true, }, - "Short-term order would exceed max open short-term orders across blocks": { - allowedOrders: []clobtypes.Order{ - testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob0_Buy5_Price10_GTB20, - testapp.DefaultGenesis(), - ), - }, - limitedOrder: testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob1_Buy5_Price10_GTB15, - testapp.DefaultGenesis(), - ), - equityTierLimitConfiguration: clobtypes.EquityTierLimitConfiguration{ - ShortTermOrderEquityTiers: []clobtypes.EquityTierLimit{ - { - UsdTncRequired: dtypes.NewInt(0), - Limit: 0, - }, - { - UsdTncRequired: dtypes.NewInt(5_000_000_000), // $5,000 - Limit: 1, - }, - { - UsdTncRequired: dtypes.NewInt(70_000_000_000), // $70,000 - Limit: 100, - }, - }, - }, - advanceBlock: true, - expectError: true, - // The short-term order will be forgotten when restarting the app. - crashingAppCheckTxNonDeterminsmChecksDisabled: true, - }, "Long-term order would exceed max open stateful orders across blocks": { allowedOrders: []clobtypes.Order{ testapp.MustScaleOrder( @@ -393,38 +300,6 @@ func TestPlaceOrder_EquityTierLimit(t *testing.T) { advanceBlock: true, expectError: true, }, - "Order cancellation prevents exceeding max open short-term orders for short-term order in same block": { - allowedOrders: []clobtypes.Order{ - testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob0_Buy5_Price10_GTB20, - testapp.DefaultGenesis(), - ), - }, - limitedOrder: testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob1_Buy5_Price10_GTB15, - testapp.DefaultGenesis(), - ), - cancellation: clobtypes.NewMsgCancelOrderShortTerm( - constants.Order_Alice_Num0_Id0_Clob0_Buy5_Price10_GTB20.OrderId, - constants.Order_Alice_Num0_Id0_Clob0_Buy5_Price10_GTB20.GetGoodTilBlock(), - ), - equityTierLimitConfiguration: clobtypes.EquityTierLimitConfiguration{ - ShortTermOrderEquityTiers: []clobtypes.EquityTierLimit{ - { - UsdTncRequired: dtypes.NewInt(0), - Limit: 0, - }, - { - UsdTncRequired: dtypes.NewInt(5_000_000_000), // $5,000 - Limit: 1, - }, - { - UsdTncRequired: dtypes.NewInt(70_000_000_000), // $70,000 - Limit: 100, - }, - }, - }, - }, "Order cancellation prevents exceeding max open stateful orders for long-term order in same block": { allowedOrders: []clobtypes.Order{ testapp.MustScaleOrder( @@ -522,41 +397,6 @@ func TestPlaceOrder_EquityTierLimit(t *testing.T) { }, }, }, - "Order cancellation prevents exceeding max open short-term orders for short-term order across blocks": { - allowedOrders: []clobtypes.Order{ - testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob0_Buy5_Price10_GTB20, - testapp.DefaultGenesis(), - ), - }, - limitedOrder: testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob1_Buy5_Price10_GTB15, - testapp.DefaultGenesis(), - ), - cancellation: clobtypes.NewMsgCancelOrderShortTerm( - constants.Order_Alice_Num0_Id0_Clob0_Buy5_Price10_GTB20.OrderId, - constants.Order_Alice_Num0_Id0_Clob0_Buy5_Price10_GTB20.GetGoodTilBlock(), - ), - equityTierLimitConfiguration: clobtypes.EquityTierLimitConfiguration{ - ShortTermOrderEquityTiers: []clobtypes.EquityTierLimit{ - { - UsdTncRequired: dtypes.NewInt(0), - Limit: 0, - }, - { - UsdTncRequired: dtypes.NewInt(5_000_000_000), // $5,000 - Limit: 1, - }, - { - UsdTncRequired: dtypes.NewInt(70_000_000_000), // $70,000 - Limit: 100, - }, - }, - }, - advanceBlock: true, - // The short-term order & cancel will be forgotten when restarting the app. - crashingAppCheckTxNonDeterminsmChecksDisabled: true, - }, "Order cancellation prevents exceeding max open stateful orders for long-term order across blocks": { allowedOrders: []clobtypes.Order{ testapp.MustScaleOrder( @@ -737,65 +577,6 @@ func TestPlaceOrder_EquityTierLimit_OrderExpiry(t *testing.T) { expectError bool crashingAppCheckTxNonDeterminsmChecksDisabled bool }{ - "Short-term order has not expired": { - firstOrder: testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob1_Buy5_Price10_GTB15, - testapp.DefaultGenesis(), - ), - secondOrder: testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob0_Buy5_Price10_GTB20, - testapp.DefaultGenesis(), - ), - equityTierLimitConfiguration: clobtypes.EquityTierLimitConfiguration{ - ShortTermOrderEquityTiers: []clobtypes.EquityTierLimit{ - { - UsdTncRequired: dtypes.NewInt(0), - Limit: 0, - }, - { - UsdTncRequired: dtypes.NewInt(5_000_000_000), // $5,000 - Limit: 1, - }, - { - UsdTncRequired: dtypes.NewInt(70_000_000_000), // $70,000 - Limit: 100, - }, - }, - }, - advanceToBlockAndTime: 14, - expectError: true, - // Short term order will be forgotten on app restart. - crashingAppCheckTxNonDeterminsmChecksDisabled: true, - }, - "Short-term order has expired": { - firstOrder: testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob1_Buy5_Price10_GTB15, - testapp.DefaultGenesis(), - ), - secondOrder: testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob0_Buy5_Price10_GTB20, - testapp.DefaultGenesis(), - ), - equityTierLimitConfiguration: clobtypes.EquityTierLimitConfiguration{ - ShortTermOrderEquityTiers: []clobtypes.EquityTierLimit{ - { - UsdTncRequired: dtypes.NewInt(0), - Limit: 0, - }, - { - UsdTncRequired: dtypes.NewInt(5_000_000_000), // $5,000 - Limit: 1, - }, - { - UsdTncRequired: dtypes.NewInt(70_000_000_000), // $70,000 - Limit: 100, - }, - }, - }, - advanceToBlockAndTime: 15, - // Short term order will be forgotten on app restart. - crashingAppCheckTxNonDeterminsmChecksDisabled: true, - }, "Stateful order has not expired": { firstOrder: testapp.MustScaleOrder( constants.LongTermOrder_Alice_Num0_Id0_Clob1_Buy5_Price10_GTBT5, @@ -911,132 +692,6 @@ func TestPlaceOrder_EquityTierLimit_OrderFill(t *testing.T) { expectError bool crashingAppCheckTxNonDeterminsmChecksDisabled bool }{ - "Fully filled order prevents exceeding max open short-term orders for short-term order in same block": { - makerOrder: testapp.MustScaleOrder( - constants.Order_Bob_Num0_Id8_Clob0_Sell20_Price10_GTB22, - testapp.DefaultGenesis(), - ), - takerOrder: testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob0_Buy5_Price10_GTB20, - testapp.DefaultGenesis(), - ), - extraOrder: testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob1_Buy5_Price10_GTB15, - testapp.DefaultGenesis(), - ), - equityTierLimitConfiguration: clobtypes.EquityTierLimitConfiguration{ - ShortTermOrderEquityTiers: []clobtypes.EquityTierLimit{ - { - UsdTncRequired: dtypes.NewInt(0), - Limit: 0, - }, - { - UsdTncRequired: dtypes.NewInt(5_000_000_000), // $5,000 - Limit: 1, - }, - { - UsdTncRequired: dtypes.NewInt(70_000_000_000), // $70,000 - Limit: 100, - }, - }, - }, - }, - "Partially filled order causes new short-term order to exceed max open short-term orders in same block": { - makerOrder: testapp.MustScaleOrder( - constants.Order_Bob_Num0_Id8_Clob0_Sell20_Price10_GTB22, - testapp.DefaultGenesis(), - ), - takerOrder: testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob0_Buy35_Price10_GTB20, - testapp.DefaultGenesis(), - ), - extraOrder: testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob1_Buy5_Price10_GTB15, - testapp.DefaultGenesis(), - ), - equityTierLimitConfiguration: clobtypes.EquityTierLimitConfiguration{ - ShortTermOrderEquityTiers: []clobtypes.EquityTierLimit{ - { - UsdTncRequired: dtypes.NewInt(0), - Limit: 0, - }, - { - UsdTncRequired: dtypes.NewInt(5_000_000_000), // $5,000 - Limit: 1, - }, - { - UsdTncRequired: dtypes.NewInt(70_000_000_000), // $70,000 - Limit: 100, - }, - }, - }, - expectError: true, - }, - "Fully filled order prevents exceeding max open short-term orders for short-term order across blocks": { - makerOrder: testapp.MustScaleOrder( - constants.Order_Bob_Num0_Id8_Clob0_Sell20_Price10_GTB22, - testapp.DefaultGenesis(), - ), - takerOrder: testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob0_Buy5_Price10_GTB20, - testapp.DefaultGenesis(), - ), - extraOrder: testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob1_Buy5_Price10_GTB15, - testapp.DefaultGenesis(), - ), - equityTierLimitConfiguration: clobtypes.EquityTierLimitConfiguration{ - ShortTermOrderEquityTiers: []clobtypes.EquityTierLimit{ - { - UsdTncRequired: dtypes.NewInt(0), - Limit: 0, - }, - { - UsdTncRequired: dtypes.NewInt(5_000_000_000), // $5,000 - Limit: 1, - }, - { - UsdTncRequired: dtypes.NewInt(70_000_000_000), // $70,000 - Limit: 100, - }, - }, - }, - advanceBlock: true, - }, - "Partially filled order causes new short-term order to exceed max open short-term orders across blocks": { - makerOrder: testapp.MustScaleOrder( - constants.Order_Bob_Num0_Id8_Clob0_Sell20_Price10_GTB22, - testapp.DefaultGenesis(), - ), - takerOrder: testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob0_Buy35_Price10_GTB20, - testapp.DefaultGenesis(), - ), - extraOrder: testapp.MustScaleOrder( - constants.Order_Alice_Num0_Id0_Clob1_Buy5_Price10_GTB15, - testapp.DefaultGenesis(), - ), - equityTierLimitConfiguration: clobtypes.EquityTierLimitConfiguration{ - ShortTermOrderEquityTiers: []clobtypes.EquityTierLimit{ - { - UsdTncRequired: dtypes.NewInt(0), - Limit: 0, - }, - { - UsdTncRequired: dtypes.NewInt(5_000_000_000), // $5,000 - Limit: 1, - }, - { - UsdTncRequired: dtypes.NewInt(70_000_000_000), // $70,000 - Limit: 100, - }, - }, - }, - advanceBlock: true, - expectError: true, - // The short-term order will be forgotten when restarting the app. - crashingAppCheckTxNonDeterminsmChecksDisabled: true, - }, "Order fully filled prevents exceeding max open stateful orders for conditional order across blocks": { makerOrder: testapp.MustScaleOrder( constants.LongTermOrder_Bob_Num0_Id0_Clob0_Sell5_Price5_GTBT10, diff --git a/protocol/x/clob/keeper/equity_tier_limit.go b/protocol/x/clob/keeper/equity_tier_limit.go index be4df49446..15ff5cb6ee 100644 --- a/protocol/x/clob/keeper/equity_tier_limit.go +++ b/protocol/x/clob/keeper/equity_tier_limit.go @@ -95,6 +95,9 @@ func (k Keeper) getEquityTierLimitForSubaccount( return equityTierLimit, nil, nil } +// Deprecated: Equity tier limits were removed for short term orders. +// See https://github.com/dydxprotocol/v4-chain/pull/1318. +// // ValidateSubaccountEquityTierLimitForShortTermOrder returns an error if adding the order would exceed the equity // tier limit on how many short term open orders a subaccount can have. Short-term fill-or-kill and immediate-or-cancel // orders never rest on the book and will always be allowed as they do not apply to the number of open orders that diff --git a/protocol/x/clob/keeper/grpc_query_stateful_order.go b/protocol/x/clob/keeper/grpc_query_stateful_order.go new file mode 100644 index 0000000000..5fdb365695 --- /dev/null +++ b/protocol/x/clob/keeper/grpc_query_stateful_order.go @@ -0,0 +1,43 @@ +package keeper + +import ( + "context" + + "github.com/dydxprotocol/v4-chain/protocol/lib" + "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func (k Keeper) StatefulOrder( + c context.Context, + req *types.QueryStatefulOrderRequest, +) (*types.QueryStatefulOrderResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + ctx := lib.UnwrapSDKContext(c, types.ModuleName) + + val, found := k.GetLongTermOrderPlacement( + ctx, + req.OrderId, + ) + if !found { + return nil, status.Error(codes.NotFound, "not found") + } + + res := &types.QueryStatefulOrderResponse{ + OrderPlacement: val, + } + + // Get the fill amount + _, fillAmount, _ := k.GetOrderFillAmount(ctx, req.OrderId) + res.FillAmount = fillAmount.ToUint64() + + // Get triggered status for conditional orders + if req.OrderId.IsConditionalOrder() { + res.Triggered = k.IsConditionalOrderTriggered(ctx, req.OrderId) + } + + return res, nil +} diff --git a/protocol/x/clob/keeper/grpc_query_stateful_order_test.go b/protocol/x/clob/keeper/grpc_query_stateful_order_test.go new file mode 100644 index 0000000000..f99791d838 --- /dev/null +++ b/protocol/x/clob/keeper/grpc_query_stateful_order_test.go @@ -0,0 +1,52 @@ +package keeper_test + +import ( + "testing" + + testApp "github.com/dydxprotocol/v4-chain/protocol/testutil/app" + "github.com/dydxprotocol/v4-chain/protocol/testutil/constants" + "github.com/dydxprotocol/v4-chain/protocol/x/clob/types" + "github.com/stretchr/testify/require" +) + +func TestStatefulOrderTest(t *testing.T) { + tApp := testApp.NewTestAppBuilder(t).Build() + ctx := tApp.InitChain() + + tApp.App.ClobKeeper.SetLongTermOrderPlacement( + ctx, + constants.LongTermOrder_Alice_Num0_Id0_Clob0_Buy100_Price10_GTBT15, + 1, + ) + + tApp.App.ClobKeeper.SetOrderFillAmount( + ctx, + constants.LongTermOrder_Alice_Num0_Id0_Clob0_Buy100_Price10_GTBT15.OrderId, + 5, + 123456789, + ) + + res, err := tApp.App.ClobKeeper.StatefulOrder( + ctx, + &types.QueryStatefulOrderRequest{ + OrderId: constants.LongTermOrder_Alice_Num0_Id0_Clob0_Buy100_Price10_GTBT15.OrderId, + }, + ) + + require.NoError(t, err) + require.Equal( + t, + &types.QueryStatefulOrderResponse{ + OrderPlacement: types.LongTermOrderPlacement{ + Order: constants.LongTermOrder_Alice_Num0_Id0_Clob0_Buy100_Price10_GTBT15, + PlacementIndex: types.TransactionOrdering{ + BlockHeight: 1, + TransactionIndex: 0, + }, + }, + FillAmount: 5, + Triggered: false, + }, + res, + ) +} diff --git a/protocol/x/clob/keeper/orders.go b/protocol/x/clob/keeper/orders.go index aaeca84de0..9986580930 100644 --- a/protocol/x/clob/keeper/orders.go +++ b/protocol/x/clob/keeper/orders.go @@ -167,7 +167,6 @@ func (k Keeper) CancelShortTermOrder( // // An error will be returned if any of the following conditions are true: // - Standard stateful validation fails. -// - The subaccount's equity tier limit is exceeded. // - Placing the short term order on the memclob returns an error. // // This method will panic if the provided order is not a Short-Term order. @@ -208,12 +207,6 @@ func (k Keeper) PlaceShortTermOrder( return 0, 0, err } - // Validate that adding the order wouldn't exceed subaccount equity tier limits. - err = k.ValidateSubaccountEquityTierLimitForShortTermOrder(ctx, order) - if err != nil { - return 0, 0, err - } - // Place the order on the memclob and return the result. orderSizeOptimisticallyFilledFromMatchingQuantums, orderStatus, offchainUpdates, err := k.MemClob.PlaceOrder( ctx, diff --git a/protocol/x/clob/keeper/orders_test.go b/protocol/x/clob/keeper/orders_test.go index da10a4b948..c01b27aaba 100644 --- a/protocol/x/clob/keeper/orders_test.go +++ b/protocol/x/clob/keeper/orders_test.go @@ -578,32 +578,6 @@ func TestPlaceShortTermOrder(t *testing.T) { constants.EthUsd_20PercentInitial_10PercentMaintenance.Params.Id: big.NewInt(2_000_000_000), }, }, - `Subaccount cannot place maker buy order for 1 BTC at 5 subticks with 0 collateral`: { - perpetuals: []perptypes.Perpetual{ - constants.BtcUsd_50PercentInitial_40PercentMaintenance, - }, - subaccounts: []satypes.Subaccount{constants.Carl_Num0_0USD}, - clobs: []types.ClobPair{ - constants.ClobPair_Btc, - }, - existingOrders: []types.Order{}, - feeParams: constants.PerpetualFeeParamsNoFee, - order: constants.Order_Carl_Num0_Id0_Clob0_Buy1BTC_Price5subticks_GTB10, - expectedErr: types.ErrOrderWouldExceedMaxOpenOrdersEquityTierLimit, - }, - `Subaccount cannot place maker sell order for 1 BTC at 500,000 with 0 collateral`: { - perpetuals: []perptypes.Perpetual{ - constants.BtcUsd_50PercentInitial_40PercentMaintenance, - }, - subaccounts: []satypes.Subaccount{constants.Carl_Num0_0USD}, - clobs: []types.ClobPair{ - constants.ClobPair_Btc, - }, - existingOrders: []types.Order{}, - feeParams: constants.PerpetualFeeParamsNoFee, - order: constants.Order_Carl_Num0_Id0_Clob0_Sell1BTC_Price500000_GTB10, - expectedErr: types.ErrOrderWouldExceedMaxOpenOrdersEquityTierLimit, - }, // // The following 3 tests are a group to test the deprecation of pessimistic collateralization check. // 1. The first should have a buy price well below the oracle price of 50,000. (success) diff --git a/protocol/x/clob/module_test.go b/protocol/x/clob/module_test.go index 9035ae7f56..d926d8ec4c 100644 --- a/protocol/x/clob/module_test.go +++ b/protocol/x/clob/module_test.go @@ -251,12 +251,13 @@ func TestAppModuleBasic_GetQueryCmd(t *testing.T) { cmd := am.GetQueryCmd() require.Equal(t, "clob", cmd.Use) - require.Equal(t, 5, len(cmd.Commands())) + require.Equal(t, 6, len(cmd.Commands())) require.Equal(t, "get-block-rate-limit-config", cmd.Commands()[0].Name()) require.Equal(t, "get-equity-tier-limit-config", cmd.Commands()[1].Name()) require.Equal(t, "get-liquidations-config", cmd.Commands()[2].Name()) require.Equal(t, "list-clob-pair", cmd.Commands()[3].Name()) require.Equal(t, "show-clob-pair", cmd.Commands()[4].Name()) + require.Equal(t, "stateful-order", cmd.Commands()[5].Name()) } func TestAppModule_Name(t *testing.T) { diff --git a/protocol/x/clob/types/query.pb.go b/protocol/x/clob/types/query.pb.go index ee500746b5..d8ecfb7bf6 100644 --- a/protocol/x/clob/types/query.pb.go +++ b/protocol/x/clob/types/query.pb.go @@ -568,6 +568,117 @@ func (m *QueryBlockRateLimitConfigurationResponse) GetBlockRateLimitConfig() Blo return BlockRateLimitConfiguration{} } +// QueryStatefulOrderRequest is a request message for StatefulOrder. +type QueryStatefulOrderRequest struct { + // Order id to query. + OrderId OrderId `protobuf:"bytes,1,opt,name=order_id,json=orderId,proto3" json:"order_id"` +} + +func (m *QueryStatefulOrderRequest) Reset() { *m = QueryStatefulOrderRequest{} } +func (m *QueryStatefulOrderRequest) String() string { return proto.CompactTextString(m) } +func (*QueryStatefulOrderRequest) ProtoMessage() {} +func (*QueryStatefulOrderRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_3365c195b25c5bc0, []int{10} +} +func (m *QueryStatefulOrderRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryStatefulOrderRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryStatefulOrderRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryStatefulOrderRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryStatefulOrderRequest.Merge(m, src) +} +func (m *QueryStatefulOrderRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryStatefulOrderRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryStatefulOrderRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryStatefulOrderRequest proto.InternalMessageInfo + +func (m *QueryStatefulOrderRequest) GetOrderId() OrderId { + if m != nil { + return m.OrderId + } + return OrderId{} +} + +// QueryStatefulOrderResponse is a response message that contains the stateful +// order. +type QueryStatefulOrderResponse struct { + // Stateful order placement. + OrderPlacement LongTermOrderPlacement `protobuf:"bytes,1,opt,name=order_placement,json=orderPlacement,proto3" json:"order_placement"` + // Fill amounts. + FillAmount uint64 `protobuf:"varint,2,opt,name=fill_amount,json=fillAmount,proto3" json:"fill_amount,omitempty"` + // Triggered status. + Triggered bool `protobuf:"varint,3,opt,name=triggered,proto3" json:"triggered,omitempty"` +} + +func (m *QueryStatefulOrderResponse) Reset() { *m = QueryStatefulOrderResponse{} } +func (m *QueryStatefulOrderResponse) String() string { return proto.CompactTextString(m) } +func (*QueryStatefulOrderResponse) ProtoMessage() {} +func (*QueryStatefulOrderResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_3365c195b25c5bc0, []int{11} +} +func (m *QueryStatefulOrderResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryStatefulOrderResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryStatefulOrderResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryStatefulOrderResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryStatefulOrderResponse.Merge(m, src) +} +func (m *QueryStatefulOrderResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryStatefulOrderResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryStatefulOrderResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryStatefulOrderResponse proto.InternalMessageInfo + +func (m *QueryStatefulOrderResponse) GetOrderPlacement() LongTermOrderPlacement { + if m != nil { + return m.OrderPlacement + } + return LongTermOrderPlacement{} +} + +func (m *QueryStatefulOrderResponse) GetFillAmount() uint64 { + if m != nil { + return m.FillAmount + } + return 0 +} + +func (m *QueryStatefulOrderResponse) GetTriggered() bool { + if m != nil { + return m.Triggered + } + return false +} + // QueryLiquidationsConfigurationRequest is a request message for // LiquidationsConfiguration. type QueryLiquidationsConfigurationRequest struct { @@ -577,7 +688,7 @@ func (m *QueryLiquidationsConfigurationRequest) Reset() { *m = QueryLiqu func (m *QueryLiquidationsConfigurationRequest) String() string { return proto.CompactTextString(m) } func (*QueryLiquidationsConfigurationRequest) ProtoMessage() {} func (*QueryLiquidationsConfigurationRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_3365c195b25c5bc0, []int{10} + return fileDescriptor_3365c195b25c5bc0, []int{12} } func (m *QueryLiquidationsConfigurationRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -618,7 +729,7 @@ func (m *QueryLiquidationsConfigurationResponse) Reset() { func (m *QueryLiquidationsConfigurationResponse) String() string { return proto.CompactTextString(m) } func (*QueryLiquidationsConfigurationResponse) ProtoMessage() {} func (*QueryLiquidationsConfigurationResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_3365c195b25c5bc0, []int{11} + return fileDescriptor_3365c195b25c5bc0, []int{13} } func (m *QueryLiquidationsConfigurationResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -665,7 +776,7 @@ func (m *StreamOrderbookUpdatesRequest) Reset() { *m = StreamOrderbookUp func (m *StreamOrderbookUpdatesRequest) String() string { return proto.CompactTextString(m) } func (*StreamOrderbookUpdatesRequest) ProtoMessage() {} func (*StreamOrderbookUpdatesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_3365c195b25c5bc0, []int{12} + return fileDescriptor_3365c195b25c5bc0, []int{14} } func (m *StreamOrderbookUpdatesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -722,7 +833,7 @@ func (m *StreamOrderbookUpdatesResponse) Reset() { *m = StreamOrderbookU func (m *StreamOrderbookUpdatesResponse) String() string { return proto.CompactTextString(m) } func (*StreamOrderbookUpdatesResponse) ProtoMessage() {} func (*StreamOrderbookUpdatesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_3365c195b25c5bc0, []int{13} + return fileDescriptor_3365c195b25c5bc0, []int{15} } func (m *StreamOrderbookUpdatesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -791,6 +902,8 @@ func init() { proto.RegisterType((*QueryEquityTierLimitConfigurationResponse)(nil), "dydxprotocol.clob.QueryEquityTierLimitConfigurationResponse") proto.RegisterType((*QueryBlockRateLimitConfigurationRequest)(nil), "dydxprotocol.clob.QueryBlockRateLimitConfigurationRequest") proto.RegisterType((*QueryBlockRateLimitConfigurationResponse)(nil), "dydxprotocol.clob.QueryBlockRateLimitConfigurationResponse") + proto.RegisterType((*QueryStatefulOrderRequest)(nil), "dydxprotocol.clob.QueryStatefulOrderRequest") + proto.RegisterType((*QueryStatefulOrderResponse)(nil), "dydxprotocol.clob.QueryStatefulOrderResponse") proto.RegisterType((*QueryLiquidationsConfigurationRequest)(nil), "dydxprotocol.clob.QueryLiquidationsConfigurationRequest") proto.RegisterType((*QueryLiquidationsConfigurationResponse)(nil), "dydxprotocol.clob.QueryLiquidationsConfigurationResponse") proto.RegisterType((*StreamOrderbookUpdatesRequest)(nil), "dydxprotocol.clob.StreamOrderbookUpdatesRequest") @@ -800,77 +913,86 @@ func init() { func init() { proto.RegisterFile("dydxprotocol/clob/query.proto", fileDescriptor_3365c195b25c5bc0) } var fileDescriptor_3365c195b25c5bc0 = []byte{ - // 1112 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xcd, 0x4f, 0x24, 0x45, - 0x14, 0xa7, 0x00, 0x77, 0xe1, 0xb1, 0x6b, 0xb4, 0x58, 0xd8, 0x71, 0x80, 0x01, 0x5a, 0xf9, 0xdc, - 0xd8, 0x0d, 0xec, 0xc6, 0xac, 0xac, 0xd9, 0x04, 0x88, 0xa2, 0xc9, 0xe2, 0x62, 0xbb, 0xa2, 0xd1, - 0x4d, 0x3a, 0x35, 0xdd, 0xc5, 0x4c, 0x85, 0xee, 0xae, 0xa1, 0xbb, 0xa6, 0x03, 0x31, 0xc6, 0xc4, - 0x83, 0x17, 0x3d, 0x98, 0x78, 0xf0, 0xe0, 0xd1, 0xbb, 0xff, 0x81, 0x51, 0x6f, 0x7b, 0xdc, 0xc4, - 0xc4, 0x78, 0x30, 0xc6, 0x80, 0x67, 0xff, 0x86, 0x4d, 0x57, 0xd7, 0xcc, 0xce, 0xd0, 0x1f, 0x03, - 0x5c, 0x66, 0xba, 0x5f, 0xfd, 0xde, 0xeb, 0xdf, 0xfb, 0xa8, 0x5f, 0x15, 0x4c, 0x39, 0xc7, 0xce, - 0x51, 0x23, 0xe0, 0x82, 0xdb, 0xdc, 0x35, 0x6c, 0x97, 0x57, 0x8d, 0xc3, 0x26, 0x0d, 0x8e, 0x75, - 0x69, 0xc3, 0x2f, 0x77, 0x2e, 0xeb, 0xf1, 0x72, 0xf9, 0x46, 0x8d, 0xd7, 0xb8, 0x34, 0x19, 0xf1, - 0x53, 0x02, 0x2c, 0x4f, 0xd6, 0x38, 0xaf, 0xb9, 0xd4, 0x20, 0x0d, 0x66, 0x10, 0xdf, 0xe7, 0x82, - 0x08, 0xc6, 0xfd, 0x50, 0xad, 0x2e, 0xdb, 0x3c, 0xf4, 0x78, 0x68, 0x54, 0x49, 0x48, 0x93, 0xf8, - 0x46, 0xb4, 0x5a, 0xa5, 0x82, 0xac, 0x1a, 0x0d, 0x52, 0x63, 0xbe, 0x04, 0x2b, 0xac, 0x91, 0x66, - 0x54, 0x75, 0xb9, 0x7d, 0x60, 0x05, 0x44, 0x50, 0xcb, 0x65, 0x1e, 0x13, 0x96, 0xcd, 0xfd, 0x7d, - 0x56, 0x53, 0x0e, 0xb3, 0x69, 0x87, 0xf8, 0xc7, 0x6a, 0x10, 0x16, 0x28, 0xc8, 0x4a, 0x1a, 0x42, - 0x0f, 0x9b, 0x4c, 0x1c, 0x5b, 0x82, 0xd1, 0x20, 0x2b, 0xe8, 0xad, 0xb4, 0x87, 0xcb, 0x0e, 0x9b, - 0xcc, 0x49, 0xf2, 0xea, 0x06, 0x4f, 0xa4, 0xc1, 0x1e, 0x8d, 0xd4, 0xe2, 0xfd, 0xae, 0x45, 0xe6, - 0x3b, 0xf4, 0x88, 0x06, 0x06, 0xdf, 0xdf, 0xb7, 0xec, 0x3a, 0x61, 0xbe, 0xd5, 0x6c, 0x38, 0x44, - 0xd0, 0x30, 0x6d, 0x49, 0xfc, 0xb5, 0x25, 0xb8, 0xf9, 0x41, 0x5c, 0xb1, 0x6d, 0x2a, 0xb6, 0x5c, - 0x5e, 0xdd, 0x25, 0x2c, 0x30, 0xe9, 0x61, 0x93, 0x86, 0x02, 0xbf, 0x08, 0xfd, 0xcc, 0x29, 0xa1, - 0x19, 0xb4, 0x78, 0xdd, 0xec, 0x67, 0x8e, 0xf6, 0x31, 0x8c, 0x49, 0xe8, 0x73, 0x5c, 0xd8, 0xe0, - 0x7e, 0x48, 0xf1, 0x7d, 0x18, 0x6e, 0x97, 0x44, 0xe2, 0x47, 0xd6, 0x26, 0xf4, 0x54, 0x6b, 0xf5, - 0x96, 0xdf, 0xe6, 0xe0, 0x93, 0x7f, 0xa6, 0xfb, 0xcc, 0x21, 0x5b, 0xbd, 0x6b, 0x44, 0x71, 0xd8, - 0x70, 0xdd, 0xb3, 0x1c, 0xde, 0x01, 0x78, 0xde, 0x42, 0x15, 0x7b, 0x5e, 0x4f, 0xfa, 0xad, 0xc7, - 0xfd, 0xd6, 0x93, 0x79, 0x52, 0xfd, 0xd6, 0x77, 0x49, 0x8d, 0x2a, 0x5f, 0xb3, 0xc3, 0x53, 0xfb, - 0x09, 0x41, 0xa9, 0x8b, 0xfc, 0x86, 0xeb, 0xe6, 0xf1, 0x1f, 0xb8, 0x20, 0x7f, 0xbc, 0xdd, 0x45, - 0xb2, 0x5f, 0x92, 0x5c, 0xe8, 0x49, 0x32, 0xf9, 0x78, 0x17, 0xcb, 0xbf, 0x11, 0x4c, 0xef, 0xd0, - 0xe8, 0x7d, 0xee, 0xd0, 0x47, 0x3c, 0xfe, 0xdd, 0x22, 0xae, 0xdd, 0x74, 0xe5, 0x62, 0xab, 0x22, - 0x8f, 0x61, 0x3c, 0x19, 0xd8, 0x46, 0xc0, 0x1b, 0x3c, 0xa4, 0x81, 0xe5, 0x11, 0x61, 0xd7, 0x69, - 0xd8, 0xae, 0x4e, 0x9a, 0xf9, 0x1e, 0x71, 0xe3, 0xd1, 0xe2, 0xc1, 0x0e, 0x8d, 0x76, 0x12, 0xb4, - 0x79, 0x43, 0x46, 0xd9, 0x55, 0x41, 0x94, 0x15, 0x7f, 0x06, 0x63, 0x51, 0x0b, 0x6c, 0x79, 0x34, - 0xb2, 0x3c, 0x2a, 0x02, 0x66, 0x87, 0xed, 0xac, 0xd2, 0xc1, 0xbb, 0x08, 0xef, 0x24, 0x70, 0x73, - 0x34, 0xea, 0xfc, 0x64, 0x62, 0xd4, 0xfe, 0x47, 0x30, 0x93, 0x9f, 0x9e, 0x6a, 0x46, 0x0d, 0xae, - 0x06, 0x34, 0x6c, 0xba, 0x22, 0x54, 0xad, 0xd8, 0xee, 0xf5, 0xcd, 0x8c, 0x28, 0x31, 0x60, 0xc3, - 0x77, 0xf6, 0xb8, 0xdb, 0xf4, 0xe8, 0x2e, 0x0d, 0xe2, 0xd6, 0xa9, 0xb6, 0xb5, 0xa2, 0x97, 0x09, - 0x8c, 0x66, 0xa0, 0xf0, 0x0c, 0x5c, 0x6b, 0x0f, 0x83, 0xd5, 0x9e, 0x7f, 0x68, 0x35, 0xfb, 0x3d, - 0x07, 0xbf, 0x04, 0x03, 0x1e, 0x8d, 0x64, 0x45, 0xfa, 0xcd, 0xf8, 0x11, 0x8f, 0xc3, 0x95, 0x48, - 0x06, 0x29, 0x0d, 0xcc, 0xa0, 0xc5, 0x41, 0x53, 0xbd, 0x69, 0xcb, 0xb0, 0x28, 0x87, 0xee, 0x6d, - 0xa9, 0x06, 0x8f, 0x18, 0x0d, 0x1e, 0xc4, 0x5a, 0xb0, 0x25, 0x77, 0x77, 0x33, 0xe8, 0xec, 0xab, - 0xf6, 0x23, 0x82, 0xa5, 0x73, 0x80, 0x55, 0x95, 0x7c, 0x28, 0xe5, 0x49, 0x8c, 0x9a, 0x03, 0x23, - 0xa3, 0x6c, 0x45, 0xa1, 0x55, 0x79, 0xc6, 0x68, 0x16, 0x46, 0x5b, 0x82, 0x05, 0x49, 0x6e, 0x33, - 0x1e, 0x1a, 0x93, 0x08, 0x9a, 0x9f, 0xc8, 0x0f, 0x48, 0x65, 0x5d, 0x88, 0x55, 0x79, 0x1c, 0xc0, - 0xcd, 0x1c, 0xf9, 0x55, 0x69, 0xe8, 0x19, 0x69, 0x14, 0x04, 0x56, 0x59, 0x24, 0xc3, 0x7d, 0x06, - 0xa2, 0x2d, 0xc0, 0x9c, 0x24, 0xf6, 0xa0, 0x43, 0x6a, 0x33, 0x53, 0xf8, 0x1a, 0xc1, 0x7c, 0x2f, - 0xa4, 0x4a, 0xe0, 0x31, 0x8c, 0x66, 0x28, 0xb7, 0x22, 0x3f, 0x97, 0x41, 0x3e, 0x1d, 0x52, 0x71, - 0xc6, 0x6e, 0x6a, 0x45, 0xdb, 0x80, 0xa9, 0x0f, 0x45, 0x40, 0x89, 0xf7, 0x30, 0x70, 0x68, 0x50, - 0xe5, 0xfc, 0xe0, 0xa3, 0x44, 0xbd, 0x5b, 0x6a, 0x90, 0x9e, 0xd6, 0x81, 0xee, 0x69, 0xd5, 0xfe, - 0x44, 0x50, 0xc9, 0x8b, 0xa1, 0x72, 0xf8, 0x04, 0xae, 0xaa, 0x43, 0x41, 0x6d, 0xb9, 0xbb, 0xdd, - 0xbc, 0xd5, 0xa9, 0xa2, 0xa7, 0xcf, 0x90, 0x87, 0xfb, 0xfb, 0x5b, 0xb1, 0x21, 0x89, 0xb8, 0xb7, - 0xda, 0xda, 0x63, 0x6a, 0x1d, 0x97, 0x61, 0x28, 0xf4, 0x49, 0x23, 0xac, 0x73, 0x21, 0xf7, 0xcb, - 0x90, 0xd9, 0x7e, 0xc7, 0xb3, 0x70, 0x2d, 0x69, 0x7d, 0x9d, 0xb2, 0x5a, 0x5d, 0xc8, 0xad, 0x73, - 0xdd, 0x1c, 0x91, 0xb6, 0x77, 0xa5, 0x09, 0x4f, 0xc0, 0x30, 0x3d, 0xa2, 0xb6, 0xe5, 0x71, 0x87, - 0x96, 0x06, 0xe5, 0xfa, 0x50, 0x6c, 0xd8, 0xe1, 0x0e, 0x5d, 0xfb, 0x79, 0x18, 0x5e, 0x90, 0x4d, - 0xc2, 0xdf, 0x20, 0x18, 0x6a, 0x89, 0x33, 0x5e, 0xce, 0xa8, 0x79, 0xce, 0x09, 0x57, 0x5e, 0xcc, - 0xc3, 0x9e, 0x3d, 0xe2, 0xb4, 0xa5, 0xaf, 0xfe, 0xf8, 0xef, 0xfb, 0xfe, 0x57, 0xf1, 0xac, 0x51, - 0x70, 0x1d, 0x30, 0x3e, 0x67, 0xce, 0x17, 0xf8, 0x5b, 0x04, 0x23, 0x1d, 0xa7, 0x4c, 0x3e, 0xa1, - 0xf4, 0x71, 0x57, 0xbe, 0xd5, 0x8b, 0x50, 0xc7, 0xb1, 0xa5, 0xbd, 0x26, 0x39, 0x55, 0xf0, 0x64, - 0x11, 0x27, 0xfc, 0x2b, 0x82, 0x52, 0x9e, 0x5c, 0xe2, 0xb5, 0x0b, 0x69, 0x6b, 0xc2, 0xf1, 0xf6, - 0x25, 0xf4, 0x58, 0x5b, 0x97, 0x5c, 0xef, 0xac, 0xa3, 0x65, 0xcd, 0x30, 0x32, 0xef, 0x33, 0x96, - 0xcf, 0x1d, 0x6a, 0x09, 0x9e, 0xfc, 0xdb, 0x1d, 0x24, 0x7f, 0x47, 0x30, 0x59, 0xa4, 0x5c, 0xf8, - 0x5e, 0x5e, 0xd5, 0xce, 0xa1, 0xbb, 0xe5, 0xb7, 0x2e, 0xe7, 0xac, 0xf2, 0x9a, 0x97, 0x79, 0xcd, - 0xe0, 0x8a, 0x51, 0x78, 0x07, 0xc4, 0xbf, 0x20, 0x98, 0x28, 0x90, 0x2d, 0xbc, 0x9e, 0xc7, 0xa2, - 0xb7, 0xe0, 0x96, 0xef, 0x5d, 0xca, 0x57, 0x25, 0x30, 0x27, 0x13, 0x98, 0xc6, 0x53, 0x85, 0x17, - 0x63, 0xfc, 0x1b, 0x82, 0x57, 0x72, 0xc5, 0x10, 0xdf, 0xcd, 0x63, 0xd0, 0x4b, 0x69, 0xcb, 0x6f, - 0x5e, 0xc2, 0x53, 0x31, 0xd7, 0x25, 0xf3, 0x45, 0x3c, 0x6f, 0x9c, 0xeb, 0x32, 0x8d, 0xbf, 0x84, - 0xf1, 0x6c, 0x1d, 0xc4, 0x2b, 0x19, 0x24, 0x0a, 0x65, 0xb7, 0xbc, 0x7a, 0x01, 0x8f, 0x84, 0xee, - 0x0a, 0xda, 0xdc, 0x7d, 0x72, 0x52, 0x41, 0x4f, 0x4f, 0x2a, 0xe8, 0xdf, 0x93, 0x0a, 0xfa, 0xee, - 0xb4, 0xd2, 0xf7, 0xf4, 0xb4, 0xd2, 0xf7, 0xd7, 0x69, 0xa5, 0xef, 0xd3, 0x37, 0x6a, 0x4c, 0xd4, - 0x9b, 0x55, 0xdd, 0xe6, 0x5e, 0x77, 0x32, 0xd1, 0x9d, 0xd7, 0xa5, 0xe0, 0x1a, 0x6d, 0xcb, 0x51, - 0x92, 0xa0, 0x38, 0x6e, 0xd0, 0xb0, 0x7a, 0x45, 0x9a, 0x6f, 0x3f, 0x0b, 0x00, 0x00, 0xff, 0xff, - 0xf1, 0xed, 0x1e, 0x02, 0x67, 0x0d, 0x00, 0x00, + // 1251 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0xcd, 0x6f, 0xdc, 0x44, + 0x14, 0x8f, 0x93, 0xd0, 0x6e, 0x5f, 0xda, 0x02, 0xd3, 0xaf, 0xad, 0x93, 0x6e, 0x52, 0x43, 0x3e, + 0x4b, 0xed, 0x24, 0xad, 0x50, 0x49, 0x50, 0xa5, 0x24, 0x82, 0x50, 0x29, 0xa1, 0x8b, 0x1b, 0x42, + 0x05, 0x95, 0x2c, 0xaf, 0x3d, 0xeb, 0xb5, 0x62, 0x7b, 0x36, 0xf6, 0x78, 0x95, 0x08, 0x21, 0x24, + 0x0e, 0x5c, 0xe0, 0x80, 0xc4, 0x81, 0x03, 0x12, 0x17, 0xfe, 0x06, 0x8e, 0x08, 0xb8, 0xf5, 0x58, + 0x09, 0x09, 0x71, 0x40, 0x08, 0x25, 0x9c, 0xf9, 0x1b, 0x90, 0x67, 0xc6, 0x9b, 0xdd, 0xd8, 0xde, + 0x4d, 0x72, 0xd9, 0x5d, 0xbf, 0xf7, 0x7b, 0x6f, 0x7e, 0xef, 0x63, 0xde, 0xf3, 0xc2, 0x2d, 0x7b, + 0xdf, 0xde, 0x6b, 0x86, 0x84, 0x12, 0x8b, 0x78, 0x9a, 0xe5, 0x91, 0x9a, 0xb6, 0x1b, 0xe3, 0x70, + 0x5f, 0x65, 0x32, 0xf4, 0x6a, 0xa7, 0x5a, 0x4d, 0xd4, 0xf2, 0x55, 0x87, 0x38, 0x84, 0x89, 0xb4, + 0xe4, 0x17, 0x07, 0xca, 0x63, 0x0e, 0x21, 0x8e, 0x87, 0x35, 0xb3, 0xe9, 0x6a, 0x66, 0x10, 0x10, + 0x6a, 0x52, 0x97, 0x04, 0x91, 0xd0, 0xce, 0x59, 0x24, 0xf2, 0x49, 0xa4, 0xd5, 0xcc, 0x08, 0x73, + 0xff, 0x5a, 0x6b, 0xa1, 0x86, 0xa9, 0xb9, 0xa0, 0x35, 0x4d, 0xc7, 0x0d, 0x18, 0x58, 0x60, 0xb5, + 0x2c, 0xa3, 0x9a, 0x47, 0xac, 0x1d, 0x23, 0x34, 0x29, 0x36, 0x3c, 0xd7, 0x77, 0xa9, 0x61, 0x91, + 0xa0, 0xee, 0x3a, 0xc2, 0xe0, 0x76, 0xd6, 0x20, 0xf9, 0x30, 0x9a, 0xa6, 0x1b, 0x0a, 0xc8, 0x7c, + 0x16, 0x82, 0x77, 0x63, 0x97, 0xee, 0x1b, 0xd4, 0xc5, 0x61, 0x9e, 0xd3, 0x3b, 0x59, 0x0b, 0xcf, + 0xdd, 0x8d, 0x5d, 0x9b, 0xc7, 0xd5, 0x0d, 0x1e, 0xcd, 0x82, 0x7d, 0xdc, 0x12, 0xca, 0x9c, 0x0c, + 0x93, 0xd0, 0xc6, 0x29, 0xb5, 0x87, 0x5d, 0x6a, 0x37, 0xb0, 0xf1, 0x1e, 0x0e, 0x35, 0x52, 0xaf, + 0x1b, 0x56, 0xc3, 0x74, 0x03, 0x23, 0x6e, 0xda, 0x26, 0xc5, 0x51, 0x56, 0xc2, 0xed, 0x95, 0x59, + 0xb8, 0xf1, 0x41, 0x92, 0xd0, 0x75, 0x4c, 0xd7, 0x3c, 0x52, 0xab, 0x9a, 0x6e, 0xa8, 0xe3, 0xdd, + 0x18, 0x47, 0x14, 0x5d, 0x86, 0x41, 0xd7, 0x2e, 0x4b, 0x13, 0xd2, 0xcc, 0x25, 0x7d, 0xd0, 0xb5, + 0x95, 0x8f, 0xe0, 0x1a, 0x83, 0x1e, 0xe1, 0xa2, 0x26, 0x09, 0x22, 0x8c, 0x1e, 0xc2, 0x85, 0x76, + 0xc6, 0x18, 0x7e, 0x64, 0x71, 0x54, 0xcd, 0x54, 0x5e, 0x4d, 0xed, 0x56, 0x87, 0x9f, 0xff, 0x3d, + 0x3e, 0xa0, 0x97, 0x2c, 0xf1, 0xac, 0x98, 0x82, 0xc3, 0x8a, 0xe7, 0x1d, 0xe7, 0xf0, 0x2e, 0xc0, + 0x51, 0x85, 0x85, 0xef, 0x29, 0x95, 0xb7, 0x83, 0x9a, 0xb4, 0x83, 0xca, 0xdb, 0x4d, 0xb4, 0x83, + 0x5a, 0x35, 0x1d, 0x2c, 0x6c, 0xf5, 0x0e, 0x4b, 0xe5, 0x47, 0x09, 0xca, 0x5d, 0xe4, 0x57, 0x3c, + 0xaf, 0x88, 0xff, 0xd0, 0x29, 0xf9, 0xa3, 0xf5, 0x2e, 0x92, 0x83, 0x8c, 0xe4, 0x74, 0x5f, 0x92, + 0xfc, 0xf0, 0x2e, 0x96, 0x7f, 0x49, 0x30, 0xbe, 0x89, 0x5b, 0xef, 0x13, 0x1b, 0x6f, 0x91, 0xe4, + 0x73, 0xcd, 0xf4, 0xac, 0xd8, 0x63, 0xca, 0x34, 0x23, 0xcf, 0xe0, 0x3a, 0xef, 0xe7, 0x66, 0x48, + 0x9a, 0x24, 0xc2, 0xa1, 0xe1, 0x9b, 0xd4, 0x6a, 0xe0, 0xa8, 0x9d, 0x9d, 0x2c, 0xf3, 0x6d, 0xd3, + 0x4b, 0x3a, 0x8f, 0x84, 0x9b, 0xb8, 0xb5, 0xc9, 0xd1, 0xfa, 0x55, 0xe6, 0xa5, 0x2a, 0x9c, 0x08, + 0x29, 0xfa, 0x04, 0xae, 0xb5, 0x52, 0xb0, 0xe1, 0xe3, 0x96, 0xe1, 0x63, 0x1a, 0xba, 0x56, 0xd4, + 0x8e, 0x2a, 0xeb, 0xbc, 0x8b, 0xf0, 0x26, 0x87, 0xeb, 0x57, 0x5a, 0x9d, 0x47, 0x72, 0xa1, 0xf2, + 0x9f, 0x04, 0x13, 0xc5, 0xe1, 0x89, 0x62, 0x38, 0x70, 0x3e, 0xc4, 0x51, 0xec, 0xd1, 0x48, 0x94, + 0x62, 0xbd, 0xdf, 0x99, 0x39, 0x5e, 0x12, 0xc0, 0x4a, 0x60, 0x6f, 0x13, 0x2f, 0xf6, 0x71, 0x15, + 0x87, 0x49, 0xe9, 0x44, 0xd9, 0x52, 0xef, 0xb2, 0x09, 0x57, 0x72, 0x50, 0x68, 0x02, 0x2e, 0xb6, + 0x9b, 0xc1, 0x68, 0xf7, 0x3f, 0xa4, 0xc5, 0x7e, 0x64, 0xa3, 0x57, 0x60, 0xc8, 0xc7, 0x2d, 0x96, + 0x91, 0x41, 0x3d, 0xf9, 0x89, 0xae, 0xc3, 0xb9, 0x16, 0x73, 0x52, 0x1e, 0x9a, 0x90, 0x66, 0x86, + 0x75, 0xf1, 0xa4, 0xcc, 0xc1, 0x0c, 0x6b, 0xba, 0x77, 0xd8, 0xb0, 0xd8, 0x72, 0x71, 0xb8, 0x91, + 0x8c, 0x8a, 0x35, 0x76, 0xf9, 0xe3, 0xb0, 0xb3, 0xae, 0xca, 0xf7, 0x12, 0xcc, 0x9e, 0x00, 0x2c, + 0xb2, 0x14, 0x40, 0xb9, 0x68, 0x02, 0x89, 0x3e, 0xd0, 0x72, 0xd2, 0xd6, 0xcb, 0xb5, 0x48, 0xcf, + 0x35, 0x9c, 0x87, 0x51, 0x66, 0x61, 0x9a, 0x91, 0x5b, 0x4d, 0x9a, 0x46, 0x37, 0x29, 0x2e, 0x0e, + 0xe4, 0x3b, 0x49, 0x44, 0xdd, 0x13, 0x2b, 0xe2, 0xd8, 0x81, 0x1b, 0x05, 0xd3, 0x59, 0x84, 0xa1, + 0xe6, 0x84, 0xd1, 0xc3, 0xb1, 0x88, 0x82, 0x37, 0xf7, 0x31, 0x88, 0xf2, 0x14, 0x6e, 0x32, 0x62, + 0x4f, 0xa8, 0x49, 0x71, 0x3d, 0xf6, 0x1e, 0x27, 0x73, 0x34, 0xbd, 0x57, 0xcb, 0x50, 0x62, 0x73, + 0x35, 0xad, 0xf9, 0xc8, 0xa2, 0x9c, 0x73, 0x34, 0x33, 0x79, 0x64, 0xa7, 0xbd, 0x44, 0xf8, 0xa3, + 0xf2, 0x93, 0x04, 0x72, 0x9e, 0x6b, 0x11, 0xe5, 0x53, 0x78, 0x99, 0xfb, 0x6e, 0x7a, 0xa6, 0x85, + 0x7d, 0x1c, 0x50, 0x71, 0xc4, 0x6c, 0xce, 0x11, 0x1b, 0x24, 0x70, 0xb6, 0x70, 0xe8, 0x33, 0x17, + 0xd5, 0xd4, 0x40, 0x9c, 0x78, 0x99, 0x74, 0x49, 0xd1, 0x38, 0x8c, 0xd4, 0x5d, 0xcf, 0x33, 0x4c, + 0x9f, 0xc4, 0x01, 0x65, 0x3d, 0x39, 0xac, 0x43, 0x22, 0x5a, 0x61, 0x12, 0x34, 0x06, 0x17, 0x68, + 0xe8, 0x3a, 0x0e, 0x0e, 0xb1, 0xcd, 0xba, 0xb3, 0xa4, 0x1f, 0x09, 0x94, 0x69, 0x98, 0x64, 0xb4, + 0x37, 0x3a, 0x76, 0x53, 0x6e, 0x51, 0xbf, 0x94, 0x60, 0xaa, 0x1f, 0x52, 0x04, 0xfb, 0x0c, 0xae, + 0xe4, 0xac, 0x3a, 0x11, 0xf0, 0x64, 0x5e, 0xc0, 0x19, 0x97, 0x22, 0x58, 0xe4, 0x65, 0x34, 0xca, + 0x0a, 0xdc, 0x7a, 0x42, 0x43, 0x6c, 0xf2, 0xf4, 0xd4, 0x08, 0xd9, 0xf9, 0x90, 0xef, 0xb3, 0xb4, + 0x8e, 0xd9, 0xfb, 0x3b, 0xd4, 0x7d, 0x7f, 0x95, 0x3f, 0x24, 0xa8, 0x14, 0xf9, 0x68, 0x17, 0xec, + 0xbc, 0x58, 0x93, 0x62, 0x08, 0x3d, 0xe8, 0xe6, 0x2d, 0xf6, 0xac, 0x9a, 0xdd, 0xaa, 0x8f, 0xeb, + 0xf5, 0xb5, 0x44, 0xc0, 0x3d, 0x6e, 0x2f, 0xa4, 0x9d, 0x22, 0xf4, 0x48, 0x86, 0x52, 0x14, 0x98, + 0xcd, 0xa8, 0x41, 0x78, 0xb5, 0x4a, 0x7a, 0xfb, 0x19, 0xdd, 0x86, 0x8b, 0xfc, 0x32, 0x34, 0xb0, + 0xeb, 0x34, 0x28, 0x2b, 0xd7, 0x25, 0x7d, 0x84, 0xc9, 0xde, 0x63, 0x22, 0x34, 0x0a, 0x17, 0xf0, + 0x1e, 0xb6, 0x0c, 0x9f, 0xd8, 0xb8, 0x3c, 0xcc, 0xf4, 0xa5, 0x44, 0xb0, 0x49, 0x6c, 0xbc, 0xf8, + 0x03, 0xc0, 0x4b, 0xac, 0x48, 0xe8, 0x2b, 0x09, 0x4a, 0xe9, 0xba, 0x42, 0x73, 0x39, 0x39, 0x2f, + 0xd8, 0xf9, 0xf2, 0x4c, 0x11, 0xf6, 0xf8, 0xd2, 0x57, 0x66, 0xbf, 0xf8, 0xfd, 0xdf, 0x6f, 0x07, + 0x5f, 0x43, 0xb7, 0xb5, 0x1e, 0xef, 0x4f, 0xda, 0xa7, 0xae, 0xfd, 0x19, 0xfa, 0x5a, 0x82, 0x91, + 0x8e, 0xbd, 0x5b, 0x4c, 0x28, 0xfb, 0x02, 0x20, 0xdf, 0xe9, 0x47, 0xa8, 0x63, 0x91, 0x2b, 0xaf, + 0x33, 0x4e, 0x15, 0x34, 0xd6, 0x8b, 0x13, 0xfa, 0x45, 0x82, 0x72, 0xd1, 0x02, 0x41, 0x8b, 0xa7, + 0xda, 0x36, 0x9c, 0xe3, 0xbd, 0x33, 0x6c, 0x28, 0x65, 0x89, 0x71, 0xbd, 0xbf, 0x24, 0xcd, 0x29, + 0x9a, 0x96, 0xfb, 0x02, 0x68, 0x04, 0xc4, 0xc6, 0x06, 0x25, 0xfc, 0xdb, 0xea, 0x20, 0xf9, 0x9b, + 0x04, 0x63, 0xbd, 0x66, 0x39, 0x5a, 0x2e, 0xca, 0xda, 0x09, 0x36, 0x91, 0xfc, 0xf6, 0xd9, 0x8c, + 0x45, 0x5c, 0x53, 0x2c, 0xae, 0x09, 0x54, 0xd1, 0x7a, 0xbe, 0x34, 0xa3, 0x9f, 0x25, 0x18, 0xed, + 0x31, 0xc8, 0xd1, 0x52, 0x11, 0x8b, 0xfe, 0x2b, 0x48, 0x5e, 0x3e, 0x93, 0xad, 0x08, 0x60, 0x92, + 0x05, 0x30, 0x8e, 0x6e, 0xf5, 0xfc, 0x27, 0x81, 0x7e, 0x95, 0xe0, 0x66, 0xe1, 0x30, 0x44, 0x0f, + 0x8a, 0x18, 0xf4, 0x9b, 0xb4, 0xf2, 0x5b, 0x67, 0xb0, 0x14, 0xcc, 0x55, 0xc6, 0x7c, 0x06, 0x4d, + 0x69, 0x27, 0xfa, 0xf7, 0x81, 0x02, 0xb8, 0xd4, 0xb5, 0xaf, 0xd0, 0x1b, 0x45, 0x67, 0xe7, 0x6d, + 0x4c, 0xf9, 0xee, 0x09, 0xd1, 0x82, 0xdd, 0x00, 0xfa, 0x1c, 0xae, 0xe7, 0xcf, 0x5d, 0x34, 0x9f, + 0xe3, 0xaa, 0xe7, 0x98, 0x97, 0x17, 0x4e, 0x61, 0xc1, 0x09, 0xcc, 0x4b, 0xab, 0xd5, 0xe7, 0x07, + 0x15, 0xe9, 0xc5, 0x41, 0x45, 0xfa, 0xe7, 0xa0, 0x22, 0x7d, 0x73, 0x58, 0x19, 0x78, 0x71, 0x58, + 0x19, 0xf8, 0xf3, 0xb0, 0x32, 0xf0, 0xf1, 0x9b, 0x8e, 0x4b, 0x1b, 0x71, 0x4d, 0xb5, 0x88, 0xdf, + 0x9d, 0xbc, 0xd6, 0xfd, 0xbb, 0x6c, 0xc0, 0x6b, 0x6d, 0xc9, 0x1e, 0x4f, 0x28, 0xdd, 0x6f, 0xe2, + 0xa8, 0x76, 0x8e, 0x89, 0xef, 0xfd, 0x1f, 0x00, 0x00, 0xff, 0xff, 0xcd, 0x79, 0x36, 0x31, 0x08, + 0x0f, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -897,6 +1019,8 @@ type QueryClient interface { BlockRateLimitConfiguration(ctx context.Context, in *QueryBlockRateLimitConfigurationRequest, opts ...grpc.CallOption) (*QueryBlockRateLimitConfigurationResponse, error) // Queries LiquidationsConfiguration. LiquidationsConfiguration(ctx context.Context, in *QueryLiquidationsConfigurationRequest, opts ...grpc.CallOption) (*QueryLiquidationsConfigurationResponse, error) + // Queries the stateful order for a given order id. + StatefulOrder(ctx context.Context, in *QueryStatefulOrderRequest, opts ...grpc.CallOption) (*QueryStatefulOrderResponse, error) // Streams orderbook updates. StreamOrderbookUpdates(ctx context.Context, in *StreamOrderbookUpdatesRequest, opts ...grpc.CallOption) (Query_StreamOrderbookUpdatesClient, error) } @@ -963,6 +1087,15 @@ func (c *queryClient) LiquidationsConfiguration(ctx context.Context, in *QueryLi return out, nil } +func (c *queryClient) StatefulOrder(ctx context.Context, in *QueryStatefulOrderRequest, opts ...grpc.CallOption) (*QueryStatefulOrderResponse, error) { + out := new(QueryStatefulOrderResponse) + err := c.cc.Invoke(ctx, "/dydxprotocol.clob.Query/StatefulOrder", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *queryClient) StreamOrderbookUpdates(ctx context.Context, in *StreamOrderbookUpdatesRequest, opts ...grpc.CallOption) (Query_StreamOrderbookUpdatesClient, error) { stream, err := c.cc.NewStream(ctx, &_Query_serviceDesc.Streams[0], "/dydxprotocol.clob.Query/StreamOrderbookUpdates", opts...) if err != nil { @@ -1009,6 +1142,8 @@ type QueryServer interface { BlockRateLimitConfiguration(context.Context, *QueryBlockRateLimitConfigurationRequest) (*QueryBlockRateLimitConfigurationResponse, error) // Queries LiquidationsConfiguration. LiquidationsConfiguration(context.Context, *QueryLiquidationsConfigurationRequest) (*QueryLiquidationsConfigurationResponse, error) + // Queries the stateful order for a given order id. + StatefulOrder(context.Context, *QueryStatefulOrderRequest) (*QueryStatefulOrderResponse, error) // Streams orderbook updates. StreamOrderbookUpdates(*StreamOrderbookUpdatesRequest, Query_StreamOrderbookUpdatesServer) error } @@ -1035,6 +1170,9 @@ func (*UnimplementedQueryServer) BlockRateLimitConfiguration(ctx context.Context func (*UnimplementedQueryServer) LiquidationsConfiguration(ctx context.Context, req *QueryLiquidationsConfigurationRequest) (*QueryLiquidationsConfigurationResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method LiquidationsConfiguration not implemented") } +func (*UnimplementedQueryServer) StatefulOrder(ctx context.Context, req *QueryStatefulOrderRequest) (*QueryStatefulOrderResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method StatefulOrder not implemented") +} func (*UnimplementedQueryServer) StreamOrderbookUpdates(req *StreamOrderbookUpdatesRequest, srv Query_StreamOrderbookUpdatesServer) error { return status.Errorf(codes.Unimplemented, "method StreamOrderbookUpdates not implemented") } @@ -1151,6 +1289,24 @@ func _Query_LiquidationsConfiguration_Handler(srv interface{}, ctx context.Conte return interceptor(ctx, in, info, handler) } +func _Query_StatefulOrder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryStatefulOrderRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).StatefulOrder(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/dydxprotocol.clob.Query/StatefulOrder", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).StatefulOrder(ctx, req.(*QueryStatefulOrderRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Query_StreamOrderbookUpdates_Handler(srv interface{}, stream grpc.ServerStream) error { m := new(StreamOrderbookUpdatesRequest) if err := stream.RecvMsg(m); err != nil { @@ -1200,6 +1356,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "LiquidationsConfiguration", Handler: _Query_LiquidationsConfiguration_Handler, }, + { + MethodName: "StatefulOrder", + Handler: _Query_StatefulOrder_Handler, + }, }, Streams: []grpc.StreamDesc{ { @@ -1591,6 +1751,87 @@ func (m *QueryBlockRateLimitConfigurationResponse) MarshalToSizedBuffer(dAtA []b return len(dAtA) - i, nil } +func (m *QueryStatefulOrderRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryStatefulOrderRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryStatefulOrderRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.OrderId.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryStatefulOrderResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryStatefulOrderResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryStatefulOrderResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Triggered { + i-- + if m.Triggered { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x18 + } + if m.FillAmount != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.FillAmount)) + i-- + dAtA[i] = 0x10 + } + { + size, err := m.OrderPlacement.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *QueryLiquidationsConfigurationRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1668,20 +1909,20 @@ func (m *StreamOrderbookUpdatesRequest) MarshalToSizedBuffer(dAtA []byte) (int, var l int _ = l if len(m.ClobPairId) > 0 { - dAtA10 := make([]byte, len(m.ClobPairId)*10) - var j9 int + dAtA12 := make([]byte, len(m.ClobPairId)*10) + var j11 int for _, num := range m.ClobPairId { for num >= 1<<7 { - dAtA10[j9] = uint8(uint64(num)&0x7f | 0x80) + dAtA12[j11] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j9++ + j11++ } - dAtA10[j9] = uint8(num) - j9++ + dAtA12[j11] = uint8(num) + j11++ } - i -= j9 - copy(dAtA[i:], dAtA10[:j9]) - i = encodeVarintQuery(dAtA, i, uint64(j9)) + i -= j11 + copy(dAtA[i:], dAtA12[:j11]) + i = encodeVarintQuery(dAtA, i, uint64(j11)) i-- dAtA[i] = 0xa } @@ -1901,6 +2142,34 @@ func (m *QueryBlockRateLimitConfigurationResponse) Size() (n int) { return n } +func (m *QueryStatefulOrderRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.OrderId.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryStatefulOrderResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.OrderPlacement.Size() + n += 1 + l + sovQuery(uint64(l)) + if m.FillAmount != 0 { + n += 1 + sovQuery(uint64(m.FillAmount)) + } + if m.Triggered { + n += 2 + } + return n +} + func (m *QueryLiquidationsConfigurationRequest) Size() (n int) { if m == nil { return 0 @@ -2896,6 +3165,211 @@ func (m *QueryBlockRateLimitConfigurationResponse) Unmarshal(dAtA []byte) error } return nil } +func (m *QueryStatefulOrderRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryStatefulOrderRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryStatefulOrderRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OrderId", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.OrderId.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryStatefulOrderResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryStatefulOrderResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryStatefulOrderResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OrderPlacement", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.OrderPlacement.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field FillAmount", wireType) + } + m.FillAmount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.FillAmount |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Triggered", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Triggered = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *QueryLiquidationsConfigurationRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/protocol/x/perpetuals/keeper/perpetual.go b/protocol/x/perpetuals/keeper/perpetual.go index 44f9b1ef95..4e8460b466 100644 --- a/protocol/x/perpetuals/keeper/perpetual.go +++ b/protocol/x/perpetuals/keeper/perpetual.go @@ -523,17 +523,14 @@ func (k Keeper) sampleAllPerpetuals(ctx sdk.Context) ( marketIdToIndexPrice := k.pricesKeeper.GetMarketIdToValidIndexPrice(ctx) + invalidPerpetualIndexPrices := []uint32{} for _, perp := range allPerpetuals { indexPrice, exists := marketIdToIndexPrice[perp.Params.MarketId] // Valid index price is missing if !exists { // Only log and increment stats if height is passed initialization period. if ctx.BlockHeight() > pricestypes.PriceDaemonInitializationBlocks { - log.ErrorLog( - ctx, - "Perpetual does not have valid index price. Skipping premium", - constants.MarketIdLogKey, perp.Params.MarketId, - ) + invalidPerpetualIndexPrices = append(invalidPerpetualIndexPrices, perp.Params.MarketId) telemetry.IncrCounterWithLabels( []string{ types.ModuleName, @@ -601,6 +598,13 @@ func (k Keeper) sampleAllPerpetuals(ctx sdk.Context) ( ), ) } + if len(invalidPerpetualIndexPrices) > 0 { + log.ErrorLog( + ctx, + "Perpetuals do not have valid index price. Skipping premium", + constants.MarketIdsLogKey, invalidPerpetualIndexPrices, + ) + } return samples, nil } diff --git a/protocol/x/prices/keeper/update_price.go b/protocol/x/prices/keeper/update_price.go index c7621e5c6b..b4851b5c43 100644 --- a/protocol/x/prices/keeper/update_price.go +++ b/protocol/x/prices/keeper/update_price.go @@ -60,6 +60,7 @@ func (k Keeper) GetValidMarketPriceUpdates( // 3. Collect all "valid" price updates. updates := make([]*types.MsgUpdateMarketPrices_MarketPrice, 0, len(allMarketParamPrices)) + nonExistentMarkets := []uint32{} for _, marketParamPrice := range allMarketParamPrices { marketId := marketParamPrice.Param.Id indexPrice, indexPriceExists := allIndexPrices[marketId] @@ -73,15 +74,18 @@ func (k Keeper) GetValidMarketPriceUpdates( // there will be a delay in populating index prices after network genesis or a network restart, or when a // market is created, it takes the daemon some time to warm up. if !k.IsRecentlyAvailable(ctx, marketId) { - log.ErrorLog( - ctx, - "Index price for market does not exist", - constants.MarketIdLogKey, - marketId, - ) + nonExistentMarkets = append(nonExistentMarkets, marketId) } continue } + if len(nonExistentMarkets) > 0 { + log.ErrorLog( + ctx, + "Index price for markets does not exist", + constants.MarketIdsLogKey, + nonExistentMarkets, + ) + } // Index prices of 0 are unexpected. In this scenario, we skip the proposal logic for the market and report an // error. diff --git a/protocol/x/vault/keeper/msg_server_deposit_to_vault.go b/protocol/x/vault/keeper/msg_server_deposit_to_vault.go index 6be3d80de8..2d51c25747 100644 --- a/protocol/x/vault/keeper/msg_server_deposit_to_vault.go +++ b/protocol/x/vault/keeper/msg_server_deposit_to_vault.go @@ -16,13 +16,14 @@ func (k msgServer) DepositToVault( msg *types.MsgDepositToVault, ) (*types.MsgDepositToVaultResponse, error) { ctx := lib.UnwrapSDKContext(goCtx, types.ModuleName) + quoteQuantums := msg.QuoteQuantums.BigInt() // Mint shares for the vault. err := k.MintShares( ctx, *msg.VaultId, msg.SubaccountId.Owner, - msg.QuoteQuantums.BigInt(), + quoteQuantums, ) if err != nil { return nil, err @@ -36,7 +37,7 @@ func (k msgServer) DepositToVault( *msg.SubaccountId, *msg.VaultId.ToSubaccountId(), assettypes.AssetUsdc.Id, - msg.QuoteQuantums.BigInt(), + quoteQuantums, ) if err != nil { return nil, err diff --git a/protocol/x/vault/keeper/msg_server_deposit_to_vault_test.go b/protocol/x/vault/keeper/msg_server_deposit_to_vault_test.go index b803769a86..af5c72f70f 100644 --- a/protocol/x/vault/keeper/msg_server_deposit_to_vault_test.go +++ b/protocol/x/vault/keeper/msg_server_deposit_to_vault_test.go @@ -2,6 +2,7 @@ package keeper_test import ( "bytes" + "math" "math/big" "testing" @@ -198,7 +199,7 @@ func TestMsgDepositToVault(t *testing.T) { big.NewInt(1_000), }, }, - "Two failed deposits due to non-positive amounts": { + "Three failed deposits due to invalid deposit amount": { vaultId: constants.Vault_Clob_1, depositorSetups: []DepositorSetup{ { @@ -227,14 +228,27 @@ func TestMsgDepositToVault(t *testing.T) { checkTxResponseContains: "Deposit amount is invalid", expectedOwnerShares: nil, }, + { + depositor: constants.Bob_Num0, + depositAmount: new(big.Int).Add( + new(big.Int).SetUint64(math.MaxUint64), + big.NewInt(1), + ), + msgSigner: constants.Bob_Num0.Owner, + checkTxFails: true, + checkTxResponseContains: "Deposit amount is invalid", + expectedOwnerShares: nil, + }, }, totalSharesHistory: []*big.Int{ big.NewInt(0), big.NewInt(0), + big.NewInt(0), }, vaultEquityHistory: []*big.Int{ big.NewInt(0), big.NewInt(0), + big.NewInt(0), }, }, } diff --git a/protocol/x/vault/types/msg_deposit_to_vault.go b/protocol/x/vault/types/msg_deposit_to_vault.go index eb3d091402..12bb006b3d 100644 --- a/protocol/x/vault/types/msg_deposit_to_vault.go +++ b/protocol/x/vault/types/msg_deposit_to_vault.go @@ -1,8 +1,8 @@ package types import ( + errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/dydxprotocol/v4-chain/protocol/dtypes" ) var _ sdk.Msg = &MsgDepositToVault{} @@ -14,9 +14,10 @@ func (msg *MsgDepositToVault) ValidateBasic() error { return err } - // Validate that quote quantums is positive. - if msg.QuoteQuantums.Cmp(dtypes.NewInt(0)) <= 0 { - return ErrInvalidDepositAmount + // Validate that quote quantums is positive and an uint64. + quoteQuantums := msg.QuoteQuantums.BigInt() + if quoteQuantums.Sign() <= 0 || !quoteQuantums.IsUint64() { + return errorsmod.Wrap(ErrInvalidDepositAmount, "quote quantums must be strictly positive and less than 2^64") } return nil diff --git a/protocol/x/vault/types/msg_deposit_to_vault_test.go b/protocol/x/vault/types/msg_deposit_to_vault_test.go index ab9a25c648..a369a69af7 100644 --- a/protocol/x/vault/types/msg_deposit_to_vault_test.go +++ b/protocol/x/vault/types/msg_deposit_to_vault_test.go @@ -1,6 +1,8 @@ package types_test import ( + "math" + "math/big" "testing" "github.com/dydxprotocol/v4-chain/protocol/dtypes" @@ -22,6 +24,26 @@ func TestMsgDepositToVault_ValidateBasic(t *testing.T) { QuoteQuantums: dtypes.NewInt(1), }, }, + "Success: max uint64 quote quantums": { + msg: types.MsgDepositToVault{ + VaultId: &constants.Vault_Clob_0, + SubaccountId: &constants.Alice_Num0, + QuoteQuantums: dtypes.NewIntFromUint64(math.MaxUint64), + }, + }, + "Failure: quote quantums greater than max uint64": { + msg: types.MsgDepositToVault{ + VaultId: &constants.Vault_Clob_0, + SubaccountId: &constants.Alice_Num0, + QuoteQuantums: dtypes.NewIntFromBigInt( + new(big.Int).Add( + new(big.Int).SetUint64(math.MaxUint64), + new(big.Int).SetUint64(1), + ), + ), + }, + expectedErr: "Deposit amount is invalid", + }, "Failure: zero quote quantums": { msg: types.MsgDepositToVault{ VaultId: &constants.Vault_Clob_0,