Intents and orders
What an intent is
Section titled “What an intent is”An intent is a declaration of an acceptable outcome, authorized by its owner: what must be true when it settles, not the steps to get there.
“Get me from New York to Paris tomorrow, in under eight hours, for under $800.” The traveller fixes price, timing and destination. The travel agent chooses the airlines and the connections.
On Khalani an intent escrows its source value up front and states the outcome it accepts. The hub releases the escrow only for a fill that meets that outcome. A fill that doesn’t meet it cannot execute, so the user never carries that risk.
An intent has two sides:
- Give: the escrowed source, an amount of one mToken.
- Get: the outcome it accepts. The hub accepts two shapes today: an exact amount of one destination mToken, or a rate that any fraction of the source can be filled at. API orders always use the rate. The intent format also defines minimums, ranges and multiple acceptable assets, which the hub does not accept yet.
How an order becomes an intent
Section titled “How an order becomes an intent”An order built with POST /v2/build becomes one intent on the hub, the root intent, when its deposit arrives:
- Give: the deposit, in source mTokens, less the fees withheld at publish.
- Get: the destination mToken at the quoted rate (
intentOutcomeRate), fillable in any fraction. - Valid until: the order’s deadline.
The order’s terms (pair, amount, rate, flat fee, recipients, deadline) were signed at build and must match the deposit the user sent. No API call or transaction can change them after the deposit. traces.rootIntentId in the order response is this intent’s id, and a cancel signs against it.
Partial fills form a chain
Section titled “Partial fills form a chain”A rate-based intent can fill in pieces. When a solver fills part of it, the hub splits the intent in the same transaction: the filled slice’s output is credited to the order on the hub, the parent closes, and the remainder becomes a child intent. Nothing is paid out to the user until the order settles.
The child is not a new order. The hub requires it to carry the parent’s exact terms (same author, rate and deadline), so only the amount shrinks. A sequence of partial fills therefore forms a chain in which every link holds the rate of the original order:
flowchart LR
root["root intent<br/>1,000"] -- "remainder 400" --> c1["child 1<br/>400"]
c1 -- "remainder 150" --> c2["child 2<br/>150"]
c2 --> tip["tip<br/>open, filled, expired<br/>or cancelled"]
root -. "filled 600" .-> p1["credited at the rate"]
c1 -. "filled 250" .-> p2["credited at the rate"]
The API reports the whole chain as one order. traces.chainObservations records each link as it is observed.
How an intent ends
Section titled “How an intent ends”The last child in the chain is its tip. It either fills completely, reaches the deadline, or is cancelled, and one settlement transaction then closes the order:
- the filled amount, at the order’s rate, is paid to
payoutAddron the destination chain, - the unfilled share of the deposit, after the flat fee, is refunded to
refundAddron the source chain, - the fees are taken: the flat fee in full, the percentage fees on the filled part only.
Each order settles once. Cancels and fills are applied in sequence, so a cancel that races a fill settles what was filled and refunds the rest.