Monaco Protocol SDK v1.0.37
This is an additive release — no breaking changes. It adds a post-only flag to limit-order placement and replacement across every client.postOnly is a maker-only guarantee, not a new order type: a placement or replacement that would cross the book is rejected instead of matching, so a resting quote never accidentally takes. Existing code keeps working unchanged; the flag is opt-in. The one thing to know before adopting it is how a crossing rejection surfaces — a message match for single orders, a structured error code for batches.
Added
Post-only orders
SetpostOnly: true alongside a normal limit placement or replacement to guarantee the order can only add liquidity. If the price would cross the book at admission time (BUY at or above the best ask, or SELL at or below the best bid), Monaco rejects the order instead of letting it take.
- Exposed on every limit-order surface:
sdk.trading.placeLimitOrder,replaceOrder,batchCreate, andbatchReplace(@0xmonaco/core), theuseTrade()equivalents (@0xmonaco/react), and the RESTcreate_order/batch_create_orders/replace_order/batch_replace_ordersendpoints (POST /api/v1/orders,POST /api/v1/orders/batch-create,PUT /api/v1/orders/{order_id},POST /api/v1/orders/batch-replace) and their gRPCOrdersServiceequivalents. The MCPplace_limit_orderandreplace_ordertools take an optionalpostOnlytoo. - Maker-only, not a new order type.
postOnlycomposes withLIMITorders usingGTCtime in force only. It is rejected onMARKETorders and rejected when combined withIOCorFOK— both are immediate-or-cancel semantics that contradict a maker-only guarantee. It is not available onplaceMarketOrder. The TypeScript schemas enforce these combinations client-side onplaceLimitOrderandbatchCreateso a bad combination fails fast without a round trip — but that client check is for fast feedback only; the server’s own validation is authoritative and always enforced. - Crossing rejection. A crossing
postOnlyorder or replacement is rejected with REST400 Bad Request/ gRPCInvalidArgument, message containing"post-only order would cross"(internally logged asPOST_ONLY_WOULD_CROSS). For a singleplaceLimitOrderorreplaceOrder, that code is not part of the response body — match on the message text.batchCreateandbatchReplaceare different: each per-item result carries a structurederror.code, set toPOST_ONLY_WOULD_CROSSfor a post-only crossing rejection — match oncodethere. - Replace semantics.
postOnlyis re-stated explicitly on every replacement; it is never inherited from the original order. A singlereplaceOrdervalidatespostOnlybefore cancelling the original, so a rejected replacement leaves the original resting, untouched.batchReplaceis cancel-first: a batch item whosepostOnlyreplacement is rejected for crossing reports the error with its original already cancelled, matching the existing failed-to-place batch-replace contract — refresh your live orders before retrying. - Admission-time check only. The crossing predicate is evaluated once, when the order is admitted (placed or replaced) —
postOnlyis not a perpetual anti-taker guarantee. Once a non-crossingpostOnlyorder is admitted and rests, it behaves like an ordinary resting order of the same time in force: a later book move can trade against it like any other resting order. The flag is not stored on the order and not echoed back in order-detail responses.
Upgrade
1.0.37 too; it runs via npx -y @0xmonaco/mcp-server, so restarting your assistant picks up the new version and the postOnly tool inputs.
Nothing in this release is breaking. One thing worth adopting:
- Use
postOnlyfor maker quoting. SetpostOnly: trueon limit placements and replacements where an accidental take is worse than a rejected order you can immediately re-price — market-maker quoting, or rebuilding quotes right after a market reopens. Handle the crossing rejection by the message for single orders ("post-only order would cross") and byerror.code === "POST_ONLY_WOULD_CROSS"for batches, and rememberbatchReplacecancels first — a rejected item leaves no resting order behind.

