@ledgerhq/zcash-utils 0.1.0
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/README.md +129 -0
- package/index.d.ts +112 -0
- package/index.darwin-arm64.node +0 -0
- package/index.darwin-x64.node +0 -0
- package/index.js +317 -0
- package/index.linux-arm64-gnu.node +0 -0
- package/index.linux-x64-gnu.node +0 -0
- package/index.win32-arm64-msvc.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# @ledgerhq/zcash-utils
|
|
2
|
+
|
|
3
|
+
Rust workspace for Zcash cryptographic operations. Provides key derivation,
|
|
4
|
+
shielded transaction decryption, and compact block scanning across multiple
|
|
5
|
+
runtime targets.
|
|
6
|
+
|
|
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
|
|
18
|
+
|
|
19
|
+
```
|
|
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
|
+
|
|
29
|
+
## CLI usage
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Key derivation
|
|
33
|
+
ledger-zcash-cli derive --mnemonic "abandon abandon ... about" --format json
|
|
34
|
+
|
|
35
|
+
# Query chain tip
|
|
36
|
+
ledger-zcash-cli tip --grpc-url https://zaino-zec-testnet.nodes.stg.ledger-test.com/
|
|
37
|
+
|
|
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
|
+
```
|
|
47
|
+
|
|
48
|
+
### `derive` options
|
|
49
|
+
|
|
50
|
+
```
|
|
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
|
+
|
|
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
|
|
73
|
+
```
|
|
74
|
+
|
|
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
|
|
104
|
+
```
|
|
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.
|
|
115
|
+
|
|
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.
|
|
119
|
+
|
|
120
|
+
### Required secrets and variables
|
|
121
|
+
|
|
122
|
+
| Secret / Variable | Purpose |
|
|
123
|
+
| ------------------------------ | ----------------------------------------------------- |
|
|
124
|
+
| `GITHUB_TOKEN` | Automatically provided by GitHub Actions |
|
|
125
|
+
| `vars.ARTIFACTORY_PUBLISH_URL` | JFrog Artifactory registry URL (without `https://`) |
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
MIT OR Apache-2.0
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
/* auto-generated by NAPI-RS */
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Parameters for scanning a block range for shielded transactions.
|
|
8
|
+
*
|
|
9
|
+
* The UFVK must be obtained from the Ledger device — never derive it from
|
|
10
|
+
* a seed phrase directly in this layer.
|
|
11
|
+
*/
|
|
12
|
+
export interface SyncParams {
|
|
13
|
+
/** gRPC endpoint URL (e.g. `"https://zaino-zec-testnet.nodes.stg.ledger-test.com/"`). */
|
|
14
|
+
grpcUrl: string
|
|
15
|
+
/** Unified Full Viewing Key (UFVK) for the account to scan. */
|
|
16
|
+
viewingKey: string
|
|
17
|
+
/** First block height to scan (inclusive). */
|
|
18
|
+
startHeight: number
|
|
19
|
+
/** Last block height to scan (inclusive). */
|
|
20
|
+
endHeight: number
|
|
21
|
+
/** `"mainnet"` or `"testnet"` (default: `"testnet"`). */
|
|
22
|
+
network?: string
|
|
23
|
+
/**
|
|
24
|
+
* When `true`, Sapling outputs are stripped before trial decryption.
|
|
25
|
+
* Only Orchard actions are processed — eliminates all Sapling crypto work.
|
|
26
|
+
* Set to `true` for Ledger wallets (Orchard-only support).
|
|
27
|
+
*/
|
|
28
|
+
orchardOnly?: boolean
|
|
29
|
+
/**
|
|
30
|
+
* Maximum retry attempts per range on transient errors (timeout, 503).
|
|
31
|
+
* The failing range is split in half on each retry. Defaults to 3.
|
|
32
|
+
*/
|
|
33
|
+
maxRetries?: number
|
|
34
|
+
/** Emit per-phase timing diagnostics to stderr every 10 seconds. */
|
|
35
|
+
verbose?: boolean
|
|
36
|
+
}
|
|
37
|
+
/** A single shielded note found during decryption. */
|
|
38
|
+
export interface ShieldedNote {
|
|
39
|
+
/** Amount in zatoshis (f64 for JS Number compatibility). */
|
|
40
|
+
amount: number
|
|
41
|
+
/** `"incoming"`, `"outgoing"`, or `"internal"`. */
|
|
42
|
+
transferType: string
|
|
43
|
+
/** Memo text decoded from the note. */
|
|
44
|
+
memo: string
|
|
45
|
+
}
|
|
46
|
+
/** A matched and fully-decrypted shielded transaction. */
|
|
47
|
+
export interface ShieldedTransaction {
|
|
48
|
+
/** Transaction ID in big-endian (display) hex order. */
|
|
49
|
+
txid: string
|
|
50
|
+
/** Raw transaction bytes as a hex string. */
|
|
51
|
+
hex: string
|
|
52
|
+
/** Block height at which this transaction was confirmed. */
|
|
53
|
+
blockHeight: number
|
|
54
|
+
/** Block hash in big-endian (display) hex order. */
|
|
55
|
+
blockHash: string
|
|
56
|
+
/** Block timestamp (Unix seconds). */
|
|
57
|
+
blockTime: number
|
|
58
|
+
/** Transaction fee in zatoshis (shielded bundles only). */
|
|
59
|
+
fee: number
|
|
60
|
+
/** Decrypted Sapling notes belonging to this account. */
|
|
61
|
+
saplingNotes: Array<ShieldedNote>
|
|
62
|
+
/** Decrypted Orchard notes belonging to this account. */
|
|
63
|
+
orchardNotes: Array<ShieldedNote>
|
|
64
|
+
}
|
|
65
|
+
/** Scan statistics returned once the stream is exhausted. */
|
|
66
|
+
export interface SyncStats {
|
|
67
|
+
blocksScanned: number
|
|
68
|
+
elapsedMs: number
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Start scanning a range of compact blocks and return a transaction stream.
|
|
72
|
+
*
|
|
73
|
+
* The scan runs in the background immediately. Call `stream.next()` to
|
|
74
|
+
* consume transactions as they are found. Call `stream.stats()` after the
|
|
75
|
+
* stream is exhausted to retrieve scan statistics.
|
|
76
|
+
*
|
|
77
|
+
* Trial decryption runs entirely in Rust (no JS event loop blocking).
|
|
78
|
+
* `GetTransaction` is called only for matched transactions.
|
|
79
|
+
*/
|
|
80
|
+
export declare function startSync(params: SyncParams): Promise<TransactionStream>
|
|
81
|
+
/** Returns the current chain tip height from the gRPC endpoint. */
|
|
82
|
+
export declare function getChainTip(grpcUrl: string): Promise<number>
|
|
83
|
+
/**
|
|
84
|
+
* Async iterator over matched shielded transactions.
|
|
85
|
+
*
|
|
86
|
+
* Usage (TypeScript):
|
|
87
|
+
* ```ts
|
|
88
|
+
* const stream = await startSync(params);
|
|
89
|
+
* let tx: ShieldedTransaction | null;
|
|
90
|
+
* while ((tx = await stream.next()) !== null) {
|
|
91
|
+
* console.log(tx);
|
|
92
|
+
* }
|
|
93
|
+
* const stats = await stream.stats();
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export declare class TransactionStream {
|
|
97
|
+
/**
|
|
98
|
+
* Returns the next matched transaction, or `null` when the scan is complete.
|
|
99
|
+
*
|
|
100
|
+
* Safety: napi-rs requires `unsafe` for `&mut self` in async methods.
|
|
101
|
+
* This method is safe to call — it only mutates the internal channel receiver.
|
|
102
|
+
*/
|
|
103
|
+
next(): Promise<ShieldedTransaction | null>
|
|
104
|
+
/**
|
|
105
|
+
* Returns scan statistics once the stream is exhausted (i.e. after `next()`
|
|
106
|
+
* returns `null`). Calling this before the stream is done will wait until
|
|
107
|
+
* the background sync task finishes.
|
|
108
|
+
*
|
|
109
|
+
* Safety: napi-rs requires `unsafe` for `&mut self` in async methods.
|
|
110
|
+
*/
|
|
111
|
+
stats(): Promise<SyncStats>
|
|
112
|
+
}
|
|
Binary file
|
|
Binary file
|
package/index.js
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
/* prettier-ignore */
|
|
4
|
+
|
|
5
|
+
/* auto-generated by NAPI-RS */
|
|
6
|
+
|
|
7
|
+
const { existsSync, readFileSync } = require('fs')
|
|
8
|
+
const { join } = require('path')
|
|
9
|
+
|
|
10
|
+
const { platform, arch } = process
|
|
11
|
+
|
|
12
|
+
let nativeBinding = null
|
|
13
|
+
let localFileExisted = false
|
|
14
|
+
let loadError = null
|
|
15
|
+
|
|
16
|
+
function isMusl() {
|
|
17
|
+
// For Node 10
|
|
18
|
+
if (!process.report || typeof process.report.getReport !== 'function') {
|
|
19
|
+
try {
|
|
20
|
+
const lddPath = require('child_process').execSync('which ldd').toString().trim()
|
|
21
|
+
return readFileSync(lddPath, 'utf8').includes('musl')
|
|
22
|
+
} catch (e) {
|
|
23
|
+
return true
|
|
24
|
+
}
|
|
25
|
+
} else {
|
|
26
|
+
const { glibcVersionRuntime } = process.report.getReport().header
|
|
27
|
+
return !glibcVersionRuntime
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
switch (platform) {
|
|
32
|
+
case 'android':
|
|
33
|
+
switch (arch) {
|
|
34
|
+
case 'arm64':
|
|
35
|
+
localFileExisted = existsSync(join(__dirname, 'index.android-arm64.node'))
|
|
36
|
+
try {
|
|
37
|
+
if (localFileExisted) {
|
|
38
|
+
nativeBinding = require('./index.android-arm64.node')
|
|
39
|
+
} else {
|
|
40
|
+
nativeBinding = require('@ledgerhq/zcash-utils-android-arm64')
|
|
41
|
+
}
|
|
42
|
+
} catch (e) {
|
|
43
|
+
loadError = e
|
|
44
|
+
}
|
|
45
|
+
break
|
|
46
|
+
case 'arm':
|
|
47
|
+
localFileExisted = existsSync(join(__dirname, 'index.android-arm-eabi.node'))
|
|
48
|
+
try {
|
|
49
|
+
if (localFileExisted) {
|
|
50
|
+
nativeBinding = require('./index.android-arm-eabi.node')
|
|
51
|
+
} else {
|
|
52
|
+
nativeBinding = require('@ledgerhq/zcash-utils-android-arm-eabi')
|
|
53
|
+
}
|
|
54
|
+
} catch (e) {
|
|
55
|
+
loadError = e
|
|
56
|
+
}
|
|
57
|
+
break
|
|
58
|
+
default:
|
|
59
|
+
throw new Error(`Unsupported architecture on Android ${arch}`)
|
|
60
|
+
}
|
|
61
|
+
break
|
|
62
|
+
case 'win32':
|
|
63
|
+
switch (arch) {
|
|
64
|
+
case 'x64':
|
|
65
|
+
localFileExisted = existsSync(
|
|
66
|
+
join(__dirname, 'index.win32-x64-msvc.node')
|
|
67
|
+
)
|
|
68
|
+
try {
|
|
69
|
+
if (localFileExisted) {
|
|
70
|
+
nativeBinding = require('./index.win32-x64-msvc.node')
|
|
71
|
+
} else {
|
|
72
|
+
nativeBinding = require('@ledgerhq/zcash-utils-win32-x64-msvc')
|
|
73
|
+
}
|
|
74
|
+
} catch (e) {
|
|
75
|
+
loadError = e
|
|
76
|
+
}
|
|
77
|
+
break
|
|
78
|
+
case 'ia32':
|
|
79
|
+
localFileExisted = existsSync(
|
|
80
|
+
join(__dirname, 'index.win32-ia32-msvc.node')
|
|
81
|
+
)
|
|
82
|
+
try {
|
|
83
|
+
if (localFileExisted) {
|
|
84
|
+
nativeBinding = require('./index.win32-ia32-msvc.node')
|
|
85
|
+
} else {
|
|
86
|
+
nativeBinding = require('@ledgerhq/zcash-utils-win32-ia32-msvc')
|
|
87
|
+
}
|
|
88
|
+
} catch (e) {
|
|
89
|
+
loadError = e
|
|
90
|
+
}
|
|
91
|
+
break
|
|
92
|
+
case 'arm64':
|
|
93
|
+
localFileExisted = existsSync(
|
|
94
|
+
join(__dirname, 'index.win32-arm64-msvc.node')
|
|
95
|
+
)
|
|
96
|
+
try {
|
|
97
|
+
if (localFileExisted) {
|
|
98
|
+
nativeBinding = require('./index.win32-arm64-msvc.node')
|
|
99
|
+
} else {
|
|
100
|
+
nativeBinding = require('@ledgerhq/zcash-utils-win32-arm64-msvc')
|
|
101
|
+
}
|
|
102
|
+
} catch (e) {
|
|
103
|
+
loadError = e
|
|
104
|
+
}
|
|
105
|
+
break
|
|
106
|
+
default:
|
|
107
|
+
throw new Error(`Unsupported architecture on Windows: ${arch}`)
|
|
108
|
+
}
|
|
109
|
+
break
|
|
110
|
+
case 'darwin':
|
|
111
|
+
localFileExisted = existsSync(join(__dirname, 'index.darwin-universal.node'))
|
|
112
|
+
try {
|
|
113
|
+
if (localFileExisted) {
|
|
114
|
+
nativeBinding = require('./index.darwin-universal.node')
|
|
115
|
+
} else {
|
|
116
|
+
nativeBinding = require('@ledgerhq/zcash-utils-darwin-universal')
|
|
117
|
+
}
|
|
118
|
+
break
|
|
119
|
+
} catch {}
|
|
120
|
+
switch (arch) {
|
|
121
|
+
case 'x64':
|
|
122
|
+
localFileExisted = existsSync(join(__dirname, 'index.darwin-x64.node'))
|
|
123
|
+
try {
|
|
124
|
+
if (localFileExisted) {
|
|
125
|
+
nativeBinding = require('./index.darwin-x64.node')
|
|
126
|
+
} else {
|
|
127
|
+
nativeBinding = require('@ledgerhq/zcash-utils-darwin-x64')
|
|
128
|
+
}
|
|
129
|
+
} catch (e) {
|
|
130
|
+
loadError = e
|
|
131
|
+
}
|
|
132
|
+
break
|
|
133
|
+
case 'arm64':
|
|
134
|
+
localFileExisted = existsSync(
|
|
135
|
+
join(__dirname, 'index.darwin-arm64.node')
|
|
136
|
+
)
|
|
137
|
+
try {
|
|
138
|
+
if (localFileExisted) {
|
|
139
|
+
nativeBinding = require('./index.darwin-arm64.node')
|
|
140
|
+
} else {
|
|
141
|
+
nativeBinding = require('@ledgerhq/zcash-utils-darwin-arm64')
|
|
142
|
+
}
|
|
143
|
+
} catch (e) {
|
|
144
|
+
loadError = e
|
|
145
|
+
}
|
|
146
|
+
break
|
|
147
|
+
default:
|
|
148
|
+
throw new Error(`Unsupported architecture on macOS: ${arch}`)
|
|
149
|
+
}
|
|
150
|
+
break
|
|
151
|
+
case 'freebsd':
|
|
152
|
+
if (arch !== 'x64') {
|
|
153
|
+
throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
|
|
154
|
+
}
|
|
155
|
+
localFileExisted = existsSync(join(__dirname, 'index.freebsd-x64.node'))
|
|
156
|
+
try {
|
|
157
|
+
if (localFileExisted) {
|
|
158
|
+
nativeBinding = require('./index.freebsd-x64.node')
|
|
159
|
+
} else {
|
|
160
|
+
nativeBinding = require('@ledgerhq/zcash-utils-freebsd-x64')
|
|
161
|
+
}
|
|
162
|
+
} catch (e) {
|
|
163
|
+
loadError = e
|
|
164
|
+
}
|
|
165
|
+
break
|
|
166
|
+
case 'linux':
|
|
167
|
+
switch (arch) {
|
|
168
|
+
case 'x64':
|
|
169
|
+
if (isMusl()) {
|
|
170
|
+
localFileExisted = existsSync(
|
|
171
|
+
join(__dirname, 'index.linux-x64-musl.node')
|
|
172
|
+
)
|
|
173
|
+
try {
|
|
174
|
+
if (localFileExisted) {
|
|
175
|
+
nativeBinding = require('./index.linux-x64-musl.node')
|
|
176
|
+
} else {
|
|
177
|
+
nativeBinding = require('@ledgerhq/zcash-utils-linux-x64-musl')
|
|
178
|
+
}
|
|
179
|
+
} catch (e) {
|
|
180
|
+
loadError = e
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
localFileExisted = existsSync(
|
|
184
|
+
join(__dirname, 'index.linux-x64-gnu.node')
|
|
185
|
+
)
|
|
186
|
+
try {
|
|
187
|
+
if (localFileExisted) {
|
|
188
|
+
nativeBinding = require('./index.linux-x64-gnu.node')
|
|
189
|
+
} else {
|
|
190
|
+
nativeBinding = require('@ledgerhq/zcash-utils-linux-x64-gnu')
|
|
191
|
+
}
|
|
192
|
+
} catch (e) {
|
|
193
|
+
loadError = e
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
break
|
|
197
|
+
case 'arm64':
|
|
198
|
+
if (isMusl()) {
|
|
199
|
+
localFileExisted = existsSync(
|
|
200
|
+
join(__dirname, 'index.linux-arm64-musl.node')
|
|
201
|
+
)
|
|
202
|
+
try {
|
|
203
|
+
if (localFileExisted) {
|
|
204
|
+
nativeBinding = require('./index.linux-arm64-musl.node')
|
|
205
|
+
} else {
|
|
206
|
+
nativeBinding = require('@ledgerhq/zcash-utils-linux-arm64-musl')
|
|
207
|
+
}
|
|
208
|
+
} catch (e) {
|
|
209
|
+
loadError = e
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
localFileExisted = existsSync(
|
|
213
|
+
join(__dirname, 'index.linux-arm64-gnu.node')
|
|
214
|
+
)
|
|
215
|
+
try {
|
|
216
|
+
if (localFileExisted) {
|
|
217
|
+
nativeBinding = require('./index.linux-arm64-gnu.node')
|
|
218
|
+
} else {
|
|
219
|
+
nativeBinding = require('@ledgerhq/zcash-utils-linux-arm64-gnu')
|
|
220
|
+
}
|
|
221
|
+
} catch (e) {
|
|
222
|
+
loadError = e
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
break
|
|
226
|
+
case 'arm':
|
|
227
|
+
if (isMusl()) {
|
|
228
|
+
localFileExisted = existsSync(
|
|
229
|
+
join(__dirname, 'index.linux-arm-musleabihf.node')
|
|
230
|
+
)
|
|
231
|
+
try {
|
|
232
|
+
if (localFileExisted) {
|
|
233
|
+
nativeBinding = require('./index.linux-arm-musleabihf.node')
|
|
234
|
+
} else {
|
|
235
|
+
nativeBinding = require('@ledgerhq/zcash-utils-linux-arm-musleabihf')
|
|
236
|
+
}
|
|
237
|
+
} catch (e) {
|
|
238
|
+
loadError = e
|
|
239
|
+
}
|
|
240
|
+
} else {
|
|
241
|
+
localFileExisted = existsSync(
|
|
242
|
+
join(__dirname, 'index.linux-arm-gnueabihf.node')
|
|
243
|
+
)
|
|
244
|
+
try {
|
|
245
|
+
if (localFileExisted) {
|
|
246
|
+
nativeBinding = require('./index.linux-arm-gnueabihf.node')
|
|
247
|
+
} else {
|
|
248
|
+
nativeBinding = require('@ledgerhq/zcash-utils-linux-arm-gnueabihf')
|
|
249
|
+
}
|
|
250
|
+
} catch (e) {
|
|
251
|
+
loadError = e
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
break
|
|
255
|
+
case 'riscv64':
|
|
256
|
+
if (isMusl()) {
|
|
257
|
+
localFileExisted = existsSync(
|
|
258
|
+
join(__dirname, 'index.linux-riscv64-musl.node')
|
|
259
|
+
)
|
|
260
|
+
try {
|
|
261
|
+
if (localFileExisted) {
|
|
262
|
+
nativeBinding = require('./index.linux-riscv64-musl.node')
|
|
263
|
+
} else {
|
|
264
|
+
nativeBinding = require('@ledgerhq/zcash-utils-linux-riscv64-musl')
|
|
265
|
+
}
|
|
266
|
+
} catch (e) {
|
|
267
|
+
loadError = e
|
|
268
|
+
}
|
|
269
|
+
} else {
|
|
270
|
+
localFileExisted = existsSync(
|
|
271
|
+
join(__dirname, 'index.linux-riscv64-gnu.node')
|
|
272
|
+
)
|
|
273
|
+
try {
|
|
274
|
+
if (localFileExisted) {
|
|
275
|
+
nativeBinding = require('./index.linux-riscv64-gnu.node')
|
|
276
|
+
} else {
|
|
277
|
+
nativeBinding = require('@ledgerhq/zcash-utils-linux-riscv64-gnu')
|
|
278
|
+
}
|
|
279
|
+
} catch (e) {
|
|
280
|
+
loadError = e
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
break
|
|
284
|
+
case 's390x':
|
|
285
|
+
localFileExisted = existsSync(
|
|
286
|
+
join(__dirname, 'index.linux-s390x-gnu.node')
|
|
287
|
+
)
|
|
288
|
+
try {
|
|
289
|
+
if (localFileExisted) {
|
|
290
|
+
nativeBinding = require('./index.linux-s390x-gnu.node')
|
|
291
|
+
} else {
|
|
292
|
+
nativeBinding = require('@ledgerhq/zcash-utils-linux-s390x-gnu')
|
|
293
|
+
}
|
|
294
|
+
} catch (e) {
|
|
295
|
+
loadError = e
|
|
296
|
+
}
|
|
297
|
+
break
|
|
298
|
+
default:
|
|
299
|
+
throw new Error(`Unsupported architecture on Linux: ${arch}`)
|
|
300
|
+
}
|
|
301
|
+
break
|
|
302
|
+
default:
|
|
303
|
+
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (!nativeBinding) {
|
|
307
|
+
if (loadError) {
|
|
308
|
+
throw loadError
|
|
309
|
+
}
|
|
310
|
+
throw new Error(`Failed to load native binding`)
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const { TransactionStream, startSync, getChainTip } = nativeBinding
|
|
314
|
+
|
|
315
|
+
module.exports.TransactionStream = TransactionStream
|
|
316
|
+
module.exports.startSync = startSync
|
|
317
|
+
module.exports.getChainTip = getChainTip
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ledgerhq/zcash-utils",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Native Zcash key derivation and shielded sync — Node.js (NAPI)",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"index.js",
|
|
9
|
+
"index.d.ts",
|
|
10
|
+
"*.node"
|
|
11
|
+
],
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/LedgerHQ/ledger-zcash-utils.git"
|
|
15
|
+
},
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@changesets/cli": "^2.29.8",
|
|
21
|
+
"@napi-rs/cli": "^2.18.0",
|
|
22
|
+
"@types/node": "^25.5.2",
|
|
23
|
+
"tsx": "^4.21.0",
|
|
24
|
+
"typescript": "^6.0.2"
|
|
25
|
+
},
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"scripts": {
|
|
28
|
+
"// ── NAPI (Node.js / Electron) ──────────────────────────────────────": "",
|
|
29
|
+
"build": "./scripts/build-napi.sh",
|
|
30
|
+
"build:debug": "DEBUG=1 ./scripts/build-napi.sh",
|
|
31
|
+
"// ── CLI artifacts ───────────────────────────────────────────────────": "",
|
|
32
|
+
"build:cli:macos": "./scripts/build-cli-macos.sh",
|
|
33
|
+
"build:cli:linux": "./scripts/build-cli-linux.sh",
|
|
34
|
+
"// ── Rust checks & tests ────────────────────────────────────────────": "",
|
|
35
|
+
"check": "cargo check --workspace",
|
|
36
|
+
"test": "cargo test --package zcash-crypto",
|
|
37
|
+
"test:cli": "cargo test --package zcash-cli",
|
|
38
|
+
"test:all": "cargo test --workspace",
|
|
39
|
+
"// ── Coverage ───────────────────────────────────────────────────────": "",
|
|
40
|
+
"coverage": "./scripts/coverage.sh",
|
|
41
|
+
"coverage:open": "OPEN_REPORT=1 ./scripts/coverage.sh",
|
|
42
|
+
"// ── Rustdoc ────────────────────────────────────────────────────────": "",
|
|
43
|
+
"doc": "cargo doc --workspace --no-deps",
|
|
44
|
+
"doc:open": "cargo doc --workspace --no-deps --open",
|
|
45
|
+
"// ── CLI (ledger-zcash-cli) — usage: pnpm cli -- derive --mnemonic '...'": "",
|
|
46
|
+
"cli": "cargo run -q -p zcash-cli",
|
|
47
|
+
"cli:derive": "cargo run -q -p zcash-cli -- derive --help",
|
|
48
|
+
"cli:tip": "cargo run -q -p zcash-cli -- tip --help",
|
|
49
|
+
"cli:sync": "cargo run -q -p zcash-cli -- sync --help",
|
|
50
|
+
"// ── Node.js validation & benchmarks ───────────────────────────────": "",
|
|
51
|
+
"sync-tx": "tsx examples/sync-tx.node.ts --start-height 1130000 --end-height 1180000",
|
|
52
|
+
"bench": "tsx examples/bench.ts --start-height 280000 --end-height 285000"
|
|
53
|
+
}
|
|
54
|
+
}
|