LI.FI Intents Testing
Focused quote-to-fill checks for the LI.FI Intents solver pass.
This page is the test companion to the Aggregator Market Access Plan. The implementation is intentionally one vertical slice: publish quotes, prepare one selected order, build fill calldata with real hook material, and submit the fill when running live.
Current Commands
Use the registration command first, then the quote/fill runner:
pnpm --filter @steerprotocol/collateral-rail-quote-server lifi:register-solver
pnpm --filter @steerprotocol/collateral-rail-quote-server lifi:register-solver -- --live
pnpm --filter @steerprotocol/collateral-rail-quote-server lifi:submit-trust-components
pnpm --filter @steerprotocol/collateral-rail-quote-server lifi:submit-trust-components -- --live --strict
pnpm --filter @steerprotocol/collateral-rail-quote-server lifi:run -- --publish-quotes
pnpm --filter @steerprotocol/collateral-rail-quote-server lifi:run -- --fill-once
pnpm --filter @steerprotocol/collateral-rail-quote-server lifi:run -- --publish-quotes --fill-once
pnpm --filter @steerprotocol/collateral-rail-quote-server lifi:open-escrow-order -- --quote-backed
pnpm --filter @steerprotocol/collateral-rail-quote-server lifi:open-escrow-order -- --quote-backed --preflight
pnpm --filter @steerprotocol/collateral-rail-quote-server lifi:open-escrow-order -- --quote-backed --live
pnpm --filter @steerprotocol/collateral-rail-quote-server lifi:readiness -- --strict
pnpm --filter @steerprotocol/collateral-rail-quote-server lifi:serve -- --onceAdd --live only after reviewing the dry-run JSON. Without --live, the
runner builds quote bodies and fill plans but does not submit transactions.
The LI.FI solver API key is sent as x-api-key.
Quote submission uses the live solver API chain fields fromChain and
toChain; keep tests around this because older docs have shown
fromChainId/toChainId.
Registration Inputs
LI_FI_INTENTS_API_KEYLI_FI_ORDER_SERVER_BASELI_FI_SOLVER_ACCOUNT_ADDRESSLI_FI_SOLVER_ACCOUNT_MESSAGELI_FI_SOLVER_ACCOUNT_SIGNATURELI_FI_TRUST_COMPONENTS_JSONLI_FI_TRUST_COMPONENTS_PATH, optional path override for trust-component submission
The public LI.FI docs currently describe POST /quotes/trustComponents, but
the dev API returns HTTP 404 for that path. Keep
lifi:submit-trust-components in dry-run mode for local schema validation
unless LI.FI confirms the current dev path.
Quote Inputs
LI_FI_INTENTS_API_KEYLI_FI_ORDER_SERVER_BASELI_FI_INVENTORY_ROUTES_JSON, static quote route list; each route includes token decimalsLI_FI_QUOTE_TTL_SECONDSLI_FI_PREVIEW_POLICY_JSONLI_FI_TRUST_COMPONENTS_JSONLI_FI_ALLOWED_ORIGIN_CHAINSLI_FI_ALLOWED_OUTPUT_CHAINSLI_FI_ALLOWED_INPUT_TOKENSLI_FI_ALLOWED_OUTPUT_TOKENS
LI_FI_EXCLUSIVE_FOR is derived from the deployed LI.FI hook executor when the
deployment manifest exists for CHAIN_ID.
Fill Inputs
CHAIN_IDQUOTE_RPC_URLorRPC_URLfor live fills. If omitted,loadRuntimeEnvfalls back toSEPOLIA_RPC_URL.SPONSOR_SIGNER_PRIVATE_KEY. If omitted,loadRuntimeEnvfalls back toREGISTERED_ISSUER_QUOTE_SIGNER_PRIVATE_KEY.LI_FI_ORDER_FETCH_PATH, used when selected-order JSON is omittedLI_FI_READINESS_CHECK_ORDERS, set tofalseto skip readiness order pollingLI_FI_SERVE_PUBLISH_QUOTESLI_FI_SERVE_VERIFY_IDENTITYLI_FI_SERVE_FILL_ORDERSLI_FI_SERVE_POLL_INTERVAL_MSLI_FI_SERVE_MAX_ITERATIONSLI_FI_PENDING_FILL_ALERT_SECONDSLI_FI_SERVE_PLAN_FINALISELI_FI_SERVE_SUBMIT_FINALISELI_FI_BACKGROUND_ENABLED, set tofalsewhen the HTTP server should only provide manual quote-signing endpointsLI_FI_INPUT_SETTLER_KIND,escroworcompactTARGET_POOL_ID, required when build-request JSON is omitted. If omitted,loadRuntimeEnvfalls back toREGISTERED_ISSUER_POOL_ID.LI_FI_REPLAY_PGLITE_DATA_DIR, required for live fillsLI_FI_MIN_FILL_BUFFER_SECONDSLI_FI_FILL_MODE, defaults tohook-executor; usedirect-output-settleronly for compatibility testsLI_FI_POOL_KEY_JSONM1_JWT
Deployed registered-issuer profiles derive the LI.FI executor, input/output
settlers, broker adapter, collateral, USDM1, issuer id, settlement controller,
collateral manager, router, solver address, exclusive-for address, and
quote-backed M1 defaults from deployments/manifests/<chainId>-*.json, with
broadcast/DeployLifiHookExecutor.s.sol/<chainId>/run-latest.json as the
executor fallback.
Keep manual override variables such as LI_FI_SELECTED_ORDER_JSON,
LI_FI_BUILD_REQUEST_JSON, LI_FI_HOOK_MATERIAL_JSON,
LI_FI_QUOTED_PRICE_E18, approval override JSON, and finalise overrides for
controlled compatibility tests only.
LI_FI_TEST_INPUT_TOKEN,LI_FI_TEST_OUTPUT_TOKEN,LI_FI_TEST_INPUT_AMOUNT, andLI_FI_TEST_OUTPUT_AMOUNT, optional controlled escrow order overrides. When omitted, the opener uses the firstLI_FI_INVENTORY_ROUTES_JSONroute and reuses routemaxToAmountwhen it is present. Manual plain tests may still compute output fromLI_FI_QUOTED_PRICE_E18.LI_FI_TEST_ORDER_PRIVATE_KEYandLI_FI_TEST_ORDER_ADDRESS, optional funded escrow-order wallet. When omitted, the opener falls back toSPONSOR_SIGNER_PRIVATE_KEY.LI_FI_MIN_NATIVE_BALANCE_WEI, optional live opener gas-balance floorLI_FI_TEST_OUTPUT_CHAIN_ID,LI_FI_TEST_FILL_DEADLINE_SECONDS,LI_FI_TEST_EXPIRY_SECONDS,LI_FI_TEST_OUTPUT_CALL, andLI_FI_TEST_OUTPUT_CONTEXTfor optional escrow-order overrides.LI_FI_TEST_ORDER_USER,LI_FI_TEST_ORDER_NONCE, andLI_FI_TEST_OUTPUT_RECIPIENTare fixture/debug overrides only; by default the opener derives the user and recipient from the order signer and generates a fresh order nonce.
Tests
Local tests should prove only the retained vertical slice:
- M1 quote routes use live capacity previews and produce LI.FI quote submission bodies
- solver registration builds and submits the expected registration body
- escrow order opener builds LI.FI
StandardOrderbytes andopen(StandardOrder)calldata without submitting by default - dry-run quote publishing never calls LI.FI
- selected order + build request + hook material produce fill calldata
- default fill mode builds
LifiHookExecutor.finaliseEscrowOrder(...)calldata and does not require solver-side output inventory - direct output-settler mode remains covered as a compatibility test
- selected order fetch can derive build request and plain, registered-issuer, or M1 deposit hook material when manual JSON is omitted
- PGlite replay journal persists approval and fill submissions across process opens
- serve loop refreshes quotes, polls orders, fills new order ids, and skips duplicate order ids
- live serve loop checks
/solver-api/solver/identitiesbefore quote/order/fill work unlessLI_FI_SERVE_VERIFY_IDENTITY=false - serve loop can poll selected orders without filling them when
LI_FI_SERVE_FILL_ORDERS=false - serve loop queries LI.FI order status after attempted fills
- serve loop plans escrow/compact finalise calldata after delivered/proven status when finalise config is present
- finalise submitter preflights, waits for receipts, and reuses replay records
- serve loop reports stale pending fills from durable replay storage
- dry-run fill returns replay key, target, chain id, and no transaction hash
- live fill path is guarded by signer, chain id, deadline buffer, and preflight
Venue Checks
Run lifi:readiness -- --strict for identity and uploaded quote checks, then
run lifi:serve -- --once for one quote-publish/order-poll/fill iteration.
Leave LI_FI_SERVE_SUBMIT_FINALISE=false until an order reaches a
delivered/proven status with valid finalise inputs.
For live readiness without publishing quotes or filling orders:
LI_FI_SERVE_PUBLISH_QUOTES=false LI_FI_SERVE_FILL_ORDERS=false \
pnpm --filter @steerprotocol/collateral-rail-quote-server lifi:serve -- --live --onceWhen a manual command needs only the quote-signing endpoints, start the quote server with the background publisher disabled:
LI_FI_BACKGROUND_ENABLED=false pnpm --filter @steerprotocol/collateral-rail-quote-server devThe current LI.FI dev key has been verified to return one registered identity matching the quote signer.
For non-mutating readback after quote publication:
pnpm --filter @steerprotocol/collateral-rail-quote-server lifi:readiness -- --strict
pnpm --filter @steerprotocol/collateral-rail-quote-server lifi:readiness -- --strict --skip-ordersThe readiness command checks the registered signer identity, uploaded quotes,
configured quote route coverage, and optionally the /orders count. It
does not publish, open, approve, fill, or finalise anything.
The live dev readback currently returns uploaded quotes as flattened rows under
data; the quote-server client normalizes those rows before matching them to
LI_FI_INVENTORY_ROUTES_JSON.
Controlled Escrow Order
Use this only after quote publishing is accepted and the test account is funded on the origin chain:
pnpm --filter @steerprotocol/collateral-rail-quote-server lifi:open-escrow-order -- --quote-backed
pnpm --filter @steerprotocol/collateral-rail-quote-server lifi:open-escrow-order -- --quote-backed --preflight
pnpm --filter @steerprotocol/collateral-rail-quote-server lifi:open-escrow-order -- --quote-backed --liveQuote-backed dry-run mode requests a LI.FI integrator quote, selects the quote
whose metadata.exclusiveFor matches our configured hook executor/exclusive
filler, and returns the LI.FI-provided approval check and
order.openIntentTx. Preflight mode reads native gas, input-token balance, and
allowance without submitting. Live mode approves the returned spender when
allowance is too low, then submits the returned open transaction. After the
order server detects it, lifi:serve -- --live --once can ingest it from
/orders without LI_FI_SELECTED_ORDER_JSON. The live opener also reports
open.onChainOrderId when it can extract the order id from the input-settler
receipt logs for operator evidence. The raw opener is still available by
omitting --quote-backed, but it is only for local calldata/debug
compatibility.
In live mode the opener preflights the signer native balance, ERC-20 input
token balance, and existing allowance before submitting approval/open
transactions. It fails closed before approval if native gas is below
LI_FI_MIN_NATIVE_BALANCE_WEI or if the input-token balance is lower than
LI_FI_TEST_INPUT_AMOUNT.
Use LI_FI_TEST_ORDER_PRIVATE_KEY for this funded order wallet when the
registered solver signer should remain separate from the escrow order creator.
LI_FI_TEST_ORDER_ADDRESS is an optional guard; if present it must match the
private key-derived address.
If the LI_FI_TEST_* token/amount overrides are omitted, the opener uses
the first quote route's tokenIn, tokenOut, and amount. Prefer
publishing routes with maxToAmount; the old
amount * LI_FI_QUOTED_PRICE_E18 / 1e18 derivation is only for manual plain
tests.
For same-chain controlled tests, the opener defaults missing settlement
addresses to the maintained LI.FI deployments: InputSettlerEscrow
0x000025c3226C00B2Cdc200005a1600509f4e00C0 and Output Settler
0x0000000000eC36B683C2E6AC89e9A75989C22a2e. It also defaults both oracle
fields to the Output Settler, matching LI.FI same-chain guidance.
The Steer fill path is same-chain callback based. In v1 the deployed
LifiHookExecutor is the LI.FI solver identity, while the hot EOA is only the
operator submitting transactions. The executor receives escrowed input tokens
during LI.FI finalise, calls the signed swap router with dynamically generated
hook calldata, and passes the hook-generated output tokens to LI.FI's output
settler.
Remaining Automation Tests
The unattended lifi:serve command exists; remaining tests should cover:
- duplicate order rejection by
orderId - repeated selected-order polling loop
- live settlement/finalisation against delivered/proven status payloads