Skip to content
Solvers

Run a solver

A solver is a loop: keep a live copy of the book, decide what to fill, build a solution, sign it, submit it, and update your state from the result. Field names and method signatures are in the Medusa API and the intent reference.

Call subscribeIntents over WebSocket with a signed credential { address, validUntil }, where validUntil is a unix time at most 600 seconds ahead and greater than the last one you used. Each credential is single-use, so sign a fresh one for every connection.

The first notification is OpenIntents, a full snapshot. Replace your local book with it, then apply each update:

Notification Do
NewIntent Add the intent.
SolutionAccepted Remove intents_solved (this includes the solution’s just-in-time intents) and add new_intents (its remainder children).
StatusChanged Apply the new state; remove the intent if it is no longer Open.

If you fall behind, the server ends the subscription with an error. Resubscribe with a new credential and replace your book with the new snapshot. You can hold several connections for the same address.

An intent offers srcAmount of srcMToken and accepts the outcome in outcome. The live shapes are:

  • PercentageFilled: one or more outcome mTokens, each with a rate (mAmounts[i], outcome units per 10^18 source units), fillable in any fraction and paid in exactly one of them. Orders built through the Khalani API always have a single outcome mToken, are authored by the hub’s order contract, and have validBefore set to the order’s deadline.
  • Exact: one or more outcome mTokens, each with an exact amount. The whole intent is spent, and it is paid that exact amount in one of them.

Judge validity against the hub’s clock, not your wall clock: an intent is fillable while it is Open and at or before validBefore on the hub. Every intent has validAfter of 0. The hub’s clock is not the block timestamp. Read it with getTimestamp(), which returns uint64 Unix seconds, on the intent book 0x4411E3A41C12DC6cB205f7128879283081B99576, an eth_call on the hub chain; Medusa moves it forward every 10 seconds.

You fill with mTokens you hold on the hub. Deposit on a spoke to mint them. Check a balance with getMtokenBalanceByAuthor.

  • EVM origin: a signed withdrawMtokens request releases inventory to the same address on the mToken’s origin spoke.
  • Non-EVM origin: use withdrawMtokensWithPayload with the recipient encoded in dstAddrBytes. The address-only request cannot express a Bitcoin or TRON destination. See Withdrawals for the signing type and encoding.

To fill part or all of an order O with your own inventory, publish a just-in-time intent J in the same solution: J gives the order’s destination mToken and accepts the order’s source mToken.

For a fill of f source units of an order with rate r:

  1. Size J to give a = ceil(f × r / 10^18) of the destination mToken, at a rate that accepts exactly f of the source. Give it validAfter 0 and a validBefore at or after the hub’s clock.
  2. Add two receipts: f of the source mToken owned by you (it satisfies J), and a of the destination mToken owned by O’s author (it satisfies O).
  3. Spend O’s f into your receipt and J’s a into O’s receipt.
  4. If f is less than O’s srcAmount, add a child intent for the remainder (a copy of O with the remaining amount and a fresh nonce) and spend the remainder into it.

The worked example in the intent reference shows the resulting solution.

Sign J as an EIP-712 intent. Sign the solution by hashing its ABI encoding and signing the raw hash. Then call proposeSolution with the signed solution, your signed JIT intents, and false.

  • Success returns the hub transaction hash, and the subscription broadcasts SolutionAccepted.
  • Rejection returns a JSON-RPC error to you only; nothing is broadcast. Error -32009 means Medusa could not accept the solution right now. Nothing executed, so resend it unchanged. Treat any other error as a rejection and rebuild.

Another solver may fill the same order first. Expect rejections for intents that are no longer open, and rebuild from your updated book.

  • Keep the key that signs solutions on a server you control. Anyone with it can spend your hub inventory through solutions.
  • Watch the hub clock and the deadline. An order you are partway through can expire; your remainder child carries the same deadline.
  • Rebalance. Fills move your inventory between mTokens, so withdraw and redeposit to keep the pairs you quote funded.
  • Validation bounds your downside: a solution that would underpay an intent, overspend escrow, or pay the wrong owner does not execute.