Skip to content

[9] feat(checkout): use any route for wallet payments, EVM-only#794

Open
tomiiide wants to merge 7 commits into
checkout/08-activity-and-polishfrom
checkout/09-wallet-any-route
Open

[9] feat(checkout): use any route for wallet payments, EVM-only#794
tomiiide wants to merge 7 commits into
checkout/08-activity-and-polishfrom
checkout/09-wallet-any-route

Conversation

@tomiiide

Copy link
Copy Markdown
Contributor

Which Linear task is linked to this PR?

N/A

Why was it implemented this way?

This branch builds on checkout/08-activity-and-polish and adds the wallet-any-route work plus an EVM-only restriction for checkout.

  • Wallet pays via any route. The wallet funding flow pays directly from the connected wallet, so it keeps the integrator's full route set (no Intent Factory deposit-only override). Deposit flows (transfer/exchange/cash) still force the IF-only allow-list to surface a deposit-address route.
  • Connected wallets as destination recipients. The destination step offers already-connected wallets matching the destination ecosystem, and seeds the connected wallet as the default recipient in wallet flows.
  • EVM-only for now. Checkout forces chains.types to EVM-only, cascading to chain lists, token lists, route quotes, and the wallet menu (which now honors chains.types). The native gas token is hidden from source-token selection in the IF deposit flows, since IF cannot accept it; the wallet flow keeps full token support.

Token-type filtering is handled naturally by the existing chain-type config rather than a parallel token allow-list, reusing useTokens/useChains/useAvailableChains.

Visual showcase (Screenshots or Videos)

Not included; UI changes are funding-source/token-list filtering. Recommend a manual pass in the playground to confirm non-EVM chains/wallets/tokens are hidden and an EVM to EVM quote resolves.

Checklist before requesting a review

  • I have performed a self-review and testing of my code.
  • This pull request is focused and addresses a single problem.
  • If this PR modifies the Widget API or adds new features that require documentation, I have updated the documentation in the public-docs repository.

@changeset-bot

changeset-bot Bot commented Jun 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a622864

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@lifi/widget-checkout Minor
@lifi/widget Minor
nft-checkout Patch
tanstack-router-example Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@tomiiide tomiiide self-assigned this Jun 17, 2026
@tomiiide tomiiide force-pushed the checkout/08-activity-and-polish branch from 3b2e1c7 to 434a835 Compare June 17, 2026 10:10
@tomiiide tomiiide force-pushed the checkout/09-wallet-any-route branch from fb8bb22 to 9d790dc Compare June 17, 2026 10:10
tomiiide added 7 commits June 17, 2026 12:37
- Wallet flow drops the Intent-Factory-only exchange override; the
  deposit flows (transfer/exchange/cash) keep it.
- Records with no deposit address poll status by tx hash, deriving
  cross-chain bridge hints from the frozen route; resume opens the
  status page by hash.
- Wallet records now always persist the frozen quote so those hints
  are available to the activity list and resume.
- Pre-fills the recipient with the connected account matching the
  destination ecosystem when the integrator leaves it user-settable;
  the field stays editable.
- Falls back to the manual "where to send it" prompt when no connected
  account matches the destination chain.
Stops the seeded default (e.g. USDC) from rendering pre-highlighted;
a per-flow tokenSelected flag gates it until a genuine tap.
Fixes already-connected wallets being unselectable: the old commit
only fired on a new connection event, never for an existing wallet.
- Poll relayer/gasless routes by taskId, not as a txHash (distinct keys in
  the SDK status API), so they no longer hang on NOT_FOUND
- Resume an unfinished wallet route (in flight or failed) on the execution
  page so the SDK re-prompts/retries, instead of the poll-only status page
- Re-seed an evicted route from the 24h snapshot before resuming
- Force chains.types to EVM-only; cascades to chains, tokens, routes, wallets
- Hide native gas token in transfer/exchange/cash flows (IF can't accept it)
- Wallet menu now honors chains.types ecosystem allow/deny config
@tomiiide tomiiide force-pushed the checkout/09-wallet-any-route branch from 9d790dc to a622864 Compare June 17, 2026 10:38
@tomiiide tomiiide force-pushed the checkout/08-activity-and-polish branch from 434a835 to 08cd204 Compare June 17, 2026 10:38
@vinzenzLIFI

vinzenzLIFI commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Checkout manual testing — findings

Did a first manual pass on this branch. Tested so far:

  • Pay from Wallet — end-to-end on Ethereum mainnet, completed successfully.
  • Transfer Crypto (deposit-address / smartDeposits) — end-to-end on Ethereum mainnet (hit the refund path; see notes).
  • Deposit with Cash (Transak) — up to the Transak payment screen.

This is a first pass, not exhaustive — more testing will follow (see "Not tested yet" below). Findings so far:

🐞 Bugs (widget)

1. Back from the refund screen lands in a "Transaction details" limbo
After a deposit refunds, pressing Back navigates to the Transaction Details page, which polls /v1/status?txHash=<deposit-contract-creation-hash>&fromChain=1&toChain=1404 in a loop. Result: a permanent "Processing transaction" screen with misleading "USDC received / Swapped to stETH" steps that never resolve and contradict the refund.
→ The tx hash being polled is the deposit address's contract-creation tx, not the user's transfer. Once the flow is refunding, it shouldn't poll a tx-hash status (or should use the user's send tx). Related backend gap: the status response omits the user's initial send tx + sender address (thread).

2. Cancel-from-Transak → first Back press does nothing
Repro: Deposit with cash → Transak opens → close Transak (returns to amount screen) → click Back → no reaction; a second click works.
Cause: the cancel handler does navigate({ to: enterAmount, replace: true }) (CheckoutTransactionStatusPage.tsx:120), which replaces the status route with a second /enter-amount entry sitting right on top of the existing one. The first router.history.go(-1) (Header.tsx:71) pops to an identical /enter-amount → no visible change.
→ Fix: pop back with router.history.go(-1) instead of replace-navigating to enterAmount.

3. Cash flow doesn't forward amount/currency to Transak
Selecting "Deposit with cash" clears the amount (SelectSourcePage.tsx:232) and opens the Transak session without a fiatAmount, so Transak shows its own default "You pay 250 EUR" — including a currency that may not match the one selected in the checkout currency step. We should forward a sensible default amount and the selected currency.

ℹ️ Known issues (not widget bugs — for reference)

  • Refund on simulation failure is expected (IF retries, then refunds); the stETH-on-mainnet flakiness that triggered it on develop is known instability → CORE-360, IF edge-case thread.
  • Transfer-crypto unsupported on Arbitrum (IF is EVM-mainnet-only for now) → IF integration channel.
  • Cash refund returns funds to the Transak wallet, not the user — open design question → thread.

🧪 Not tested yet

This branch's changes still to verify (#794):

  • EVM-only enforcement — non-EVM chains, tokens, and wallets (wallet menu) are hidden.
  • Native gas token hidden in IF flows — ETH absent from the transfer/cash source-token list, but available in pay-from-wallet.
  • Connected wallets as destination recipients — the recipient picker on the destination step.

General:

  • Custom destination address — typed address / ENS validation (only used a connected wallet so far).
  • Pending / resume — close mid-deposit and remount (resumePending).
  • onError / onClose integrator callbacks (onSuccess seen via pay-from-wallet).

Blocked on a test account / payment method:

  • Connect Exchange (Mesh), e2e — no exchange test account. Also, connecting a self-custody wallet via Mesh failed: MetaMask never popped up and Mesh showed "Oops it looks like you denied the connection request" (nothing was actually denied). Likely the known multi-wallet-extension collision — the console showed window.ethereum conflicts ("Cannot redefine property: ethereum"), already acknowledged (dev-chains thread). Needs a re-test with only MetaMask enabled before filing.
  • Deposit with wallet address (Mesh) — unclear if implemented; avoided wasting funds.
  • Deposit with Cash — post-payment callback — no test card / Apple Pay / GPay, so tested only up to the Transak screen; funds arrive → IF executes → final status still needs a run.

@tomiiide tomiiide changed the title feat(checkout): use any route for wallet payments, EVM-only [9] feat(checkout): use any route for wallet payments, EVM-only Jun 18, 2026
@vinzenzLIFI

Copy link
Copy Markdown
Contributor

🐛 Mesh deposit flow — UI flicker on the failure→refund transition

Tested the Mesh (exchange) handoff e2e with real funds. Final "Refund complete" screen is correct, but on the way there the UI briefly shows funds-received → regresses to a loading/watching spinner → then the refund screen.

Root cause (IF, already known — not a new bug): the deposit-address /status regresses PENDING → INTENT_SIMULATION_FAILURE → NOT_FOUND → REFUND_IN_PROGRESS → DONE/REFUNDED. The intermediate NOT_FOUND is the IF status-regression Tomi already raised with Georgi → thread. A hotfix landed ~Jun 15 but the simulation-failure path still regresses (Tomi's Jun 16 follow-up; reconfirmed in my Jun 18 test).

Widget resilience gap (this is the part we can fix here): the status hook treats any NOT_FOUND as "pre-deposit, keep watching" and discards the last real status — useCheckoutTransactionStatus.ts#L123:

const resolvedStatus = data && data.status !== 'NOT_FOUND' ? data : undefined

So one regressive NOT_FOUND collapses resolvedStatus/phase and the render falls back to the watching screen (CheckoutTransactionStatusPage.tsx#L253), un-showing the real state. Suggested fix: latch the last non-NOT_FOUND status and never downgrade on a later NOT_FOUND (deposit-address path); later real updates still overwrite it. Same guard should cover the resume path (CheckoutTransactionStatusPage.tsx#L126-148), which currently bails to enter-amount on NOT_FOUND — a manual reload during that window would lose the refund screen.

This makes the UX resilient regardless of the IF fix timeline.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants