Collecting Orders
The order server is a helpful intermediary that allows users to submit intents (orders) and broadcasts those intents to solvers. It serves as a central hub that:
- Collects user intents from various sources.
- Broadcasts these intents to connected solvers in real-time.
- Tracks the on-chain status of all transactions.
Order subscription
Section titled “Order subscription”There are 2 ways to collect orders. Either through a websocket subscription where orders will be pushed or via a GET endpoint. It is recommended to get orders pushed via the websocket subscription. Both methods can be found in the lintent.org demo implementation.
If you use the GET endpoint too aggressively, you may be throttled or temporarily timed out. You can find swagger documentation on api interfaces on https://order-dev.li.fi/docs.
Order Server events
Section titled “Order Server events”When connected to the order server, the order server will continuously send a ping messages to which the client is expected to respond with a pong
. This is used to disconnect misbehaving clients and for debugging purposes. You can find an example implementation here.
For order collection, the important event is user:vm-order-submit
. The Data will be returned similarly to it was submitted.
Order Validation
Section titled “Order Validation”LI.FI Intents allows highly customizable orders. As a result, you should add further validation to ensure you support the order being relayed to you. It is important to properly validate orders.
Below, the term whitelisted refers to trusted and validated by you. When a token must be whitelisted, it means you trust the token. If a validation layer is whitelisted, it means you trust the validation layer, etc. Whitelisted does not mean permissioned by a central entity; it means trusted by you.
The following is an attempt at an exhaustive list of validations that solvers must implement. While this list may seem excessive, you have likely already implemented checks for most of these.
-
fillDeadline
: Ensure you have sufficient time to fill the order:- Time to fill on the destination chain, including potential source chain finality.
-
expiry
: Ensure you have enough time to fill, relay, and claim the order:- Time to fill on the destination chain, including potential source chain finality.
- Time to send message validation proof to the input chain.
- Time to claim the order after validation has been delivered.
-
Validation layer: Ensure you support submitting proofs (and, if not automatic, also relaying) to the validation layer. Additionally, the
localOracle
andremoteOracle
must be of the same validation layer. -
Ensure you have whitelisted every single
input
token. If one input token is malicious, the order may be unclaimable. Additionally, for blacklistable tokens like USDC, ensure you are not on a blacklist.- If an order has a 0 input or output of a token you have not whitelisted, the order may not be fillable. Be careful about filling orders containing unfamiliar tokens.
-
Ensure every
input
token uses the same AllocatorId. If the lockId are different, the lock expiry should be checked for every lockId. Alternatively, check if all lockIds are equal. -
Ensure the potential
reset period
for a resource lock extends beyond theexpiry
AND there is no active withdrawal. -
Ensure the
allocatorID
is whitelisted. The allocator can block claims from processing (by withdrawing signatures or reusing nonces.)- The allocatorID is part of the
lock tag
forinputs
(first 12 bytes). - Optionally, ensure the user has sufficient tokens. This should have been validated by the allocator, though.
- The allocatorID is part of the
-
Ensure the user provides an ECDSA signature or they have a whitelisted emissary registered or you register the claim on-chain before filling the claim.
- Note: If any of these actions are taken, the signature can be assumed to be trusted.
- Emissary signatures cannot be registered on-chain. The emissary must be trusted not to redact a signature.
-
For each output:
output.chainId
is whitelisted.remoteOracle
andlocalOracle
are correctly configured regardingoriginChainId
andoutput.chainId
. The config is immutable, so this can be done once for each pair.output.remoteFiller
is whitelisted.output.fulfillmentContext
is decodable, and the order type is supported and compatible withoutput.remoteFiller
.output.token
is whitelisted. Additionally, for blacklistable tokens like USDC, ensure that neither you nor the recipient is on a blacklist.- If an order has a 0 input or output of a token you have not whitelisted, the order may not be fillable. Be careful about filling orders containing unfamiliar tokens.
- You have sufficient tokens for
output.amount
. - If the output has
calldata
, ensure you can execute it and other outputs atomically. For outputs on different chains, you may have to whitelist recipients if there iscalldata
.- On OP-chains, CrossL2Inbox needs to be blacklisted in the entire call tree. If similar contracts exist on another chain, they also need to be blacklisted.
- Neither
call.length
norcontext.length
are more than 65’535 bytes long. - Validate the context depending on order type. For Bitcoin specfically, ensure the encoded multiplier is relative to the Bitcoin value.
-
If the order has multiple outputs, ensure you can fill all outputs and the first output is set to your solver identifier. If all outputs are on the same chain,
fillBatch
can be used as a protective measure. -
Validate the
allocatorData
. You may have to do an on-chain call. -
Validate that the allocator
nonce
has not been spent previously by any user. The Order nonce is not a user nonce. -
If the InputSettler has any fees, check for an imminent fee change.
Signature Validation
Section titled “Signature Validation”The StandardOrder
will be used to interface all functions on the input chain. Additionally, once hydrated with a signature, it allows one to verify the validity of an order.
The StandardOrder
struct will be signed and stored as a witness in the appropriate lock/claim structure. For TheCompact, this is:
struct BatchCompact { address arbiter; // Associated settlement contract address sponsor; // StandardOrder.user uint256 nonce; // StandardOrder.nonce uint256 expires; // StandardOrder.expires uint256[2][] idsAndAmounts; // StandardOrder.inputs Mandate mandate;}
struct Mandate { uint32 fillDeadline; // StandardOrder.fillDeadline address localOracle; // StandardOrder.localOracle OutputDescription[] outputs; // StandardOrder.outputs}
To validate an order, ensure that the sponsor and allocator signatures are valid for this EIP-712 signed structure.
On-chain Order Broadcast
Section titled “On-chain Order Broadcast”When intents are registered on-chain, they can be broadcasted on the Input Settlement contract through the IntentRegistered
event:
event IntentRegistered(bytes32 indexed orderId, StandardOrder order);