Steer Protocol
Developer Guide

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

Add --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_KEY
  • LI_FI_ORDER_SERVER_BASE
  • LI_FI_SOLVER_ACCOUNT_ADDRESS
  • LI_FI_SOLVER_ACCOUNT_MESSAGE
  • LI_FI_SOLVER_ACCOUNT_SIGNATURE
  • LI_FI_TRUST_COMPONENTS_JSON
  • LI_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_KEY
  • LI_FI_ORDER_SERVER_BASE
  • LI_FI_INVENTORY_ROUTES_JSON, static quote route list; each route includes token decimals
  • LI_FI_QUOTE_TTL_SECONDS
  • LI_FI_PREVIEW_POLICY_JSON
  • LI_FI_TRUST_COMPONENTS_JSON
  • LI_FI_ALLOWED_ORIGIN_CHAINS
  • LI_FI_ALLOWED_OUTPUT_CHAINS
  • LI_FI_ALLOWED_INPUT_TOKENS
  • LI_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_ID
  • QUOTE_RPC_URL or RPC_URL for live fills. If omitted, loadRuntimeEnv falls back to SEPOLIA_RPC_URL.
  • SPONSOR_SIGNER_PRIVATE_KEY. If omitted, loadRuntimeEnv falls back to REGISTERED_ISSUER_QUOTE_SIGNER_PRIVATE_KEY.
  • LI_FI_ORDER_FETCH_PATH, used when selected-order JSON is omitted
  • LI_FI_READINESS_CHECK_ORDERS, set to false to skip readiness order polling
  • LI_FI_SERVE_PUBLISH_QUOTES
  • LI_FI_SERVE_VERIFY_IDENTITY
  • LI_FI_SERVE_FILL_ORDERS
  • LI_FI_SERVE_POLL_INTERVAL_MS
  • LI_FI_SERVE_MAX_ITERATIONS
  • LI_FI_PENDING_FILL_ALERT_SECONDS
  • LI_FI_SERVE_PLAN_FINALISE
  • LI_FI_SERVE_SUBMIT_FINALISE
  • LI_FI_BACKGROUND_ENABLED, set to false when the HTTP server should only provide manual quote-signing endpoints
  • LI_FI_INPUT_SETTLER_KIND, escrow or compact
  • TARGET_POOL_ID, required when build-request JSON is omitted. If omitted, loadRuntimeEnv falls back to REGISTERED_ISSUER_POOL_ID.
  • LI_FI_REPLAY_PGLITE_DATA_DIR, required for live fills
  • LI_FI_MIN_FILL_BUFFER_SECONDS
  • LI_FI_FILL_MODE, defaults to hook-executor; use direct-output-settler only for compatibility tests
  • LI_FI_POOL_KEY_JSON
  • M1_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, and LI_FI_TEST_OUTPUT_AMOUNT, optional controlled escrow order overrides. When omitted, the opener uses the first LI_FI_INVENTORY_ROUTES_JSON route and reuses route maxToAmount when it is present. Manual plain tests may still compute output from LI_FI_QUOTED_PRICE_E18.
  • LI_FI_TEST_ORDER_PRIVATE_KEY and LI_FI_TEST_ORDER_ADDRESS, optional funded escrow-order wallet. When omitted, the opener falls back to SPONSOR_SIGNER_PRIVATE_KEY.
  • LI_FI_MIN_NATIVE_BALANCE_WEI, optional live opener gas-balance floor
  • LI_FI_TEST_OUTPUT_CHAIN_ID, LI_FI_TEST_FILL_DEADLINE_SECONDS, LI_FI_TEST_EXPIRY_SECONDS, LI_FI_TEST_OUTPUT_CALL, and LI_FI_TEST_OUTPUT_CONTEXT for optional escrow-order overrides. LI_FI_TEST_ORDER_USER, LI_FI_TEST_ORDER_NONCE, and LI_FI_TEST_OUTPUT_RECIPIENT are 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 StandardOrder bytes and open(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/identities before quote/order/fill work unless LI_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 --once

When 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 dev

The 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-orders

The 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 --live

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

On this page