Repository navigation
feat(sdk): validate an address against its destination chain, starting with Zcash - #492
Merged
chybisov merged 24 commits intoOct 6, 2026
Merged
Conversation
🦋 Changeset detectedLatest commit: b7870f6 The changes in this PR will be included in the next version bump. This PR includes changesets to release 8 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
|
📦 Preview published under the Install the exact version(s) — npm i @lifi/sdk-provider-bitcoin@0.0.0-preview-267433d4
npm i @lifi/sdk-provider-ethereum@0.0.0-preview-267433d4
npm i @lifi/sdk-provider-solana@0.0.0-preview-267433d4
npm i @lifi/sdk-provider-stellar@0.0.0-preview-267433d4
npm i @lifi/sdk-provider-sui@0.0.0-preview-267433d4
npm i @lifi/sdk-provider-tron@0.0.0-preview-267433d4
npm i @lifi/sdk@0.0.0-preview-267433d4 |
2 of 3 tasks
Contributor
|
📦 Preview published under the Install the exact version(s) — npm i @lifi/sdk-provider-bitcoin@0.0.0-preview-dd8065ff
npm i @lifi/sdk-provider-ethereum@0.0.0-preview-dd8065ff
npm i @lifi/sdk-provider-solana@0.0.0-preview-dd8065ff
npm i @lifi/sdk-provider-stellar@0.0.0-preview-dd8065ff
npm i @lifi/sdk-provider-sui@0.0.0-preview-dd8065ff
npm i @lifi/sdk-provider-tron@0.0.0-preview-dd8065ff
npm i @lifi/sdk@0.0.0-preview-dd8065ff |
chybisov
force-pushed
the
feature/jumemb-113-zcash-add-support-on-widgetsdk
branch
from
September 30, 2026 12:08
dd8065f to
fbb46fa
Compare
… builds bs58check exports only a default, which the CommonJS build resolved to the whole exports object, so isAddress(t1, ChainId.ZEC) threw for CommonJS users. @scure/base and @noble/hashes ship named exports for both builds.
The @lifi/sdk minor bump already re-releases the Ethereum provider.
chybisov
force-pushed
the
feature/jumemb-113-zcash-add-support-on-widgetsdk
branch
from
October 5, 2026 11:58
1d9fdb4 to
1b774ee
Compare
Contributor
|
📦 Preview published under the Install the exact version(s) — npm i @lifi/sdk-provider-bitcoin@0.0.0-preview-1b774eec
npm i @lifi/sdk-provider-ethereum@0.0.0-preview-1b774eec
npm i @lifi/sdk-provider-solana@0.0.0-preview-1b774eec
npm i @lifi/sdk-provider-stellar@0.0.0-preview-1b774eec
npm i @lifi/sdk-provider-sui@0.0.0-preview-1b774eec
npm i @lifi/sdk-provider-tron@0.0.0-preview-1b774eec
npm i @lifi/sdk-provider-zcash@0.0.0-preview-1b774eec
npm i @lifi/sdk@0.0.0-preview-1b774eec |
Contributor
|
📦 Preview published under the Install the exact version(s) — npm i @lifi/sdk-provider-bitcoin@0.0.0-preview-b7870f68
npm i @lifi/sdk-provider-ethereum@0.0.0-preview-b7870f68
npm i @lifi/sdk-provider-solana@0.0.0-preview-b7870f68
npm i @lifi/sdk-provider-stellar@0.0.0-preview-b7870f68
npm i @lifi/sdk-provider-sui@0.0.0-preview-b7870f68
npm i @lifi/sdk-provider-tron@0.0.0-preview-b7870f68
npm i @lifi/sdk-provider-zcash@0.0.0-preview-b7870f68
npm i @lifi/sdk@0.0.0-preview-b7870f68 |
melianessa
approved these changes
Oct 6, 2026
Merged
2 of 3 tasks
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 1 of 2, the SDK half of Zcash as a destination-only chain. The widget half (lifinance/widget#884) consumes these packages, so it waits for this release.
What was wrong
ZEC (
ChainId.ZEC) carrieschainType: UTXO, which Bitcoin already owns, and the SDK held one provider per chain type. So:BitcoinProvider.isAddressis bigmi'sisUTXOAddress. It rejects every Zcash address and accepts Bitcoin addresses, so a Zcash receiver cannot be validated and nothing can tell a Bitcoin address from a Zcash one.setProviderskeyed its map byprovider.type, so a second UTXO provider replacedBitcoinProvider.getBitcoinBalancealways reads Bitcoin (ChainId.BTCis hard-coded) and copies that amount onto whatever tokens it is given, so a Bitcoin wallet asked for a ZEC balance reports its BTC balance as ZEC.What changed
@lifi/sdk(minor, additive)SDKProvider.isAddress(address, chainId?)takes an optional chain ID. Without it, every provider answers exactly as before.SDKProvider.chainIds?declares the chains a provider serves. A provider without it serves every chain of its type that no other provider lists.findProvider(providers, chainType, chainId?)(new export) holds that rule: the provider that lists the chain, otherwise the provider of the type that lists no chains.client.getProvider(type, chainId?)uses it;getProvider(type)still returns the generic provider, sogetProvider(ChainType.UTXO)is stillBitcoinProvider.setProvidersreplaces a provider only when both its type and itschainIdsmatch, sosetProviders([BitcoinProvider()])keeps a registered Zcash provider.@lifi/sdk-provider-zcash(new package)ZcashProvider()—type: UTXO,chainIds: [ChainId.ZEC], no options.isAddressaccepts what the API pays:t1(P2PKH) ort3(P2SH) — after a Base58Check decode with checksum and a 2-byte version check (0x1CB8/0x1CBD);u1, lowercase) that carries an Orchard receiver: Bech32m (prefixu), the inverse F4Jumble (ZIP 316, personalized BLAKE2b), the 16-byte padding, then a receiver list of P2PKH, P2SH, Sapling and Orchard receivers only, each at its fixed length, in ascending typecode order, with at most one transparent receiver.getBalanceleaves every amount unknown,resolveAddressresolves nothing, andgetStepExecutorthrows "ZEC is a destination-only chain."@lifi/sdk-provider-bitcoin(minor)isAddress: no chain orChainId.BTC→ bigmi, as before; any other UTXO chain, ZEC included, →false.getBitcoinBalancegives the Bitcoin balance and block number to BTC tokens only. Other tokens come back with no amount, and a list without a BTC token asks no node.isBitcoinProvideralso requiressetOptions, so it no longer matches another UTXO provider such asZcashProvider.@lifi/sdk-provider-ethereumisAddresswraps viem in a one-argument function, so a chain ID never reaches viem'soptionsparameter. No behaviour change, so no changeset; the@lifi/sdkminor bump re-releases it.Why was it implemented this way?
chainIds, not a registry keyed by chain. Every existing and third-party provider declares onlytype; they keep their meaning with no change.getProviderand the widget both usefindProvider, so the two cannot drift apart.providers.find((p) => p.type === ChainType.UTXO)returning Bitcoin.network:isUTXOAddress(bitcoinAddress, ChainId.BTC)returnsfalsefor a valid address. viem's isoptions. With the new signature,tscreports TS2322 for both bare aliases, so both providers now wrap them.@scure/basewith@noble/hashes1.x. Both have named exports that work in the CommonJS and ESM builds (@noble/hashes2.x is ESM-only).bitcoinjs-lib'sfromBase58Checkexpects a 1-byte version, and Zcash uses 2. No maintained TypeScript Zcash client exists that would replace these few lines.getaddressbalance.Alternatives considered:
BitcoinProvider.isAddress. It worked for address checks, but couples two chains that share nothing else.sdk-provider-bitcoin. No core change, but it couples the Bitcoin and Zcash packages and adds an indirection layer.Compatibility
getProvider(type),setProvidersand execution behave as before.providers.find((p) => p.type === ChainType.UTXO)filterreturns both.isBitcoinProvider(p)trueonly for a UTXO provider withsetOptions.Release note
@lifi/sdk-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 preview or the release can publish it.Visual showcase (Screenshots or Videos)
Not applicable — no UI.
Tests
findProvider.unit.spec.ts: a listed chain wins; an unlisted chain and a missing chain ID fall back to the generic provider; the list order does not matter; no match givesundefined.createClient.unit.spec.ts: a chain-specific provider sits beside the generic one;setProvidersreplaces only the provider with the same chains, in any order, and an empty chain list stays apart from the generic provider;getProviderwith and without a chain ID.ZcashProvider.unit.spec.tsandzcashAddress.unit.spec.ts: official vectors — ZIP 320 (t1, and its TEX form), ZIP 214 (t3),zcash-test-vectors(unified and Sapling) — plus an Orchard unified address from Zashi, a corrupted checksum, testnet forms, Bitcoin and EVM addresses; other chain IDs refused; unknown balances; no step executor.unifiedAddress.unit.spec.ts: the inverse F4Jumble against the officialf4jumble.jsonrows, and all 60 rows ofunified_address.json— accepted exactly when a row has an Orchard receiver and no unknown typecode — plus a corrupted checksum, the uppercase form, a testnet (utest) address, Sapling, TEX, truncated and non-address input. The vectors live in a*.mock.tsfile, so they ship neither indistnor in the tarball.BitcoinProvider: without a chain and withChainId.BTCthe answers are unchanged; ZEC, LTC, BCH and DGE refuse everything;isBitcoinProviderrefuses another UTXO provider.isAddress(a, chainId)equalsisAddress(a)on their own chains.getBitcoinBalance.unit.spec.ts: non-BTC lists make no RPC call; mixed lists in both orders give the balance to BTC only.getBitcoinBalance.int.spec.ts: its only case asked the Bitcoin balance action for USDC and USDT on Polygon, and passed onmainonly because the BTC balance was relabelled as theirs. It now reads BTC on Bitcoin.@lifi/sdk-provider-zcashboth accept at1and an Orchardu1address and refuse a Bitcoin address. Au1check costs about 30 µs; other input is unchanged at about 5 µs.pnpm test:unit,pnpm check,pnpm check:types,pnpm check:circular-depsandpnpm knip:checkall exit 0./code-reviewrounds until no code finding remained. The rounds fixed thesetProvidersscope key (a generic provider keys by its bare type, a chain-specific one by type plus sorted chain IDs) and restoredgetBitcoinBalanceto set noamountwhen the balance request fails.Checklist before requesting a review
@lifi/sdk-provider-zcashpackage andSDKProvider.chainIdsneed a docs page after the release.