feat: add checkout widget#727
Draft
tomiiide wants to merge 62 commits into
Draft
Conversation
chybisov
reviewed
May 14, 2026
Comment on lines
+5
to
+14
| tokenEth: | ||
| 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/info/logo.png', | ||
| tokenUsdc: | ||
| 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png', | ||
| tokenMatic: | ||
| 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/polygon/info/logo.png', | ||
| exchangeCoinbase: 'https://cdn.simpleicons.org/coinbase/0052FF', | ||
| exchangeBinance: 'https://cdn.simpleicons.org/binance/F0B90B', | ||
| visa: 'https://cdn.simpleicons.org/visa/1A1F71', | ||
| mastercard: 'https://cdn.simpleicons.org/mastercard/EB001B', |
Member
There was a problem hiding this comment.
Please reach out to the design team for proper icons, and we need to put them here after they provide us with assets.
https://github.com/lifinance/types/tree/main/src/assets/icons
- Proxy Transak onramp flow with session creation - Resolve on-chain tokens to Transak crypto currencies - Handle partner auth with automatic token refresh
- Use correct auth headers and endpoints per Transak docs - Map mainnet chain IDs to testnet equivalents for staging - Handle native token address matching and add fallback data
- Add SIMULATE_ERROR env var (timeout/auth_error/config_error modes) - Add USE_REAL_CORE toggle to proxy requests to real Core API
- Checkout package: LifiWidgetCheckout (modal + ref API), router and pages for deposit/funding, MUI layout, theme/config providers, exports - Playground: @lifi/widget-checkout, swap vs checkout mode, preview, persist v3 - Deps: MUI/Emotion, TanStack Router, zustand
- Add CheckoutWidgetRuntime with checkout→WidgetConfig mapping and default wallet providers - Wire router for select source, enter amount, progress, funding paths, and widget token/tx routes - Implement SelectDepositTokenList in checkout using re-exported token-list hooks and components - Expand @lifi/widget public exports for compositors (pages, providers, token UI building blocks) - Export wallet-management wallet row helpers; pass playground widget props into checkout - Add root dev:mock-api script; refresh checkout deps and pnpm-lock.yaml
- Add TransakProvider: POST onramp session, iframe widget, useTransak hook - Add CheckoutConfig.onrampSessionApiUrl; share OnrampSession types - Lock destination asset in checkout UI (hidden/disabled to-token controls) - Merge mock Transak catalog with fallbacks (e.g. mainnet stETH) - Wire playgrounds: env for onramp API URL; default stETH target in widget - Remove Transak placeholder dialog and optional @transak/transak-sdk peer meta
- OnRampProvider + optional Transak/Mesh peers; UI SDK embed for Transak. - Drop funding-methods routes and picker UI; exchange row is coming-soon.
- Merge checkout en.json into widget languageResources for tags.* and checkout.*. - Wire layout, source page, funding options, and Transak dialog to useTranslation. - Transak: typed UI errors, stable English onError, wallet CTA via error code. - Export deepMerge from @lifi/widget.
- Add walletId to WalletMenuOpenArgs - Skip wallet-list when walletId is provided; useEffect fallback for resilience against stale state - Checkout TopWalletRows passes walletId for multi-connector cards - Back button closes modal when opened via walletId
- Wrap CheckoutRouter in error boundary with retry UI - Sync drawer visibility with controlled `open` prop - Wire onConnected/onConnecting/onError through wallet rows - Fix CSS property names in styled components - Extract ProgressPage strings to i18n - Log warnings for failed on-ramp adapter loads
Changes: - Move mock-api/ out of src/ to package root - Co-locate CheckoutDrawerContext with CheckoutDrawer at src/ root - Dissolve onramp/ into providers/OnRampProvider/ with nested TransakProvider/ and MeshProvider/ - Move SelectSource components into pages/SelectSourcePage/ - Rename CheckoutWidgetContainer to AppProvider
- Remove redundant Checkout prefix from components (Container, Header, Stack, ErrorBoundary). - Rename CheckoutDrawer to CheckoutModal (file, context, types, ref API). - Collapse barrel re-export files into component files.
Changes: - Move all checkout source to packages/widget/src/checkout/ - Move mock-api server to packages/widget/mock-api/ - Split checkout types into config, modal, results, and theme files - Inline CheckoutModalContext into CheckoutModal; rename AppProvider - Update all imports to relative paths within the widget package - Merge checkout i18n keys into widget en.json - Update playground to import checkout from @lifi/widget
Changes: - Remove CheckoutTheme, CheckoutResult, and FundingMethod types - Remove checkoutThemeToWidgetTheme and defaultCheckoutWalletProviders utilities - Replace checkout-specific config fields with a single config?: Partial<WidgetConfig> prop - Remove provider package dependencies no longer needed by checkout - Update playground to use the new config prop
Changes: - Add CheckoutResult interface and onSuccess prop to CheckoutConfig - Wire onSuccess through TransakProvider's order success handler - Fix config spread order so subvariant/variant can't be overridden
- Implement MeshProvider backed by optional @meshconnect/web-link-sdk peer - Extract shared OnRampFlowValue interface (Transak and Mesh now share it) - Add getProvider(id) to useOnRamp for provider-agnostic access - Activate "Connect Exchange" card in SelectSourceFundingOptions when Mesh SDK is installed - Add CexSessionRequest/Response types and Mesh i18n error messages
- Annotate forwardRef and createContext exports; inline route literals in checkoutNavigationRoutes so .d.ts can emit without cross-file inference. - Guard router subscribe in TransakCashProvider effect. - MUI v7 shorthand → sx; drop redundant !! coercions; misc dev tweaks.
- Sectioned funding picker; auto-advance to token select on connect. - Checkout-only amount/receive/deposit components — no review step. - CheckoutRoutesPage / CheckoutTransactionPage with optional auto-deposit; navigate via checkout-absolute paths. - Default deposit-to to Ethereum Lido stETH; normalize \`contractCalls\` to [] so useRoutes stops gating deposit quotes. - Scope the Transak cash modal to the widget scrollable container. - Fix --isolatedDeclarations errors across the checkout dir.
Changes:
- add postCheckoutSession client with x-lifi-api-key/x-lifi-integrator headers
- point Mesh/Transak providers at /v1/checkout/{onramp,cex}/session, require
widget apiKey, read base URL from onrampSessionApiUrl
- flatten CexSessionRequest to {walletAddress, tokenAddress, chainId}
- add temporary Transak native-ETH retry on 5xx for chain 1
- expose new endpoints in mock-api and proxy CEX sessions to Core
- add VITE_CHECKOUT_* env vars and plumb them through the playground
Cherry-pick from origin/feat-checkout adopting the updated execution flow. Changes: - split TransactionPage into smaller cards/sections - replace Step/StepActions/TransactionDetails with ExecutionProgress + StepActionsList - swap StepTimer/TimerContent for StepStatusTimer - move ActionRow/SentToWalletRow/StepActionRow into shared components - add useRouteExecutionMessage and useClearAmountFields
- Per-instance router and Zustand stores (flow / fiat / frozen quote) so multiple checkout instances no longer share state - Drop Mesh dev-mode txHash override that faked onSuccess - Restrict published tarball via package.json "files" - i18n the checkout ErrorBoundary - Use route.id (not index) as React key in CheckoutRoutesPage - Add missing .js ESM extensions in two TransactionPage files - Mark new compositor exports @experimental
- Replace unsafe error cast in sessionClient with a runtime guard - Skip transaction-status navigation when an onramp provider is unavailable - Stabilize Transak SDK init via refs so the iframe no longer rebuilds on parent re-renders - Read filteredWallets via ref in WalletMenuContent to avoid effect loops - Gate transactionStatusSimulation fixtures behind NODE_ENV so prod bundles dead-code-eliminate them - Document why useCheckoutUserId persists across sessions (Mesh reconciliation) - Add tests for sessionClient, resolveAdapters, checkoutToWidgetConfig, and navigationRoutes - Drop unused noQuoteAvailable alert + matching i18n key; tighten checkout PageContainer gutters
- Add `./checkout` to package.json exports and tsdown entry; drop the checkout and internal composition re-exports from the main entry - Update playground to import from `@lifi/widget/checkout` - Convert wallet-management barrel to named exports - Guard Transak `onSuccess`/`close` handlers with a per-run active flag to prevent duplicate fires from the singleton emitter
- Split Mesh and Transak into @lifi/widget-provider-{mesh,transak}; opt
in via new `onRampProviders` prop.
- Promote shared types, contexts, and session client to
@lifi/widget-provider/checkout subpath.
- Unify i18n under `checkout.onramp.*` with {{providerName}}.
- Replace per-provider contexts with OnRampSessionsContext; hosts
register via useRegisterOnRampSession and render as flat siblings
- Route by fundingCategory ('cash' | 'exchange') instead of provider id
- Drop OnRampFlowOutlet; status page reads useActiveOnRampDeposit
- OnRampHostedModals iterates registered metas
Per-instance store via useRef matches existing checkout stores. Consumers subscribe to a single session slot, so cross-provider updates no longer re-render unrelated consumers.
- Move onRampProviders from CheckoutConfig to CheckoutProps; it's a runtime value and was never read back from config. - Type checkoutNavigationRoutesValues as CheckoutNavigationRoute[].
- on-ramp providers now get the route's fromToken/fromChainId instead of the widget destination, fixing Mesh rejections for non-CEX assets - dev-only mocks: mockDepositAddress, simulateTransferReceipt, simulatePendingDuration; status page walks watching → pending → done - CEX deposit token list curated to USDC/USDT/ETH, no chain select, balances hidden - transfer-flow failure screen renders refund-in-progress copy
- QR page polls until the deposit lands, then hands off to the status
page; adaptive backoff (5s → 15s → 30s) + shared react-query key
across the handoff to dedupe requests.
- Respect integrator-supplied toChain/toToken
fe5c6d3 to
e60c1c1
Compare
Resolves SDK version drift post-rebase; drops the IntentSubstatus workaround.
Changes: - Replace viewDetails secondary CTA with inline tx-details link - Wire contactSupport handler across failed/disconnect/onramp branches - Replace history.back with deterministic enterAmount navigation - Add vitest cases for resolveStatusVariant table
- URL params + bottom-right panel drive every variant in resolveStatusVariant - Refund/retrying substatuses now render via CheckoutStatusScreen (the hardcoded StatusCompleted/StatusExecuting templates masked them) - ToneIcon: double-circle for error, single-halo for other tones per Figma - Drop back button on progress, transfer-deposit, transaction-execution
- Request-refund CTAs (amount-low / excess-held) navigate to /deposit-error/refunding instead of closing the modal - Replace `—` placeholders with realistic amounts/time so pages preview coherently from the dev simulation panel
- raw BigInt mesh balance comparison - memoize transfer-receipt sim to stop effect thrash - dedicated success-partial variant for DONE+PARTIAL - gate walletDisconnected variant on isWallet - narrow deposit effect deps, split status-screen handler bags - typed SimPreset union, pickCopy table for on-ramp copy
Match the regular widget — one `sdkConfig.apiUrl` drives both the SDK and checkout session endpoints, resolved by `CheckoutSdkBridge`.
- `useIsWalletFundedFlow` hides wallet UI on non-wallet flows; cash defaults from-token to USDC. - Transak host: strip useId colons, try/catch SDK init, scoped ErrorBoundary, drop auto-close. - Status page: pass depositAddress+fromChain; gate dev sim on modal open->close; scrub sim params.
- Drop forced wallet-disconnect redirect on transaction page - Reflect EnterAmount form tokens in simulated status pages - Prefill Transak fiat amount via OnrampSessionRequest.fiatAmount - Route requestRefund to status page sim, drop DepositRefundingPage - Rename status "view details" CTA to "View transfer details" - Refresh refund pending copy + add sentTo / sentToWallet strings
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Which Linear task is linked to this PR?
This PR delivers Checkout V1 across the Architecture and three flow parents.
See EMB-360 Checkout V1 project for the full structure.
Architecture (parent: EMB-362)
LifiWidgetCheckoutcomponent@lifi/widget-provider-*)Pay from wallet (parent: EMB-363)
Transfer crypto (parent: EMB-364)
Mesh CEX (parent: EMB-365)
userIdgenerationTransak cash (parent: EMB-366)
Why was it implemented this way?
Checkout V1 is structurally different from the existing swap flow — it's a deposit/funding journey with three entry paths (pay from wallet, transfer crypto, on-ramp via Mesh/Transak) that converge on a single execution step against a frozen quote. The implementation choices:
@lifi/widget/checkoutsubpath export — keeps the standard widget bundle clean of checkout code for partners who don't need it. Marked@experimentaluntil the API stabilizes.@lifi/widget-provider-{mesh,transak}) — partners opt in by installing only what they need; zero bundle cost otherwise. Routing is byfundingCategory('cash'|'exchange'), not by provider id, so a future third provider in the same category doesn't require core changes.useFrozenQuoteso the in-flight amount can't shift mid-transaction.useCheckoutTransactionStatuspolls deposit status; no backend webhook infrastructure required for V1.TransactionPageintoExecutionProgress+StepActionsList+ shared row components. Affects the main widget too, not just checkout; flagged for review attention.Visual showcase
TODO: screenshots / Loom of the three flows (pay from wallet, transfer crypto, Mesh, Transak).
Notes for review
@lifi/widget(no/checkout) has zero on-ramp provider transitive deps, and that installing only one of@lifi/widget-provider-{mesh,transak}doesn't ship the other — are open. Bundle analysis to follow.ExecutionProgress/StepActionsList) touches the main widget execution flow, not just checkout. Worth eyes from anyone owning the main swap journey.aa9e9e6— flagged as temporary; remove once Core handles it natively.sessionClient,resolveAdapters,checkoutToWidgetConfig, andnavigationRoutes.Checklist before requesting a review