@ledgerhq/zcash-utils 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,25 @@
1
+ # @ledgerhq/zcash-utils
2
+
3
+ ## 0.1.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Rework npm package README to document the Node.js NAPI API instead of the Rust workspace. Move workspace/development documentation to CONTRIBUTING.md.
8
+
9
+ ## 0.1.1
10
+
11
+ ### Patch Changes
12
+
13
+ - Expose `TransactionStream.cancel()` to abort a background scan immediately. Buffered transactions already sent by Rust remain consumable via `next()`.
14
+
15
+ ## 0.1.0
16
+
17
+ ### Initial Release
18
+
19
+ First public release of the Node.js (NAPI) addon for Zcash shielded transaction scanning.
20
+
21
+ - `startSync(params)` — scans a compact block range for shielded transactions using trial decryption entirely in Rust
22
+ - `getChainTip(grpcUrl)` — queries current chain tip height from a gRPC endpoint
23
+ - `TransactionStream` — async iterator over matched and fully-decrypted shielded transactions (`next()`, `stats()`)
24
+ - Pre-built `.node` binaries for macOS (arm64, x64), Linux (x64, arm64), and Windows (x64, arm64)
25
+ - Orchard-only mode (`orchardOnly: true`) for Ledger wallets
package/README.md CHANGED
@@ -1,128 +1,126 @@
1
1
  # @ledgerhq/zcash-utils
2
2
 
3
- Rust workspace for Zcash cryptographic operations. Provides key derivation,
4
- shielded transaction decryption, and compact block scanning across multiple
5
- runtime targets.
3
+ Native Node.js (NAPI) addon for Zcash shielded transaction scanning — built in Rust via [napi-rs](https://napi.rs).
6
4
 
7
- ## Build targets
8
-
9
- | Target | Script | Output |
10
- | --------------------- | ------------------------------ | --------------------------------------- |
11
- | Node.js / Electron | `./scripts/build-napi.sh` | `index.*.node` |
12
- | macOS CLI (universal) | `./scripts/build-cli-macos.sh` | `dist/ledger-zcash-cli-macos-universal` |
13
- | Linux CLI (static) | `./scripts/build-cli-linux.sh` | `dist/ledger-zcash-cli-linux-x86_64` |
14
-
15
- See [`docs/build-targets.md`](docs/build-targets.md) for prerequisites and details.
16
-
17
- ## Crate structure
5
+ ## Installation
18
6
 
7
+ ```sh
8
+ npm install @ledgerhq/zcash-utils
9
+ # or
10
+ pnpm add @ledgerhq/zcash-utils
19
11
  ```
20
- zcash-crypto Pure cryptographic logic (key derivation, trial/full decryption)
21
- zcash-sync Async sync engine (lightwalletd / Zaino)
22
- zcash-ffi-node Node.js / Electron native addon (napi-rs)
23
- zcash-cli CLI binary (ledger-zcash-cli)
24
- ```
25
-
26
- See [`docs/architecture.md`](docs/architecture.md) for the dependency graph and
27
- design decisions.
28
12
 
29
- ## CLI usage
13
+ ## Quick start
30
14
 
31
- ```bash
32
- # Key derivation
33
- ledger-zcash-cli derive --mnemonic "abandon abandon ... about" --format json
15
+ ```typescript
16
+ import { startSync, getChainTip } from "@ledgerhq/zcash-utils";
34
17
 
35
- # Query chain tip
36
- ledger-zcash-cli tip --grpc-url https://zaino-zec-testnet.nodes.stg.ledger-test.com/
18
+ const tip = await getChainTip(
19
+ "https://zaino-zec-testnet.nodes.stg.ledger-test.com/",
20
+ );
37
21
 
38
- # Scan a block range
39
- ledger-zcash-cli sync \
40
- --grpc-url https://zaino-zec-testnet.nodes.stg.ledger-test.com/ \
41
- --viewing-key uviewtest1... \
42
- --start-height 280000 \
43
- --end-height 285000 \
44
- --network testnet \
45
- --format json
46
- ```
22
+ const stream = await startSync({
23
+ grpcUrl: "https://zaino-zec-testnet.nodes.stg.ledger-test.com/",
24
+ viewingKey: "uviewtest1...",
25
+ startHeight: tip - 1000,
26
+ endHeight: tip,
27
+ network: "testnet",
28
+ orchardOnly: true,
29
+ });
47
30
 
48
- ### `derive` options
31
+ let tx;
32
+ while ((tx = await stream.next()) !== null) {
33
+ console.log(tx.txid, tx.orchardNotes);
34
+ }
49
35
 
36
+ const stats = await stream.stats();
37
+ console.log(`Scanned ${stats.blocksScanned} blocks in ${stats.elapsedMs}ms`);
50
38
  ```
51
- --mnemonic <WORDS> BIP-39 mnemonic (reads from stdin if omitted)
52
- --account <N> ZIP-32 account index [default: 0]
53
- --xpub-path <PATH> BIP-32 xpub path [default: m/44'/133'/{account}']
54
- --network mainnet|testnet [default: mainnet]
55
- --no-sapling Exclude Sapling FVK from UFVK
56
- --format human|json [default: human]
57
- ```
58
-
59
- ## Development
60
-
61
- ```bash
62
- # Run all logic tests
63
- cargo test --package zcash-crypto
64
39
 
65
- # Run CLI integration tests
66
- cargo test --package zcash-cli
67
-
68
- # Coverage (requires cargo install cargo-llvm-cov)
69
- ./scripts/coverage.sh
70
-
71
- # Type-check everything
72
- cargo check --workspace
40
+ ## API
41
+
42
+ ### `startSync(params: SyncParams): Promise<TransactionStream>`
43
+
44
+ Starts scanning a range of compact blocks and returns a transaction stream. The scan runs in the background immediately in Rust — no JS event loop blocking. `GetTransaction` is called only for matched transactions.
45
+
46
+ ### `getChainTip(grpcUrl: string): Promise<number>`
47
+
48
+ Returns the current chain tip height from the gRPC endpoint.
49
+
50
+ ### `TransactionStream`
51
+
52
+ Async iterator over matched shielded transactions.
53
+
54
+ | Method | Description |
55
+ | ---------------------------------------------- | ------------------------------------------------------------------------------------------------- |
56
+ | `next(): Promise<ShieldedTransaction \| null>` | Returns the next matched transaction, or `null` when the scan is complete. |
57
+ | `cancel(): void` | Cancels the background scan immediately. Buffered transactions are still consumable via `next()`. |
58
+ | `stats(): Promise<SyncStats>` | Returns scan statistics once the stream is exhausted. |
59
+
60
+ ## Types
61
+
62
+ ### `SyncParams`
63
+
64
+ ```typescript
65
+ interface SyncParams {
66
+ /** gRPC endpoint URL */
67
+ grpcUrl: string;
68
+ /** Unified Full Viewing Key (UFVK) for the account to scan */
69
+ viewingKey: string;
70
+ /** First block height to scan (inclusive) */
71
+ startHeight: number;
72
+ /** Last block height to scan (inclusive) */
73
+ endHeight: number;
74
+ /** "mainnet" or "testnet" (default: "testnet") */
75
+ network?: string;
76
+ /**
77
+ * When true, only Orchard actions are processed — eliminates all Sapling
78
+ * crypto work. Set to true for Ledger wallets (Orchard-only support).
79
+ */
80
+ orchardOnly?: boolean;
81
+ /**
82
+ * Maximum retry attempts per range on transient errors.
83
+ * The failing range is split in half on each retry. Defaults to 3.
84
+ */
85
+ maxRetries?: number;
86
+ /** Emit per-phase timing diagnostics to stderr every 10 seconds */
87
+ verbose?: boolean;
88
+ }
73
89
  ```
74
90
 
75
- ## Documentation
76
-
77
- - [`docs/architecture.md`](docs/architecture.md) — workspace design
78
- - [`docs/key-derivation.md`](docs/key-derivation.md) — BIP-39 → UFVK pipeline
79
- - [`docs/block-sync.md`](docs/block-sync.md) — gRPC trial + full decryption
80
- - [`docs/ffi-node.md`](docs/ffi-node.md) — Node.js/Electron integration
81
- - [`docs/build-targets.md`](docs/build-targets.md) — build scripts reference
82
-
83
- ## Release
84
-
85
- Versioning is managed with [Changesets](https://github.com/changesets/action). Every merge to `main` triggers the CI workflow, which:
86
-
87
- 1. Builds all artifacts in parallel on their respective platforms
88
- 2. Either opens/updates a **"Version Packages"** PR if changesets are pending
89
- 3. Or publishes immediately if the "Version Packages" PR has already been merged
90
-
91
- ### Publishing a new version
92
-
93
- ```bash
94
- # 1. Describe the change (patch / minor / major)
95
- pnpm changeset
96
-
97
- # 2. Commit the generated .changeset file and push
98
- git add .changeset/
99
- git commit -m "chore: add changeset"
100
- git push
101
-
102
- # 3. Merge the PR → CI automatically opens a "Version Packages" PR
103
- # 4. Merge the "Version Packages" PR → CI publishes
91
+ ### `ShieldedTransaction`
92
+
93
+ ```typescript
94
+ interface ShieldedTransaction {
95
+ txid: string; // Transaction ID (big-endian hex)
96
+ hex: string; // Raw transaction bytes (hex)
97
+ blockHeight: number;
98
+ blockHash: string; // Block hash (big-endian hex)
99
+ blockTime: number; // Unix timestamp (seconds)
100
+ fee: number; // Fee in zatoshis
101
+ saplingNotes: ShieldedNote[];
102
+ orchardNotes: ShieldedNote[];
103
+ }
104
104
  ```
105
105
 
106
- ### Artifacts produced per release
107
-
108
- | Artifact | Distribution | Platforms |
109
- | ---------------------------------- | ------------------ | --------------------------- |
110
- | `@ledgerhq/zcash-utils` | Ledger JFrog (npm) | All (bundled `.node` files) |
111
- | `ledger-zcash-cli-macos-universal` | GitHub Release | macOS arm64 + x64 |
112
- | `ledger-zcash-cli-linux-x86_64` | GitHub Release | Linux x64 (static musl) |
113
-
114
- The `.node` binaries are built in a CI matrix for each OS/architecture target, collected in the publish job, and included in the npm package via the `files` field. The `index.js` NAPI-RS loader looks for a local `.node` file first, then falls back to a separate `@ledgerhq/zcash-utils-{platform}` package if needed.
106
+ ### `ShieldedNote`
115
107
 
116
- The npm package is published to the internal Ledger JFrog Artifactory registry. The CI authenticates via OIDC (`LedgerHQ/actions-security/actions/jfrog-login`) and configures `.npmrc` to route `@ledgerhq` scoped packages to the Artifactory URL.
117
-
118
- CLI binaries are attached to the tagged GitHub Release (`v{version}`) and are not part of the npm package.
108
+ ```typescript
109
+ interface ShieldedNote {
110
+ amount: number; // Amount in zatoshis
111
+ transferType: string; // "incoming", "outgoing", or "internal"
112
+ memo: string;
113
+ }
114
+ ```
119
115
 
120
- ### Required secrets and variables
116
+ ### `SyncStats`
121
117
 
122
- | Secret / Variable | Purpose |
123
- | ------------------------------ | ----------------------------------------------------- |
124
- | `GITHUB_TOKEN` | Automatically provided by GitHub Actions |
125
- | `vars.ARTIFACTORY_PUBLISH_URL` | JFrog Artifactory registry URL (without `https://`) |
118
+ ```typescript
119
+ interface SyncStats {
120
+ blocksScanned: number;
121
+ elapsedMs: number;
122
+ }
123
+ ```
126
124
 
127
125
  ## License
128
126
 
package/index.d.ts CHANGED
@@ -101,6 +101,15 @@ export declare class TransactionStream {
101
101
  * This method is safe to call — it only mutates the internal channel receiver.
102
102
  */
103
103
  next(): Promise<ShieldedTransaction | null>
104
+ /**
105
+ * Cancels the background scan immediately.
106
+ *
107
+ * Aborts the tokio task running the sync engine. Any buffered transactions
108
+ * already sent by Rust are still consumable via `next()`, which will then
109
+ * return `null` once the buffer is drained. `stats()` will return an error
110
+ * after cancellation.
111
+ */
112
+ cancel(): void
104
113
  /**
105
114
  * Returns scan statistics once the stream is exhausted (i.e. after `next()`
106
115
  * returns `null`). Calling this before the stream is done will wait until
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@ledgerhq/zcash-utils",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Native Zcash key derivation and shielded sync — Node.js (NAPI)",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
7
7
  "files": [
8
8
  "index.js",
9
9
  "index.d.ts",
10
- "*.node"
10
+ "*.node",
11
+ "CHANGELOG.md"
11
12
  ],
12
13
  "repository": {
13
14
  "type": "git",