Skip to main content
Market makers on Convallax are fully independent entities. You hold your own wallet keys, you quote with your own wallet address, and you sign your own on-chain settlement orders. The backend never holds your keys and never signs on your behalf — it is purely a relay and matching engine. You never hold option inventory. Collateral is locked only when a trade actually fills: fill() mints option tokens atomically and pulls collateral in the same transaction. All you need ready is USDC and two one-time USDC approvals.

The Three-Channel Transport

Maker integration uses a three-channel split. Each channel does one job:
You must keep both the SSE quote-request stream (channel 1) and the post-trade WebSocket (channel 3) open at the same time: the SSE stream tells you what to quote, and the WebSocket tells you when you won. Quotes and confirmation signatures go out over REST (channel 2).
All three channels authenticate with the same per-MM API key. The SSE stream and the REST endpoints use the X-API-Key header (or ?apiKey=); the WebSocket uses ?apiKey= on the URL or an auth message.

What You Need

1

An API key

A per-MM API key generated from the Convallax dashboard (Settings → API Keys). The key maps to your stable makerId and works immediately. See the Authentication guide.
2

Your own wallet + key

You quote with your own wallet address (it becomes Order.maker) and sign settlement orders with that wallet’s private key. The backend never holds it.
3

USDC + two approvals

Settlement is atomic mint-on-fill — there is no inventory to pre-mint and no ERC-1155 approvals. You only need USDC and two one-time USDC approvals, depending on which side of the trade you take:
  • Posting collateral (you become the writer): usdc.approve(coreAddress, collateral). When a fill executes, ConvallaxCore pulls your collateral and mints fresh option tokens to the holder.
  • Paying premium (you are buying the option from the taker): usdc.approve(settlementAddress, premium).
For a standard long fill (the taker buys, makerSelling = true), you post collateral → approve Core. For a short fill (the taker writes, makerSelling = false), you pay premium → approve Settlement.
A maker that quotes both directions should approve both Core (for collateral) and Settlement (for premium) for USDC. There are no setApprovalForAll / ERC-1155 approvals anywhere in the model.
Set your USDC approvals before quoting. When you win, you only have a few seconds (the confirmation deadline) to sign — there is no time to send approval transactions. Collateral itself is never locked until a trade actually fills.

How It Works

1

Subscribe to the quote-request stream (SSE)

Open an SSE connection to the maker stream with your API key in the X-API-Key header. On connect you receive a connected event, then a snapshot of currently open requests, then live quote_request events.
Each quote_request carries the trade parameters and an SSE id: for reconnect/replay. See the Quote Request Stream guide for the full event list and Last-Event-ID semantics.
2

Connect the post-trade WebSocket

In parallel, open the post-trade WebSocket so you learn the moment one of your quotes wins. On auth you receive a connected message with protocolVersion: 3.
3

Submit your quote (REST)

For each quote_request, compute your price and POST /v1/mm/quotes. The quote.maker field must be your own wallet address — it becomes Order.maker and you must be able to sign for it.
The response returns a server-generated quoteId that is stable across updates for the same maker + request:
Store that quoteId keyed by requestId — you will need it to confirm if you win. You can update your quote at any time while the request is open by re-POSTing for the same requestId; only your latest quote is kept.
4

Win, sign, and confirm (WebSocket → REST)

When the trader commits and your quote wins, the post-trade WebSocket pushes a quote:accepted message containing the exact Order, the EIP-712 domain/types, and a confirmationDeadline:
Sign the order with your own wallet key and POST the signature to the confirm endpoint before the deadline:
The backend verifies that your signature recovers to order.maker, then pushes quote:confirmed to you (and quote:rejected to other makers).
5

Settle

Once you confirm, the taker receives your signed order and calls fill() on ConvallaxRFQSettlement. In a single atomic transaction, fill() calls ConvallaxCore.mintFor(...) to pull collateral from the writer, mint fresh option tokens to the holder, and move the premium — all or nothing. For a long fill you post collateral and the option is minted to the taker; for a short fill the taker posts collateral and the option is minted to you.
6

Reclaim collateral after settlement

On a long fill you are the writer — your USDC collateral stays locked in ConvallaxCore until the series expires and is settled. Once the series is settled (see the Settlement guide), reclaim your share of the leftover collateral with a single call:
You receive writerCollateral × writerPoolRemaining / totalCollateral — your original collateral minus whatever was paid out to holders. This is a one-shot call per series (your recorded collateral is zeroed after). Poll GET /v1/series with settled=true to find expired series you wrote, then claim. See claimWriterCollateral() for details.

Confirmation Deadline & Fallback

When a taker commits, the winning maker has a limited window (MAKER_CONFIRMATION_MS, default 10 seconds) to sign and POST the signature:
  • You confirm in time → the taker settles against your signed order; you receive quote:confirmed.
  • You miss the deadline → the backend falls back to the next-best maker’s quote and asks them to confirm; you receive quote:rejected.
  • No maker confirms → the request stays open and the taker can retry.
If you miss the deadline you lose the trade to the next-best maker. Keep your USDC approvals (Core for collateral, Settlement for premium) set ahead of time so signing is instant.

Core Quoting Loop

Winner Selection

Quote Validation Rules

Your quote must pass these validation checks:
Buy vs sell sizing. On a buy the taker submits a USDC budget (trade.budgetUsd), not a contract count. You quote a per-option price and a size = the most whole options you’re willing to write at that price. The taker receives floor(budgetUsd / price) options, capped by your size (a partial fill if your size is smaller). On a sell the taker submits a contract count (trade.size) and you quote the size you’ll take. Either way, price is always per one option.

The Order You Sign (EIP-712)

Check Relay Status

Verify connectivity and see how many makers are online:
makersConnected counts makers subscribed to the SSE quote-request stream; socketsConnected counts live post-trade WebSocket sockets. See the Relay Status reference.

Environment Variables

If you are running your own relay instance, these variables control auth and quote request behavior: If no maker keys are configured, the relay runs in OPEN dev mode (anonymous makerId, accepts anyone) — see the Authentication guide.

Dependencies (Node.js bots)

Market-maker bots run in Node.js, not in a browser. Install these packages before running the example below:
If your SSE client cannot set headers at all, you can pass the key on the URL instead: GET .../quote-requests/stream?apiKey=<your-key>. The npm eventsource package with headers: { 'X-API-Key': ... } is still the recommended approach.

Complete Worked Example Bot

A minimal bot that subscribes to the SSE stream, submits quotes via REST, listens on the WebSocket for wins, and signs winning orders with ethers:
Before going live, set your USDC approvals — usdc.approve(coreAddress, ...) if you’ll post collateral, and usdc.approve(settlementAddress, ...) if you’ll pay premium — so settlement succeeds the instant a taker fills your signed order. No inventory minting or ERC-1155 approvals are needed.

Provide Liquidity at Scale

If you’re interested in becoming a liquidity provider at scale on Convallax, contact us at support@convallax.com to discuss integration support and partnership terms.