Skip to main content
This page is for a desk already quoting Deribit Block RFQ — the private/*block_rfq* methods and the block_rfq.* channels. It is not a comparison against an order book, and the difference matters: a Block RFQ maker never posts into a book. It subscribes, receives a broadcast request, and responds. That is exactly the shape Joyride has, so the port is real and it is much smaller than a book-to-RFQ rewrite. Read the next section before anything else on this page.

A delivered quote cannot be taken back

A maker quote on Joyride cannot be cancelled, amended or replaced by any means, and there is no market maker protection to pull it automatically. Once delivered it is a firm, irrevocable two-sided price until expires_at, and the TTL chosen at signing time is the only risk control over it.
Both halves of a Deribit maker’s intraday risk system are absent here. The manual half is gone. private/cancel_block_rfq_quote, private/cancel_all_block_rfq_quotes and private/edit_block_rfq_quote have no counterpart at any layer — not in the gateway, not in the CLI, not in the SDK, and none is planned. There is no cancel, no replace and no amend. A second rfq.maker.respond on the same request is refused with RFQ_STATE_CONFLICT rather than treated as an edit. The automatic half is gone too. Deribit’s Block RFQ market maker protection — private/set_mmp_config with its Block-RFQ-only trade_count_limit, which pulls your live quotes when fills breach a threshold — has no counterpart. Nothing withdraws a quote on your behalf. These two gaps compound. A quoting loop written for Deribit treats a stale price as recoverable: send wide, tighten as confidence rises, pull when the reference moves or the pricing feed goes stale. Ported unchanged, that loop finds the retraction call absent and discovers on its first fast move that it wrote a free option it cannot take back — and nothing pulled the rest of its book either. What actually bounds the exposure is the TTL, and only the TTL:
  • The TTL is the only control over how long you are committed. Choose one you would accept being held to on your worst tick, and treat lengthening it as a risk decision.
  • TTL is capped at 3,600 seconds, and a quote can never outlive the nearest leg’s close. The venue rejects an out-of-range expiry rather than clamping it.
  • A quote reaching the venue with under two seconds of life left is refused: it would be firm but untakeable.
  • The CLI and the runner both require the TTL explicitly, with no default, for this reason.
  • Losing quotes get no push. Keep a local expiry timer per delivered quote so reserved risk is released on time.
Design for this before you write a line of code. Everything below assumes you have.

What ports across unchanged

The shape of the two venues genuinely matches, which is why the rest of this page is a list of specifics rather than a rewrite.
  • Request-driven, maker responds. You subscribe, the venue broadcasts an open request, you answer it. Nothing rests in a book.
  • Multi-leg option packages on one request. Joyride takes 1 to 13 legs, sharing one underlying and one expiry.
  • Two-sided prices. One answer carries both sides.
  • No last look on either venue. Once both signatures exist on Joyride, the fill is submittable by anyone; there is no maker confirmation step.
  • Instrument names translate automatically, in both directions. Deribit-style symbols are accepted wherever a Joyride symbol is, and the translation is lexical and total: a name that cannot be carried across exactly — a fractional strike, a perpetual, a future, a non-USDC quote leg, an unlisted asset — is refused rather than guessed, because a silently wrong instrument is a wrong trade.

What does not port

Every row here is a gateway or protocol difference. None of them can be closed by an SDK, a wrapper, or a configuration flag. One consequence worth stating on its own, because it looks like a missing feature and is not: there is no counterpart to private/get_block_rfq_quotes. With one quote per request and no quote lifecycle, there is no plural to list. Your own delivered quote comes back on rfq.get; record it locally as you send it.

Where Joyride is ahead

Two things Deribit has no equivalent for. Both are read after the risks above, not instead of them. You can decline a request you will not price. rfq.maker.decline ends an unquoted request immediately with a stated reason — unlisted_instrument, near_expiry, size_limit, stale_data, low_confidence or queue_overflow. The taker stops waiting instead of timing out, and you have said why. On Deribit, silence is the only way to pass. You are told your own economics before you sign. Every open request arrives personalized with your own fee and lock requirement for both taker sides, so you know what a fill costs you and how much collateral it will tie up before you commit to a price. Deribit has nothing equivalent; you find out after the fact. Fee rates themselves are not restated here. The live schedule and the limits are on Fees and Limits.

The concept map

The code path

Your alpha is the pricing function. Everything wrapped around it is undifferentiated work, and you do not have to port it. You supply one function that takes an open request and returns {bid, ask} — or a decline. MakerQuoteRunner owns the rest: subscribing, paging the catch-up poll, de-duplicating requests it has already answered, pacing inside the account’s rate budget, backing off, signing, persisting the quote nonce before each send, confirming the returned quote_id, and reconciling fills after a reconnect. You never touch a byte layout or an ed25519 call. The same runner is what joyride rfq maker watch runs, with your pricing program as a subprocess, so a desk can be quoting before it embeds anything:
Your program gets one open request as JSON on stdin and writes one answer on stdout. Porting a Deribit pricer means keeping the model and replacing the output stage:
bid is what you pay if the taker sells the package; ask is what you receive if the taker buys it. A sign is not decoration: a negative ask means the taker is paid to buy, which is cash leaving your vault.

Five traps

These are the ones that bite a ported integration specifically. They are listed in the order they will hurt you.
Your pricing output shape does not carry over. A Deribit quote carries a price per leg inside legs[], alongside ratio and direction, and Deribit ships private/get_leg_prices to decompose a strategy price into that vector. A Joyride quote carries two signed whole-package totals in USDC — one bid, one ask — never per leg, never per contract, never coin-denominated. The conversion therefore runs in the opposite direction to private/get_leg_prices: you fold a vector into a scalar pair rather than expanding a scalar into a vector. There is no per-leg price field anywhere in the signed bytes for a client library to fill on your behalf, so this rewrite is yours and it cannot be automated away. Totals are canonical six-decimal strings; do not compute them in floating point for production.
Expiry units differ silently. Deribit’s expires_at is milliseconds since epoch. Joyride’s expires_at is UNIX seconds, and it requires issued_at alongside it. Nothing about a millisecond value is a type error — it is a number in range — so a ported expiry calculation does not fail loudly. It signs a quote whose life is off by a factor of a thousand, and the venue either refuses it for exceeding the TTL cap or, worse, accepts something you did not mean. The safe port is to stop computing the timestamp at all: give the CLI or the runner a TTL in seconds and let it derive issued_at and expires_at.
A Deribit-shaped request payload is rejected outright, and that is the feature. rfq.create rejects unknown fields rather than dropping them, so a payload still carrying makers, disclosed, hedge or label fails loudly on the first call instead of trading on parameters that were silently discarded. Expect that error during the port and read it as the venue doing its job: a request that quietly lost its dealer list or its hedge leg would have executed as something you did not intend. The maker subscription is per-socket and is not restored by session resume. Resuming a session brings back your authentication, not your subscription. After every reconnect you must re-subscribe and page rfq.maker.poll to catch up on requests that opened while you were away — paged, because a short page does not prove you have reached the end. The runner does this for you; a hand-rolled client must. Legs are signed verbatim, in the order you submitted them. The order is inside the signed bytes. Re-deriving the leg list, normalizing it, or sorting it before signing produces a signature over a different package than the one the venue rebuilt, and the quote is refused. Copy the legs through untouched.

Onboarding is work, not a URL change

Three of the four items below have no Deribit analogue at all. Budget for them before you schedule the port.
  1. Hold a Solana keypair. It is your trading identity and your signing key. There is no API key and secret to rotate into.
  2. Fund a margin-vault subaccount on chain. Collateral does not sit with the venue. An unfunded maker cannot quote: the venue cannot state your lock requirement and refuses with RFQ_MAKER_UNFUNDED.
  3. Be granted the quoter role. It is provisioned by Joyride and cannot be enabled from the API. See Becoming an RFQ Quoter.
  4. Persist a monotonic quote nonce across restarts. The venue keeps a per-account high-water mark and it survives your process. A maker that seeds its nonce from memory on each boot collides with that mark and has its first quote refused. Persist before sending, never after.

Where to go next

Onboarding, the quoter role, and anything this page did not answer: support@joyride.exchange.