monaco.api.managed_markets
Source: protos/api/managed_markets.proto
Use ManagedMarketsService to drive the maker side of an operator-managed market launch: read the launches this wallet is assigned to, hold a short lease that fences one process at a time, and ask the engine to restate a quote set whose prices, sizes, fees and risk bucket are all chosen server-side. It never places a quote the caller describes and never moves funding.
Notes
- All three RPCs require an authenticated wallet session, and a delegated-agent session is refused on every one of them with
PERMISSION_DENIED(REST403) — permanently, not as a rollout state. The maker requirement is narrower:ClaimLeaseandRefreshQuotesare launch-scoped and need a session whose user and application both match that launch’s configured maker, whileListAssignmentsaccepts any authenticated wallet and filters by it, so a non-maker gets an empty page rather than an error. owner_idis a process fence, never authorization. It is a UUID the caller chooses to identify the process holding the lease; authorization is derived solely from the authenticated session’s user and application binding and never from an identity in the request body, so noowner_idwidens what a caller can reach. A value that is not a UUID returnsINVALID_ARGUMENT, as does a non-UUIDlaunch_idonClaimLeaseorRefreshQuotes, a non-positivequote_revision, andListAssignmentspagination outsidepage 1..=10000orpage_size 1..=100.- A different
owner_idcannot seize a live lease.claim_makeradmits a claim only when the lease is unset, already expired, or held by that same owner, so a standby claiming under a newowner_idgetsALREADY_EXISTS(REST409) until the current lease lapses. Takeover is “wait out the remaining lease, then claim”. A claim after expiry incrementsmaker_generation, which is what makes the previous holder’s next refresh fail as stale. A claim by the current owner splits onexpected_generation: supplied, it renews throughrenew_makerand moves the expiry out; omitted while the lease is still unexpired, it neither claims nor renews — it replays the existing reservation and returns its original expiry, so a loop that always omits it will let its own lease lapse. - A launch this session is not the configured maker for answers
NOT_FOUND, notPERMISSION_DENIED, so the service never confirms the existence of a launch the caller has no part in.ListAssignmentsis the exception in shape rather than in rule: it filters by the caller, so a wallet with no assignments gets an empty page rather than any error.PERMISSION_DENIEDis reserved for delegated-agent sessions. generationandquote_revisionareuint64fences. Over gRPC they areuint64fields; over REST they are exact decimal strings. A JSON client should keep the wire value as text but must not order or increment it as text —"10" < "2"lexically — and must not round-trip it through a double, which loses values above 2^53. Convert to an exact 64-bit integer type (BigIntin JavaScript) for every comparison and increment.ListAssignmentsreturns expected inventory, not a ready-to-quote set: a row withquote_enabled = falseis still assigned and still listed, butClaimLeaseandRefreshQuoteson it returnALREADY_EXISTS(REST409,Managed market is not ready for maker quotes) until the launch is ready to quote: its launch phase iswarming,activatingorlive, its runtime phase iswarmingorlive, and its allocated collateral has reached the configured allocation in full.activatingcounts — a maker must keep quoting through activation, which is the phase that depends on those quotes. Itsleasefield is declared on the message but never populated: the released handler serializes it as absent on every row, deliberately, because the database reservation cannot prove the engine’s current generation or quote revision and a fabricated zero would read as a usable fence.ClaimLeaseis the only source of a lease a caller may act on.- The two
phasefields are different vocabularies. OnManagedMarketAssignmentandManagedMarketLeaseit is the launch phase:pending,validating,registering,warming,activating,liveorfailed. OnManagedMarketQuoteStatusit is the engine’s runtime phase and takes onlywarming,liveorhalted; anything else the engine reports is answered asUNAVAILABLEwithManaged market status unavailable; reconcile the lease. ClaimLeasereserves the lease, fences it in the matching engine, then rechecks ownership before replying, so the reply is the engine’s view rather than the database reservation — a lease that expired in flight fails instead of being reported as held. The lease runs for 30 seconds.expected_generationis required when renewing an unexpired lease you hold and omitted for an initial claim or after expiry.- An initial claim whose reply was lost replays its existing durable reservation instead of incrementing
generation, so a transport retry never costs you the lease you already hold. RefreshQuotesplaces one bounded bid and one bounded ask.quote_revisionmust be positive (INVALID_ARGUMENTotherwise) and at least the revision the engine holds for that generation: a lower one is refused, and re-sending the one it already holds is an accepted idempotent no-op. Derive it from theClaimLeasereply rather than starting at1— a renewal keeps the generation’s existing revision, so1restates the quote set when the held revision is exactly1and is refused once it has advanced past it. Only a claim that bumped the generation resets the revision to0.- The engine also enforces the launch’s own cadence, refusing a refresh that advances the revision less than
refresh_interval_msafter the last one. That is a rejection rather than a dropped no-op, so pace the loop on the assignment’srefresh_interval_ms. An equal-revision retry is exempt —quote_intentreturns on the equality check before it reaches the interval check — so an idempotent replay succeeds inside the window. - Two
ALREADY_EXISTSpaths, and the engine’s own refusals are indistinguishable. The handler re-checks the launch’s persisted readiness before calling the engine, so a launch already recorded as halted or otherwise not quotable answersManaged market is not ready for maker quotes. Everything the engine itself refuses is folded byhandlers::managed_markets::engine_error—ABORTED,ALREADY_EXISTS,FAILED_PRECONDITIONandINVALID_ARGUMENTall become oneALREADY_EXISTScarryingManaged market lease changed or expired; reconcile the lease— so a stale revision, an early refresh, an expired lease and a market halted since the readiness check are one status and one message. Both paths areALREADY_EXISTS: do not branch on the text, reconcile throughClaimLeaseand act on the generation and revision it returns. - Cost:
ClaimLeaseadmits one item andRefreshQuotestwo against the caller’s ordinary order-creation budget, andListAssignmentsdraws the per-account read budget like every other authenticated read, charged before the handler runs. Those two budgets are the only sources ofRESOURCE_EXHAUSTEDhere — the engine’s cadence refusal is not one of them; it arrives as the foldedALREADY_EXISTSbelow. Either way it carries agoogle.rpc.RetryInfodetail — the same interval REST returns asretryAfter— so honor that rather than guessing. See Rate limits. ALREADY_EXISTS(REST409) also coversManaged market lease changed or expired; reconcile the lease: the lease moved to another owner or generation, or lapsed. Reconcile throughClaimLeaseand read the engine-observedgenerationandquote_revisionback before continuing.- Treat a
RefreshQuotestimeout orUNAVAILABLEas an unknown outcome, not a rejection: the intent may have reached the engine. Reconcile throughClaimLeaseand take the engine’squote_revisionrather than advancing your own and retrying blind. UNAVAILABLE(REST503) means the matching engine could not be reached or answered with a status this service cannot act on.INTERNALis a generic server-side failure and can happen before the engine is contacted at all, so unlikeUNAVAILABLEit says nothing about engine state.- Quote intents are server-derived end to end: a fixed preallocated risk bucket, server-chosen prices, sizes and the application’s canonical taker fee. The request carries no price, quantity or identity that could override any of it, and no path here funds an account.

