Skip to content

Conversation

@mrtommyit
Copy link
Contributor

@mrtommyit mrtommyit commented Oct 8, 2025

DONE

  • connect Ledger Zcash App
  • get zcash address
  • build tx (psbt, inputs) for zcash

TODO

  • hw-app-btc uses sha256 encoding for tx hash but zcash is using blake2 unlike other utxo chains like BTC, DOGE, LTC
  • signing tx is successful but signed tx is rejected by nodes with missing inputs error.

Summary by CodeRabbit

  • New Features

    • Added Zcash Ledger wallet support including address derivation, balance retrieval, and transfers (with optional memo) and fee-rate handling.
    • UTXO results now include raw transaction data alongside existing fields.
  • Tests

    • Introduced end-to-end tests for Zcash Ledger flows.
    • Updated Zcash client test to use the first address index.
  • Chores

    • Updated package metadata and release notes.
    • Adjusted internal resolutions to improve compatibility.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 8, 2025

📝 Walkthrough

Walkthrough

Introduces a Ledger-backed Zcash client with PSBT building/signing, adds Zcash e2e tests (including Ledger), updates Zcash dependencies and module declarations, adjusts root resolutions, and modifies the NowNodes UTXO provider to fetch raw transactions per UTXO (adding txHex). Includes a changeset entry and small e2e test index change.

Changes

Cohort / File(s) Summary
UTXO provider: NowNodes UTXO enrichment
`packages/xchain-utxo-providers/src/providers/nownodes/nownodes-data-provider.ts`
mapUTXOs now fetches each raw tx from NowNodes, returning UTXOs with txHex, hash, index, value; switched from flatMap to sequential async loop.
Zcash Ledger client implementation
`packages/xchain-zcash/src/clientLedger.ts`
Implements Ledger transport/app integration, address derivation, PSBT construction for ZEC, coin selection, memo/fee handling, Ledger signing and broadcast; adds/changes public types and method signatures.
Zcash tests (e2e)
`packages/xchain-zcash/e2e/client.e2e.ts`, `packages/xchain-zcash/e2e/clientLedger.e2e.ts`
Adjusts address index usage/logging in existing test; adds new Ledger e2e covering address retrieval, sync method rejection, balance fetch, and transfer (memo test skipped).
Zcash package configuration
`packages/xchain-zcash/package.json`, `packages/xchain-zcash/src/modules.d.ts`
Replaces/augments deps: adds @bitgo/utxo-lib, @ledgerhq/hw-app-btc, @ledgerhq/hw-transport, coinselect; declares module for 'coinselect/accumulative.js'.
Repository metadata
`.changeset/silver-pets-tickle.md`
Adds changeset: minor bumps for utxo-providers and zcash; notes “add zcash ledger client”.
Root resolutions
`package.json`
Adds resolution for tiny-secp256k1 ^2.2.4 alongside existing elliptic.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • import fixes #1480 — Also adds/uses coinselect accumulative module and related typings, overlapping with the new coinselect dependency and declaration.

Suggested reviewers

  • Thorian1te
  • Naq302
  • hippocampus-web3

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly indicates the introduction of Zcash Ledger functionality, directly reflecting the main change of the pull request and providing clear context for reviewers without unnecessary detail.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7785727 and 7ac563a.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (3)
  • .changeset/silver-pets-tickle.md (1 hunks)
  • package.json (1 hunks)
  • packages/xchain-zcash/package.json (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .changeset/silver-pets-tickle.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/xchain-zcash/package.json
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (1)
package.json (1)

47-47: Confirm v2 ESM compatibility before pinning.

tiny-secp256k1@^2.2.4 is ESM-only; forcing it via resolutions will make every consumer (e.g. bitcoinjs-lib, Ledger helpers) load the ESM build. If any of those still require() the CommonJS entry, we’ll hit ERR_REQUIRE_ESM at runtime. Please rerun the affected packages/tests (and ideally the Ledger e2e flow) to make sure the upgrade is safe or add the necessary code changes to handle the ESM module shape.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🧹 Nitpick comments (6)
packages/xchain-zcash/__e2e__/client.e2e.ts (1)

14-44: Consider adding assertions for test reliability.

While these e2e tests currently execute operations successfully, they lack assertions (expect() statements) to validate correctness. This means tests will pass even if operations return incorrect or unexpected values.

Consider adding assertions to each test. For example:

 it('Should get address', async () => {
   const address = await client.getAddressAsync(0)
   console.log('address', address)
+  expect(address).toBeTruthy()
+  expect(typeof address).toBe('string')
 })
 it('Should get balance', async () => {
   const address = await client.getAddressAsync(0)
   const balance = await client.getBalance(address)
   console.log('Balance', balance[0].amount.amount().toString())
   console.log(balance[0].asset)
+  expect(balance).toBeDefined()
+  expect(Array.isArray(balance)).toBe(true)
 })
 it('Should transfer TX without memo', async () => {
   const address = await client.getAddressAsync(1)
   const hash = await client.transfer({
     walletIndex: 0,
     amount: assetToBase(assetAmount('0.1', 8)),
     recipient: address,
   })
   console.log('hash', hash)
+  expect(hash).toBeTruthy()
+  expect(typeof hash).toBe('string')
 })
packages/xchain-zcash/package.json (1)

47-47: Verify coinselect version.

The specified version 3.1.12 is from April 2020. Based on learnings, the latest published version is 3.1.13 (June 2022). Consider updating to the latest patch version for potential bug fixes.

Apply this diff to update to the latest version:

-    "coinselect": "3.1.12",
+    "coinselect": "3.1.13",

Based on learnings.

packages/xchain-zcash/__e2e__/clientLedger.e2e.ts (2)

9-16: Add cleanup in afterAll hook.

The Ledger transport is created in beforeAll but never explicitly closed. This could leave the device connection open between test runs.

Add an afterAll hook to properly close the transport:

afterAll(async () => {
  await client.transport.close()
})

20-20: Consider removing console.log statements.

The test contains several console.log statements that should be removed or replaced with a proper test logger for cleaner test output in CI/CD environments.

Also applies to: 32-33, 47-47, 60-60

packages/xchain-zcash/src/ledger-btc.js (1)

1-24: Document rationale for including legacy Ledger code.

This file contains legacy Ledger toolkit code from 2016-2019. Consider:

  1. Documenting why this legacy code is needed instead of using modern @ledgerhq/hw-app-btc APIs directly (which is already a dependency).
  2. Adding a README or comment explaining the relationship between this file and the hw-app-btc package.
  3. Evaluating whether the modern hw-app-btc API can replace this legacy implementation to reduce maintenance burden.

Would you like me to investigate whether modern @ledgerhq/hw-app-btc APIs (version 10.11.2 in your dependencies) can replace this legacy implementation?

packages/xchain-zcash/src/clientLedger.ts (1)

124-126: Remove redundant skip logic

The if (hasOutputScript && !compiledMemo) { continue } branch is unreachable—script outputs are only ever added when compiledMemo is truthy. Remove these lines.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 11a8634 and 1f2826b.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (7)
  • packages/xchain-utxo-providers/src/providers/nownodes/nownodes-data-provider.ts (1 hunks)
  • packages/xchain-zcash/__e2e__/client.e2e.ts (1 hunks)
  • packages/xchain-zcash/__e2e__/clientLedger.e2e.ts (1 hunks)
  • packages/xchain-zcash/package.json (1 hunks)
  • packages/xchain-zcash/src/clientLedger.ts (1 hunks)
  • packages/xchain-zcash/src/ledger-btc.js (1 hunks)
  • packages/xchain-zcash/src/modules.d.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/xchain-zcash/src/clientLedger.ts (3)
packages/xchain-util/src/asset.ts (1)
  • Address (18-18)
packages/xchain-client/src/types.ts (1)
  • TxHash (63-63)
packages/xchain-client/src/feeRates.ts (1)
  • checkFeeBounds (35-39)
packages/xchain-zcash/__e2e__/clientLedger.e2e.ts (1)
packages/xchain-util/src/asset.ts (1)
  • assetToBase (146-152)
🪛 Biome (2.1.2)
packages/xchain-zcash/src/ledger-btc.js

[error] 704-704: Shouldn't redeclare 'buffer'. Consider to delete it or rename it.

'buffer' is defined here:

(lint/suspicious/noRedeclare)


[error] 710-710: Shouldn't redeclare 'buffer'. Consider to delete it or rename it.

'buffer' is defined here:

(lint/suspicious/noRedeclare)


[error] 724-724: Shouldn't redeclare 'transaction'. Consider to delete it or rename it.

'transaction' is defined here:

(lint/suspicious/noRedeclare)


[error] 724-724: This variable is used before its declaration.

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


[error] 745-745: Shouldn't redeclare 'i'. Consider to delete it or rename it.

'i' is defined here:

(lint/suspicious/noRedeclare)


[error] 813-813: Shouldn't redeclare 'i'. Consider to delete it or rename it.

'i' is defined here:

(lint/suspicious/noRedeclare)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (17)
packages/xchain-zcash/__e2e__/client.e2e.ts (1)

15-16: LGTM! More intuitive test setup.

Changing the index from 1 to 0 makes this test more intuitive as a basic address retrieval test, and aligns it with the "get balance" test on line 20 which also uses index 0.

packages/xchain-zcash/src/modules.d.ts (1)

1-2: LGTM!

The module augmentation for coinselect/accumulative.js is correctly declared, enabling TypeScript support for the untyped JavaScript module used in the Ledger client implementation.

packages/xchain-zcash/__e2e__/clientLedger.e2e.ts (2)

40-50: LGTM!

The transfer test correctly validates transaction creation and broadcasting without a memo. The use of real amounts (0.1 ZEC) is appropriate for end-to-end testing.


52-63: Skipped test aligns with PR objectives.

The memo test is appropriately skipped, consistent with the PR description indicating that memo functionality is part of the "Remaining / TODO" work. Consider adding a TODO comment explaining the skip reason.

You can optionally add a clarifying comment:

// TODO: Enable once memo support is fully implemented (see PR objectives)
it.skip('Should transfer TX with memo', async () => {
packages/xchain-zcash/src/clientLedger.ts (13)

1-10: LGTM!

The imports are well-organized and include all necessary types and functions for the Ledger-based Zcash client implementation.


14-14: LGTM!

The UtxoLedgerClientParams type correctly extends UtxoClientParams with the required Ledger transport, maintaining a clean API surface.


16-23: LGTM!

The constructor properly stores the Ledger transport, and the lazy initialization pattern for ledgerApp is appropriate for managing the Ledger connection lifecycle.


25-33: LGTM!

The lazy initialization pattern for the Ledger app is correctly implemented, with proper currency configuration for Zcash.


35-45: LGTM!

The address retrieval methods correctly handle the Ledger's asynchronous nature. The synchronous method appropriately throws an error, and the async method properly derives the address using the legacy format suitable for Zcash.


67-86: LGTM!

The UTXO selection logic using coinselect is correctly implemented, with proper handling of the recipient output and optional memo script.


88-103: LGTM!

The PSBT initialization correctly sets up Zcash-specific parameters including the NU5 consensus branch ID and version 455, which are appropriate for Zcash transaction construction.


135-140: LGTM!

The buildTx method correctly returns all necessary components (PSBT, UTXOs, and inputs) for the subsequent signing process.


148-159: LGTM!

The transfer initialization correctly retrieves the Ledger app, validates fee bounds, and derives the sender address from the wallet index.


176-197: LGTM!

The Ledger signing flow correctly handles Zcash-specific parameters including non-segwit mode, expiry height, and the 'zcash' additional parameter.


63-63: Verify spendPendingUTXO handling

The Keystore and Ledger clients both hard-code scanUTXOs(..., true) instead of exposing the spendPendingUTXO option that the core Client does. Decide whether Ledger/Keystore should surface this flag; if not, update comments to remove the misleading reference.


164-174: Verify Zcash hash encoding
Confirm that @ledgerhq/hw-app-btc@^10.11.2 actually uses BLAKE2 (not SHA-256) when signing Zcash transactions; if it doesn’t, track and implement the missing BLAKE2 hashing before considering this complete.


108-118: Ensure txHex is provided for non-witness UTXOs or handle missing cases
The UTXO type makes txHex optional; if you call addInput with nonWitnessUtxo: undefined, PSBT construction will fail silently. Confirm that your provider always sets txHex when witnessUtxo is absent, or add a guard to throw an error/fallback when utxo.txHex is undefined.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/xchain-zcash/src/clientLedger.ts (2)

121-123: Clarify the output script filtering logic.

This logic skips outputs with a script but no compiled memo. Since coinselect shouldn't generate script outputs (only address-based outputs or change), this condition seems unusual. If the intent is to filter out OP_RETURN outputs that aren't memos, the logic should be more explicit.

Consider adding a comment explaining when this condition would be true, or simplify the logic if this case cannot occur:

-    if (hasOutputScript && !compiledMemo) {
+    // Skip non-memo script outputs (if any)
+    if (hasOutputScript && !compiledMemo) {
       continue
     }

172-173: Clarify expiryHeight = 0 usage (packages/xchain-zcash/src/clientLedger.ts:172). Zcash allows 0 (no-expiry per ZIP-203) but UX best practice is default TTL (current height+40). Confirm this intent or switch to the default.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1f2826b and 7785727.

📒 Files selected for processing (1)
  • packages/xchain-zcash/src/clientLedger.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/xchain-zcash/src/clientLedger.ts (5)
packages/xchain-zcash/src/index.ts (1)
  • ClientLedger (5-5)
packages/xchain-zcash/src/client.ts (1)
  • Client (202-202)
packages/xchain-util/src/asset.ts (1)
  • Address (18-18)
packages/xchain-client/src/types.ts (1)
  • TxHash (63-63)
packages/xchain-client/src/feeRates.ts (1)
  • checkFeeBounds (35-39)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (1)
packages/xchain-zcash/src/clientLedger.ts (1)

10-10: Ignore suggestion to use Mayaprotocol for UTXO selection. @mayaprotocol/zcash-js only exports high-level builders (buildTx, signAndFinalize, etc.) and doesn’t expose a standalone coin-selection API, so the direct use of coinselect/accumulative.js remains necessary here.

Likely an incorrect or invalid review comment.

mrtommyit and others added 8 commits October 9, 2025 10:15
* feat: add tron ledger client

* chore: add changeset
* updated decimal cache and added Mayanode-first pool caching with Midgard fallback

* add changeset

* fix broken test

* update from CR comments
* update chainflip sdk to the latest and add broker config

* update

* added changeset
* feat: add maya ledger client

* feat: add ledger-thorchain npm

* chore: fix swap e2e test address
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@Thorian1te
Copy link
Collaborator

Add changeset pls.
Security vulnerability in tiny-secp256k1 version 1.1.6 is causing the snyk check to fail.

@mrtommyit
Copy link
Contributor Author

Add changeset pls. Security vulnerability in tiny-secp256k1 version 1.1.6 is causing the snyk check to fail.

  • Fixed tiny-secp256k1 version
  • Added changeset

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.

3 participants