@mayaprotocol/zcash-ts v1.0.1
@mayaprotocol/zcash-ts
Low-level Zcash library for TypeScript/JavaScript, designed for integration with xchainjs-lib and other blockchain libraries.
Overview
This package provides a comprehensive set of Zcash primitives and utilities, leveraging Rust's librustzcash through NAPI bindings for optimal performance and security. It's designed as a low-level library that higher-level packages like @xchainjs/xchain-zcash can build upon.
TypeScript Support
This library includes comprehensive TypeScript declarations for all functions and types, including:
- Full type definitions for the NAPI module interface
- Typed transaction structures (
NapiPartialTx,BuiltPartialTx) - Network enums and validation
- Extended transaction data documentation
Transaction Expiry
Zcash transactions support expiry heights to prevent transactions from being included in blocks after a certain point. This library provides full control over transaction expiry:
blockHeight- The current blockchain height where the transaction is being createdexpiryHeight- The block height after which the transaction expires and cannot be mined0= Transaction never expires> blockHeight= Transaction expires at that specific block height- Default:
blockHeight + 40(standard 40-block expiry window)
// Transaction that never expires
const neverExpiresTx = buildTransaction({
inputs, outputs, network: 'mainnet',
blockHeight: 1000000,
pubkey,
expiryHeight: 0 // Never expires
})
// Transaction that expires in 100 blocks
const customExpiryTx = buildTransaction({
inputs, outputs, network: 'mainnet',
blockHeight: 1000000,
pubkey,
expiryHeight: 1000100 // Expires at block 1000100
})Installation
npm install @mayaprotocol/zcash-tsPlatform Support
This package includes pre-built native binaries for:
- Linux x64 (
zec.linux-x64-gnu.node) - macOS x64 (
zec.darwin-x64.node) - Build on macOS required - macOS ARM64 (
zec.darwin-arm64.node) - Build on macOS required - Windows x64 (
zec.win32-x64-msvc.node) - Build on Windows required
Building Native Binaries
To build the native NAPI binaries:
# Build for current platform
npm run build:native
# Build for specific platforms (requires appropriate toolchain)
npm run build:native:linux # Linux x64
npm run build:native:macos # macOS x64 (requires macOS)
npm run build:native:macos-arm # macOS ARM64 (requires macOS)
npm run build:native:windows # Windows x64 (requires Windows)
# Attempt to build for all platforms (cross-compilation limited)
npm run build:native:allNote: Cross-compilation from Linux to macOS/Windows requires additional toolchain setup and may not work for all dependencies (like secp256k1). For production builds, use platform-specific build environments.
Complete API Reference
Core Functions
Address Management
// Validate a Zcash address for a specific network
validateAddress(address: string, network: string): boolean
// Generate address from private key (WIF or hex format)
addressFromPrivateKey(privateKey: string, network: string): string
// Generate address from public key buffer
addressFromPublicKey(publicKey: Buffer, network: string): stringTransaction Building
// Build an unsigned transaction with NAPI bindings support
buildTransaction(params: {
inputs: UTXO[]
outputs: TxOutput[]
network: string
blockHeight: number
pubkey: Buffer // Required for NAPI features
expiryHeight?: number // Block height after which tx expires (0 = never expires, default = blockHeight + 40)
}): UnsignedTransaction
// Sign a transaction with provided signatures
signTransaction(
unsignedTx: UnsignedTransaction,
signatures: Buffer[],
network: string,
vaultPubkey?: Buffer
): Buffer
// Calculate transaction ID from raw transaction bytes
calculateTransactionId(transactionBytes: Buffer): stringUTXO Selection (like coinselect)
// Select UTXOs using accumulative strategy (default)
selectUTXOs(params: {
utxos: UTXO[]
targets: TxOutput[]
feeRate?: number
changeAddress: string
}): UTXOSelection | null
// Select UTXOs preferring exact matches (blackjack strategy)
selectUTXOsBlackjack(params: {
utxos: UTXO[]
targets: TxOutput[]
changeAddress: string
}): UTXOSelection | null
// Select UTXOs minimizing change (branch & bound)
selectUTXOsBnB(params: {
utxos: UTXO[]
targets: TxOutput[]
changeAddress: string
costOfChange?: number
}): UTXOSelection | nullFee Calculation
// Calculate transaction fee
calculateFee(
inputCount: number,
outputCount: number,
memoLength?: number
): number
// Estimate transaction size in bytes
estimateTransactionSize(
inputCount: number,
outputCount: number,
memoLength?: number
): numberScript Generation
// Create P2PKH script from address
createPayToAddressScript(address: string): Buffer
// Create OP_RETURN script from memo
createMemoScript(memo: string): BufferNAPI-Specific Functions
// Initialize Zcash library (required before using NAPI functions)
initZecLib(): void
// Get output viewing key from vault public key
getOutputViewingKey(vaultPubkey: Buffer): BufferTypes
// Network options
export enum Network {
Mainnet = 'mainnet',
Testnet = 'testnet',
Regtest = 'regtest'
}
// UTXO for transaction inputs
export interface UTXO {
txid: string
vout: number
value: number // zatoshis
height: number
script?: string // hex-encoded, optional for compatibility
}
// Transaction output
export interface TxOutput {
address: string
value: number // zatoshis
memo?: string // optional OP_RETURN data
}
// Unsigned transaction
export interface UnsignedTransaction {
version: number // 5 for current Zcash
inputs: UTXO[] // with required scripts
outputs: TxOutput[]
lockTime: number
sighashes: Buffer[]
}
// UTXO selection result
export interface UTXOSelection {
inputs: UTXO[] // selected inputs
outputs: TxOutput[] // includes change output if needed
fee: number // calculated fee
}
// RPC configuration
export interface Config {
host: string
port: number
username: string
password: string
network: Network | string
}NAPI Types
The library uses typed NAPI bindings for communication with the Rust backend:
// NAPI network enum (matches Rust implementation)
export enum NapiNetwork {
Main = 'Main',
Test = 'Test',
Regtest = 'Regtest'
}
// NAPI transaction structure passed to/from Rust
export interface NapiPartialTx {
height: number // Block height at which transaction is being created
txid: Buffer // 32-byte transaction ID
inputs: NapiUTXO[]
outputs: NapiOutput[]
fee: number
sighashes: Buffer[] // Sighashes for each input
expiryHeight: number // Block height after which tx expires (0 = never expires)
}
// NAPI UTXO structure
export interface NapiUTXO {
txid: string // Hex-encoded transaction ID
vout: number // Output index
value: number // Amount in zatoshis
script: string // Hex-encoded script
}
// NAPI output structure
export interface NapiOutput {
address: string
amount: number // Amount in zatoshis
memo: string // Empty string if no memo
}
// Structure returned by buildPartialTx
export interface BuiltPartialTx extends NapiPartialTx {
txid: Buffer // Populated transaction ID
sighashes: Buffer[] // Calculated sighashes for signing
fee: number // Actual fee (may differ from requested)
}Extended Transaction Data
The Rust implementation has access to additional transaction fields through TransactionData<Unauthorized>:
// Additional data available in Rust but not exposed via NAPI
export interface ExtendedTransactionData {
version: number // Full version with Overwinter flag
consensusBranchId: number // Network upgrade identifier
lockTime: number // Transaction lock time
expiryHeight: number // Block height when tx expires
transparentBundle?: {
inputs: Array<{
prevOut: { txid: string; vout: number }
scriptSig: Buffer // Full unlocking script
sequence: number // For relative lock time
}>
outputs: Array<{
value: number
scriptPubKey: Buffer // Full locking script
}>
}
// Shielded components (not used in transparent-only implementation)
saplingBundle?: any
orchardBundle?: any
}To access this extended data, the NAPI bindings would need to be modified to expose these additional fields.
Additional Utilities
RPC Client
// Full-featured Zcash RPC client
export class ZcashRPCClient {
constructor(config: Config)
// Network info
getNetworkInfo(): Promise<any>
getBlockchainInfo(): Promise<any>
// Address operations
validateAddress(address: string): Promise<any>
getBalance(address: string): Promise<string>
getUTXOs(address: string): Promise<UTXO[]>
// Transaction operations
sendRawTransaction(txHex: string): Promise<string>
getRawTransaction(txid: string, verbose?: boolean): Promise<any>
}Error Handling
// Custom error class for Zcash operations
export class ZecError extends Error {
constructor(message: string)
name: 'ZecError'
}Legacy/Compatibility Exports
For backward compatibility with existing code:
// Legacy function aliases
export const isValidAddr = validateAddress
export const skToAddr = addressFromPrivateKey
export const pkToAddr = addressFromPublicKey
export const getFee = (utxos: UTXO[], outputs: Output[]) => number
export const buildTx = (config, utxos, outputs, height) => Tx
export const signAndFinalize = (tx, privateKey, network) => Buffer
// Legacy network constants
export const Main = 'main'
export const Test = 'test'
export const Regtest = 'regtest'
// Legacy types
export type Output = OutputPKH | OutputMemo
export interface OutputPKH {
type: 'pkh'
address: string
amount: number
}
export interface OutputMemo {
type: 'memo'
memo: string
}Usage Examples
Basic Address Validation
import { validateAddress, Network } from '@mayaprotocol/zcash-ts'
const isValid = validateAddress('t1XYZ...', Network.Mainnet)
console.log('Address is valid:', isValid)Transaction Building
import {
buildTransaction,
signTransaction,
calculateTransactionId,
selectUTXOs
} from '@mayaprotocol/zcash-ts'
// Select UTXOs for transaction
const selection = selectUTXOs({
utxos: availableUTXOs,
targets: [
{ address: 'tmXYZ...', value: 100000000 }, // 1 ZEC
],
changeAddress: 'tmABC...'
})
if (!selection) throw new Error('Insufficient funds')
// Build unsigned transaction
const unsignedTx = buildTransaction({
inputs: selection.inputs,
outputs: selection.outputs,
network: 'testnet',
blockHeight: 123456,
vaultPubkey: Buffer.from('...', 'hex') // Optional, enables NAPI features
})
// Sign transaction (signatures from external signer)
const signatures = await externalSigner.sign(unsignedTx.sighashes)
const signedTx = signTransaction(unsignedTx, signatures, 'testnet')
// Get transaction ID
const txid = calculateTransactionId(signedTx)RPC Integration
import { ZcashRPCClient, Config } from '@mayaprotocol/zcash-ts'
const config: Config = {
host: 'localhost',
port: 8232,
username: 'user',
password: 'pass',
network: 'mainnet'
}
const client = new ZcashRPCClient(config)
// Get UTXOs for an address
const utxos = await client.getUTXOs('t1XYZ...')
// Broadcast transaction
const txid = await client.sendRawTransaction(signedTx.toString('hex'))Testing
# Run all tests
npm test
# Run specific test suites
npm run test src/__tests__/basic.test.ts
# Run E2E tests (requires Docker)
npm run regtest:up # Start Zcash regtest node
npm run test:e2e # Run E2E tests
npm run regtest:down # Stop regtest nodeArchitecture
This library provides three levels of functionality:
- Pure TypeScript functions - Address validation, script generation, fee calculation
- NAPI bindings - High-performance transaction building and cryptographic operations via Rust
- RPC client - Direct interaction with Zcash nodes
The library automatically falls back to mock implementations when NAPI bindings are not available, ensuring compatibility across all environments.
Platform Support
- ✅ Node.js 16+
- ✅ Linux (x64, ARM64)
- ✅ macOS (x64, ARM64)
- ✅ Windows (x64)
License
MIT