Skip to content

Latest commit

 

History

History
218 lines (167 loc) · 9.33 KB

File metadata and controls

218 lines (167 loc) · 9.33 KB
title Order errors and validation
description Every rejection markets-service can return, and what to change to fix it

Every error response has the same shape:

{ "error": "action_json.data.isBid must match side" }
Status Meaning
400 The request is malformed or internally inconsistent. Fix and resubmit.
403 The cancel targets an order you do not own, or a protected namespace.
404 No such order, or the order is no longer active.
409 order_id has already been used.
500 Server-side failure. Safe to retry.

Most rejections happen before the order reaches the book, so a 400 means nothing was placed.

`markets-service` verifies your signature at submission — see [Authentication and signing](/signing#what-the-service-checks). An order whose signature does not authorize its action is rejected here rather than failing later onchain.

Signature

The signature did not recover to `signer_address`, and the signer is not a contract whose `isValidSignature` accepted it.

The digest is over the Action struct exactly as described in Authentication and signing — domain Matching version 1.0, bound to the chain and the Matching contract. A mismatch in any signed field produces a different digest and so a different recovered address. Check that action_json is byte-for-byte what you signed, and that signer_address is the key that signed it rather than the account that owns it.

A signature that cannot be checked — for example an RPC failure while resolving a contract signer — is not a rejection. The order is accepted and the failure is logged, so a transient outage never blocks a valid order.

Missing fields

Every one of these is required on POST /v1/orders.

Error Fix
order_id is required Supply a unique client-side id.
asset_address is required Take it from GET /v1/markets.
nonce is required Supply a nonce unique per (owner, nonce).
limit_price is required Supply the price in human decimals.
desired_amount is required Supply the size in human decimals.
signature is required Supply the EIP-712 signature.
invalid JSON body The body did not parse as JSON.
action_json must be valid JSON action_json is present but not valid JSON.

Action payload shape

These come from decoding action_json.data, the ABI-encoded TradeData tuple.

`data` is not exactly seven 32-byte words. After the `0x` prefix it must be 448 hex characters. See [Encoding data](/signing#encoding-data). `data` is the right length but not valid hex. A wrapper around the field-level failures below. The suffix names the specific problem.

Field consistency

The flat order fields and the signed action_json describe the same order, so they must agree. Rebuild both from one set of values rather than editing one of them.

Error Compared against
action_json.subaccount_id must match subaccount_id body subaccount_id
action_json.nonce must match nonce body nonce
action_json.owner must match owner_address body owner_address
action_json.signer must match signer_address body signer_address
action_json.data.asset must match asset_address body asset_address
action_json.data.subId must match sub_id body sub_id
action_json.data.isBid must match side true for buy, false for sell

Scaling

These are the most common rejections, and they almost always mean the body was sent in wei.

`data.limitPrice` must be a positive whole multiple of the body's `limit_price` after tick normalization. The body takes **human decimals**; only `data` carries wei. Same rule for size, normalized against the instrument's minimum size. `limitPrice` is a signed `int256` but zero and negative values are rejected. Same for `desiredAmount`. `desired_amount` is smaller than the instrument's minimum size, so it normalizes to nothing. `desired_amount` is not a whole multiple of the instrument's minimum size. If a price or amount error appears and the numbers look correct, check the scale first. See [Price and amount use two different scales](/signing#price-and-amount-use-two-different-scales).

Amounts and expiry

Error Cause
desired_amount must be greater than zero Non-positive size in the body.
filled_amount cannot be negative Negative filled_amount.
filled_amount cannot exceed desired_amount Partial-fill state is inconsistent.
expiry must be in the future expiry is at or before now. Use unix seconds.
invalid integer value … An integer field is not parseable.

Instrument

The `(asset_address, sub_id)` pair is not an enabled market. Read `GET /v1/markets` — both values must come from the same entry. The `symbol` or `asset_address` + `sub_id` on a read endpoint did not resolve. These two fields apply to the spot market only. Omit them on orders for any other market.

Spot order translation

These apply to USDCcNGN-SPOT only. Both fields are optional — omit them and your raw engine values are used as sent. Send either one and the rules below apply. See the Spot market guide for the units involved.

You sent `ui_intent`, or an `order_entry_spec` with a different value. The spec string must be exactly `usdc_cngn_spot_v1`. The two fields travel together. Send both, or neither. You sent both `side` and `ui_intent`, and they disagree. Engine side is the inverse of `ui_intent.side`. Omit `side` to let the service derive it. You sent both `limit_price` and `ui_intent`, and they disagree. The engine price is `1 / ui_intent.price`. Omit `limit_price` to let the service derive it. You sent both `desired_amount` and `ui_intent`, and they disagree. The engine amount is `ui_intent.size * ui_intent.price`. Omit `desired_amount` to let the service derive it.

Duplicate orders

`order_id` has already been submitted. Generate a fresh one; do not retry with the same id.

Treat order_id as an idempotency key you control. A 409 means the first submission was accepted, so check its status with GET /v1/orders/{order_id} rather than resubmitting.

Cancelling

Status Error Cause
404 active order not found Already filled, already cancelled, or never existed.
403 service-tagged cancels are not allowed for protected namespace … The order belongs to a protected order_id namespace.
500 failed to resolve cancel target Lookup failed server-side. Retry.

Read endpoints

Endpoint Error
GET /v1/trades limit must be between 1 and 100
GET /v1/trades before_trade_id must be a positive integer
GET /v1/candles interval must be one of 1m, 5m, 15m, 1h, 4h, 1d
GET /v1/candles limit must be between 1 and 1000
GET /v1/candles start must be an RFC3339 timestamp
GET /v1/candles end must be an RFC3339 timestamp
GET /v1/candles end must be after start
GET /v1/orders/{order_id} order not found (404)

unknown market applies to GET /v1/book, GET /v1/trades, and GET /v1/candles alike.

Most rejections trace back to how the action payload was built.