# Run a solver

> Subscribe to the book, build a solution, sign it, submit it, and keep your state in step.

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](/solvers/medusa-api/) and the [intent reference](/solvers/intent-reference/).

## 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

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.

## 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 `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](/solvers/medusa-api/#withdrawals) for the signing type and encoding.

## 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`:

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](/solvers/intent-reference/#a-worked-fill) shows the resulting solution.

## 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 `-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.

## 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.
