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.
1. Keep a live copy of the book
Section titled “1. Keep a live copy of the book”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.
2. Recognise what you can fill
Section titled “2. Recognise what you can fill”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 havevalidBeforeset 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.
3. Hold inventory on the hub
Section titled “3. Hold inventory on the hub”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
withdrawMtokensrequest releases inventory to the same address on the mToken’s origin spoke. - Non-EVM origin: use
withdrawMtokensWithPayloadwith the recipient encoded indstAddrBytes. The address-only request cannot express a Bitcoin or TRON destination. See Withdrawals for the signing type and encoding.
4. Build a solution
Section titled “4. Build a solution”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:
- Size J to give
a = ceil(f × r / 10^18)of the destination mToken, at a rate that accepts exactlyfof the source. Give itvalidAfter0 and avalidBeforeat or after the hub’s clock. - Add two receipts:
fof the source mToken owned by you (it satisfies J), andaof the destination mToken owned by O’s author (it satisfies O). - Spend O’s
finto your receipt and J’sainto O’s receipt. - If
fis less than O’ssrcAmount, 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.
5. Sign and submit
Section titled “5. Sign and submit”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
-32009means 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.
6. Operate safely
Section titled “6. Operate safely”- 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.