Repository navigation
feat(widget): make ZEC a destination-only chain and check receivers per destination chain - #884
Merged
chybisov merged 52 commits intoOct 7, 2026
Merged
Conversation
🦋 Changeset detectedLatest commit: 75824f2 The changes in this PR will be included in the next version bump. This PR includes changesets to release 32 packages
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 |
Contributor
✅ E2E Dev Smoke — passing
4 passed · 0 failed · 0 skipped · 21s |
Contributor
E2E Playground resultsDetails
📥 Download full HTML report (open the run → Artifacts → |
Contributor
E2E Examples — all passedAll examples passed in the latest run. |
Merged
2 of 3 tasks
chybisov
force-pushed
the
feature/jumemb-113-zcash-add-support-on-widgetsdk
branch
from
October 7, 2026 10:48
b6c676a to
acf07f7
Compare
chybisov
marked this pull request as ready for review
October 7, 2026 11:05
Contributor
📦 Bundle size✅ No significant changes. Every check is within budget. @lifi/widget
@lifi/wallet-management
@lifi/widget-light
Providers
Full integration
How to read this
|
…hain useAccount falls back to an account of another ecosystem when none matches the source chain, and that account never proves the source signer cannot receive at the destination.
…olved config WidgetProvider adds every destination-only chain to chains.from.deny once, so the existing allow/deny filters keep ZEC out of the source chain list, the source token list, the opposite-chain sync in useTokenSelect and the from-side chain order, instead of a special case in each.
The config memo runs on every parent render, so a fresh chains object each time re-ran the chain-order effect and refiltered every token list.
…k makes redundant A signer that is valid on its own source chain proves the shared provider exists, so the extra provider check can never change the answer.
…never reaches Checkout allows EVM chains only, so ZEC can never be its destination.
…enies as a source
…ved config FormStore and ChainOrderStore both read the config fromChain, so dropping it where the config is resolved gives both the same answer.
Found in a follow-up review: - useTokenBalance reads no balance on a destination-only chain. No provider can read one, and a balance without a block number was retried until the backoff gave up, then again on every refetch (the refuel check with a ZEC receiver started it). - useRoutes quotes as if disconnected while the signer would be taken as the receiver: with no receiver the API delivers to the signer when both chains share a chain type, so BTC -> ZEC with a connected Bitcoin wallet found no route until a receiver was set. - useTokenSelect resets a receiver the new destination cannot take when a token pick moves the destination chain, as the chain select does.
Start the package at 4.0.0-0, so the pending minor changeset releases it as 4.0.0 in line with the other providers instead of 0.1.0. A base of 4.0.0 would not work: every widget-provider bump also patch-bumps this package, which would release 4.0.1.
Replace the SDK preview pins with the released versions: @lifi/sdk 4.11.0, @lifi/sdk-provider-zcash 4.0.0, @lifi/sdk-provider-bitcoin 4.1.0 and the other providers' matching patch releases.
chybisov
force-pushed
the
feature/jumemb-113-zcash-add-support-on-widgetsdk
branch
from
October 7, 2026 13:00
8a744dc to
ef5329c
Compare
Every budget is the measured size plus 20% again, measured on this branch on top of the SDK 4.11 bump, and a check covers the Zcash provider, which the full integration check also imports. Without it the report flags @lifi/widget-provider-zcash as a published package with no size check.
chybisov
force-pushed
the
feature/jumemb-113-zcash-add-support-on-widgetsdk
branch
from
October 7, 2026 13:01
ef5329c to
75824f2
Compare
Merged
3 tasks done
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?
JUMEMB-113 — part 2 of 2, the widget half of Zcash as a destination-only chain.
SDK and rebase: rebased onto
main(#896, no merge commits).mainalready uses@lifi/sdk4.11.0 with its matching providers and bigmi 0.10.5 / 0.9.3; this PR adds@lifi/sdk-provider-zcash^4.0.0, released from lifinance/sdk#492 through lifinance/sdk#508.pnpm why @lifi/sdk→ 1 version. Upgrade the@lifi/widget-provider-*packages together with@lifi/widget: an older Bitcoin provider hands the chain ID to bigmi as anetworkand rejects every Bitcoin receiver.Bundle size budgets:
main(#896) already raised the Sui budget for SDK 4.11. This PR resets every budget to the size measured on this branch plus 20%, rounded up to a whole kB (LiFiWidget 322 kB, Solana 39 kB, Bitcoin 107 kB, Tron 877 kB, Stellar 213 kB, full integration 2292 kB; the rest are unchanged), and adds a check for the Zcash provider (6.6 kB, budget 8 kB), which the full integration check now also imports. Without it the report flags@lifi/widget-provider-zcashas a published package with no size check.What was wrong
ZEC carries
chainType: UTXO, like Bitcoin, and every receiver check in the widget compared chain types only. Once the API lists ZEC:fromAddressas the ZEC receiver.useRoutesgated the quote ongetChainTypeFromAddress(toAddress) === toChain.chainType, so a valid Zcash receiver never produced a quote.fromChainfrom the config or the URL, and the reverse and swap buttons could move it to the source side.What changed
New package
@lifi/widget-provider-zcashZcashProvider(config?)fills a newZcashContextwith the SDK'sZcashProvider(from@lifi/sdk-provider-zcash). No wallets, no connectors;config.sdkProvideroverrides the SDK provider.providers, so render the componentZcashProvider()returns around the widget, next to the other ecosystem providers.@lifi/widget-provideruseAddressForChain()→isAddressForChain(address, chain)finds the provider with the SDK'sfindProvider(the one that lists the chain inchainIds, otherwise the provider of its chain type) and asksisAddress(address, chain.id). Every call site that knows the destination uses it instead of comparing chain types:useRoutes,useToAddressRequirements(plusisValidReceiverfor the list pages),useToAddressReset,useToAddressAutoPopulate,useAccountsBalancesData,useGasRefuel, the send-to-wallet pages and checkout's recipient hooks.useSDKProviders()list, which places Zcash right after Bitcoin, and keep the explicit detection order between ecosystems.getChainFromAddress), so a Zcash address entered with any destination is recognised as ZEC.ZcashContext,useZcashContext, and theAddressChain,ChainRefandIsAddressForChaintypes.@lifi/widgetSDKProviderInitializerre-provides the widget config with every destination-only chain that no provider lists denied (withServedDestinationChains) and with such a presettoChain/toTokendropped (withoutUnservedToChain); the URLtoChainis dropped the same way. WithoutZcashProvider(), ZEC appears in no chain list, no token list and no preset.WidgetProviderresolves the integrator config throughwithDestinationOnlyChains, which adds ZEC tochains.from.deny, and drops a destination-onlyfromChain/fromToken. The widget's existing allow/deny filters then keep ZEC out of the source chain list, the source token list, the opposite-chain sync and the from-side chain order with no special case. The URLfromChainis dropped the same way, and the reverse and cards-layout swap buttons hide when the destination is not allowed as a source (isDestinationAllowedAsSource) — for ZEC and for any chain an integrator denies as a source.useAddressValidationtakeschain(strict: the route's receiver) or no chain (bookmarks keep accepting any ecosystem). Existing messages are unchanged; an unrecognised ZEC receiver gets a new message naming the accepted formats (t1/t3, oru1with an Orchard receiver) and the refused ones (Saplingzs1, TEX) under a plain key, so every locale falls back to English until translated.ZcashProvideraccepts a unifiedu1address that carries an Orchard receiver — exactly what the API pays since EXBE-597 (NEAR Intents pays it to a shielded balance) — so the widget takes it with no other change: detection, the receiver checks, bookmarks and the Zcash icon all go through the provider. The address inputs now take up to 512 characters (addressInputMaxLength): a payable unified address has at most 213, and the longest official test vector 509.chainIdits provider reports, so a Zcash bookmark shows the Zcash icon wherever it was saved. Existing bookmarks need no migration.fromAddress=bc1…, "recipient is not valid"; 1 route without it).useRoutesnow quotes as if disconnected (quoteFromAddress) while the signer would be taken as the receiver (isSignerInvalidReceiver); once a receiver is set it quotes with the signer again.useTokenBalancereads no balance on a destination-only chain. No provider can read one, and a balance without a block number was retried until the backoff gave up, then again on every refetch; the refuel check started this with a ZEC receiver.t1receiver no longer stays after a switch from ZEC to BTC. Its own patch changeset, since it applies to every chain.@lifi/sdk@4.8.1the SDK entrypoint exportsnameandversion, which madeexport type * from '@lifi/sdk'ambiguous with the widget's own (TS2308). The widget now exports itsnameandversionexplicitly — same public API.ZcashProvider(), and the playground e2e workflows also run forpackages/widget-provider-zcash.Why was it implemented this way?
chainTypefor validity any more.findProvider, so the two cannot drift apart.Alternatives considered:
@lifi/widget-provider. Zero integrator work, but an opt-in package matches the other ecosystems and gives PMT-55 a home.Compatibility
ZcashProvider()sees no change, and no ZEC.isAddress, so upgrade the@lifi/widget-provider-*packages together with@lifi/widget: an older@lifi/widget-provider-bitcoinrefuses every Bitcoin receiver.@lifi/widget-embedded(widget-light) does not registerZcashProvider()yet, so widget-light shows no ZEC.Release note
@lifi/widget-provider-zcashis a new npm package. npm trusted publishing cannot publish a package that does not exist yet, so an npm org owner must publish its first version by hand and register.github/workflows/publish.yamlas its trusted publisher before the release.The package starts at
4.0.0-0, so its minor changeset releases it as4.0.0, in line with the other providers (a base of4.0.0would become4.0.1, because every@lifi/widget-providerbump also patch-bumps it). Publish the manual bootstrap as0.0.0, as was done for@lifi/sdk-provider-zcash, so it cannot collide with the4.0.0release; deprecate0.0.0afterwards.Visual showcase (Screenshots or Videos)
Checks 1–8 ran before li.quest listed ZEC, in the playground against a local proxy that adds a ZEC chain and token:
bc1…("Wallet address doesn't match the selected destination chain Zcash") and, before unified support, a truncatedu1…address; it acceptst1…; the receiver shows the Zcash icon.t1bookmark saved while BTC is the destination keeps the Zcash icon and is disabled as a BTC receiver./v1/chainsrequest at start-up.ZcashProvider()removed from the config, ZEC appears in no chain list and no "to" token list.Unified receivers, checked headless (Playwright) in the playground against the same proxy and the SDK preview
0.0.0-preview-b7870f68, with ZEC as the destination:u1…(106 characters) is accepted.u1…(213 characters) fits the address input in full and is accepted.u1…without an Orchard receiver is refused with the Zcash message.Checks 9–12 ran headless (Playwright) against li.quest before the rebase, which now lists ZEC and returns a NEAR route for USDC → ZEC. They were repeated with the released SDK: 9, 11 and 12 pass again; in 10 the route requests carried the receivers, but li.quest answered HTTP 429 (its keyless rate limit), so no route came back in that run:
t1, Orchard-onlyu1and transparent + Sapling + Orchardu1receivers are accepted, au1without Orchard gets the Zcash message, andbc1…is refused as the wrong chain.t1oru1receiver, and the API returns a route.fromChain=20000000000005link is ignored; the "from" network and token searches find nothing on Zcash, the "to" searches do.t1receiver, picking BTC on Bitcoin from "All networks" on the "to" side resets the receiver.Not changed here: a
toAddresslink is still validated without the destination chain, sotoAddress=bc1…with ZEC as the destination is kept as the receiver and the quote waits — the same as any ecosystem mismatch before this PR.Tests
chainTypeFromAddress(provider list, detection order,chainFromAddress,isAddressForChainwith and without a Zcash provider),useAddressForChain,useChainTypeFromAddress,ZcashProvider(the new package),useAddressValidation(strict and chainless modes and their messages),useToAddressRequirements(BTC → ZEC, a fallback account of another ecosystem, no source chain, EVM → EVM, EVM → SVM, STL → STL),useToAddressReset,canQuoteWithToAddress,isSignerInvalidReceiver,useTokenBalance(no read on ZEC),useTokenSelect(receiver reset),useToAddressAutoPopulate,useAccountsBalancesData,useChains,filterAllowedTokens,getDefaultValuesFromQueryString,withDestinationOnlyChains,withServedDestinationChains,withoutUnservedToChain,isUnservedDestinationChain,isDestinationAllowedAsSource, checkout'suseDefaultWalletRecipientanduseResolvedCheckoutRecipient.pnpm build,pnpm check,pnpm check:types,pnpm check:circular-deps,pnpm knip:checkandpnpm testall exit 0./code-reviewrounds after the provider split (five before it) until no code finding remained.Checklist before requesting a review
@lifi/widget-provider-zcash,ZcashProvider()and the@lifi/widget-providerexports need docs after the release.