# Intent and settlement reference

> The intent and solution types, the rules the hub validates every solution against, and a worked fill.

## Intent

```solidity
struct Intent {
    address author;        // whose escrow; receipts that satisfy it must be owned by this address
    uint256 validBefore;   // deadline, on the hub's clock
    uint256 validAfter;    // always 0
    uint256 nonce;         // unique per author
    address srcMToken;     // what it gives
    uint256 srcAmount;     // how much it escrows
    Outcome outcome;       // what it accepts
}

struct Outcome {
    address[] mTokens;
    uint256[] mAmounts;
    OutcomeAssetStructure outcomeAssetStructure; // AnySingle | Any | All
    FillStructure fillStructure;                 // Exactly | Minimum | PctFilled | ConcreteRange
}
```

The hub accepts two outcome shapes today, both `AnySingle`: the outcome lists one or more mTokens, each with its own amount or rate in `mAmounts[i]`, and a solution pays the intent in exactly one of them.

- **`Exactly`** (wire name `Exact`): `mAmounts[i]` is an exact amount. The intent must be spent completely and paid exactly that.
- **`PctFilled`** (wire name `PercentageFilled`): `mAmounts[i]` is a rate, outcome units per 10^18 source units. Any fraction can fill; each fill must pay the author at least `spent × rate / 10^18`.

Orders built through the Khalani API always list a single outcome mToken.

The other outcome shapes are defined but not accepted yet. An intent's state is `Open`, `Solved` or `Cancelled`; expired intents are cancelled.

## Solution

```solidity
struct Solution {
    bytes32[] intentIds;      // inputs: open intents, by id
    Intent[] intentOutputs;   // remainder children of partly filled inputs
    Receipt[] receiptOutputs; // value paid out of the graph
    MoveRecord[] spendGraph;  // where each input's escrow goes
    FillRecord[] fillGraph;   // which receipt satisfies each input
}

struct Receipt { address mToken; uint256 mTokenAmount; address owner; bytes32 intentHash; }
struct MoveRecord { uint64 srcIdx; OutputIdx outputIdx; uint256 qty; }   // input → output
struct OutputIdx { OutType outType; uint64 outIdx; }                      // Intent | Receipt
struct FillRecord { uint64 inIdx; uint64 outIdx; OutType outType; }       // input ← receipt
```

Just-in-time intents are submitted alongside the solution (the second `proposeSolution` parameter) and referenced in `intentIds` like any other input. They must be consumed in the same transaction.

## Enums

Hashes and signatures use each enum's `uint8` value. Medusa's JSON takes only the names, and rejects numbers. Two names on the wire differ from the Solidity names.

| Enum | `uint8` values | JSON names |
|---|---|---|
| `OutcomeAssetStructure` | `AnySingle` 0, `Any` 1, `All` 2 | `"AnySingle"`, `"Any"`, `"All"` |
| `FillStructure` | `Exactly` 0, `Minimum` 1, `PctFilled` 2, `ConcreteRange` 3 | `"Exact"`, `"Minimum"`, `"PercentageFilled"`, `"ConcreteRange"` |
| `OutType` | `Intent` 0, `Receipt` 1 | `"Intent"`, `"Receipt"` |

## Hashes

- **Intent id:** the EIP-712 `hashStruct` of the intent, with no domain. The intent book's `getIntentId(intent)` returns the same value, so an `eth_call` checks your encoding. The type string is:

  ```text
  Intent(address author,uint256 validBefore,uint256 validAfter,uint256 nonce,address srcMToken,uint256 srcAmount,Outcome outcome)Outcome(address[] mTokens,uint256[] mAmounts,uint8 outcomeAssetStructure,uint8 fillStructure)
  ```

- **Intent signature:** EIP-712 over the same struct under the `KhalaniIntent` domain described in [Signing](/solvers/medusa-api/#signing), whose separator is `0x6e8db7854b04f3651a03e71c732b1a9e8e41e68e2dea0e3ad621976c1409b722`.
- **Solution hash:** `keccak256(abi.encode(solution))`, with the whole solution encoded as one tuple, as Solidity's `abi.encode` of the struct does. The encoding starts with a `0x…20` offset word, `OutputIdx` is encoded inline and every enum is a `uint8`. The tuple type is:

  ```text
  (bytes32[],(address,uint256,uint256,uint256,address,uint256,(address[],uint256[],uint8,uint8))[],(address,uint256,address,bytes32)[],(uint64,(uint8,uint64),uint256)[],(uint64,uint64,uint8)[])
  ```

## Validation rules

The hub checks the whole solution before applying it, and reverts all of it if any check fails:

- Every input is `Open` and at or before its `validBefore` on the hub's clock.
- **Conservation:** for each input, the quantities moved out of it sum to its `srcAmount`.
- Every input spends something and is satisfied by at least one receipt in `fillGraph`.
- A spend into a receipt uses the input's `srcMToken`, and its `qty` equals the receipt's `mTokenAmount`. A spend into a remainder child has a `qty` equal to the child's `srcAmount`. Each receipt is funded by exactly one move and claimed by at most one fill.
- A receipt that satisfies an intent is owned by that intent's author, in the intent's outcome mToken.
- **The rate holds:** a `PctFilled` input receives at least its rate on what it spent; an `Exactly` input is spent completely and receives exactly its amount.
- **Remainders:** an input has at most one remainder child. The child must carry the parent's `author`, `srcMToken`, `validBefore`, `validAfter` and `outcome`; only `srcAmount` and `nonce` differ (any nonce unused for that author).

## A worked fill

An open order O, authored by the hub's order contract, gives `s = 1,000,000,000` of mToken S and accepts mToken D at rate `r = 998000000000000000` (0.998), `PctFilled`. You fill `f = 600,000,000` from your D inventory.

Your just-in-time intent J gives `a = ceil(f × r / 10^18) = 598,800,000` of D and accepts S at rate `floor(f × 10^18 / a)`, `PctFilled`, with `validAfter` 0 and a short `validBefore`.

```text
intentIds       [ O, J ]
receiptOutputs  [ R0: { mToken: S, mTokenAmount: 600000000, owner: you,      intentHash: J },
                  R1: { mToken: D, mTokenAmount: 598800000, owner: O.author, intentHash: O } ]
intentOutputs   [ C:  O with srcAmount 400000000 and a fresh nonce ]
spendGraph      [ { srcIdx: 0, outputIdx: { Receipt, 0 }, qty: 600000000 },   // O → R0
                  { srcIdx: 0, outputIdx: { Intent, 0 },  qty: 400000000 },   // O → remainder C
                  { srcIdx: 1, outputIdx: { Receipt, 1 }, qty: 598800000 } ]  // J → R1
fillGraph       [ { inIdx: 0, outIdx: 1, outType: Receipt },                  // R1 satisfies O
                  { inIdx: 1, outIdx: 0, outType: Receipt } ]                 // R0 satisfies J
```

O is spent `600,000,000 + 400,000,000 = s` and receives `598,800,000 ≥ 600,000,000 × 0.998`. J spends all of `a` and receives `600,000,000` of S at its rate. The remainder C stays open with O's terms, for the next solution.

On success, the subscription broadcasts `SolutionAccepted` with O and J solved and C new.

### Test vectors

The same fill with concrete values, to check your encoding offline. S is the Arbitrum USDC mToken, D the Base USDC mToken, O's author the order contract, and you are the example address `0x5b38da6a701c568545dcfcb03fcb875f56beddc4`.

```text
S  0xBfd80b874e2215f8d2Be0644c25271307Cc28076
D  0x6C3D9a02487D3B2d398bee6CB7c64bE0B38955cc
O  { author: 0xa83d18aa3F32270762147e0E0F2CC3396A8f157A, validBefore: 1792443600, validAfter: 0, nonce: 1,
     srcMToken: S, srcAmount: 1000000000,
     outcome: { mTokens: [D], mAmounts: [998000000000000000], AnySingle, PctFilled } }
J  { author: you, validBefore: 1792440000, validAfter: 0, nonce: 2,
     srcMToken: D, srcAmount: 598800000,
     outcome: { mTokens: [S], mAmounts: [1002004008016032064], AnySingle, PctFilled } }
C  O with nonce 3 and srcAmount 400000000
```

| Value | Result |
|---|---|
| O's id | `0xc797464c9a24cc82b8cc0e4d466a58caa3502513ebd7814f34e9305b7112f037` |
| J's id | `0x8e346366bbb72f460cd1c1de1690beefd13ce5a983dbec1372d78a1349386ecd` |
| C's id | `0x2506c2d8ee7ebf592a4ee2b8fb844129b6df6373f38b23ba71ef639f91430ebf` |
| J's EIP-712 digest | `0x5cba6caa7d0721b35110d1897fc28a99f6f35ca57343289fbc44119025f6365a` |
| Solution hash | `0x76f7f27454cfc380718880141cd9d42e44d9ccf385df6ff23d2bb7aee1625f45` |

The three ids are what the intent book's `getIntentId` returns for these intents. The solution is the worked fill above, with receipts R0 and R1 carrying J's and O's ids as `intentHash`.
