Skip to content

Zcash Integration

SIP Protocol integrates Zcash technology for privacy-preserving cross-chain transactions. This guide covers setup, usage, and best practices.

SIP leverages Zcash in three key ways:

FeatureDescriptionStatus
Zcash RPC ClientFull shielded transaction supportImplemented
Viewing KeysSelective disclosure inspired by ZcashImplemented
Proof CompositionHalo2 proofs + Mina verificationPlanned
Terminal window
npm install @sip-protocol/sdk
import { ZcashRPCClient, createZcashClient } from '@sip-protocol/sdk'
// Create client
const zcash = createZcashClient({
host: '127.0.0.1',
port: 8232,
username: process.env.ZCASH_RPC_USER,
password: process.env.ZCASH_RPC_PASS
})
// Check connection
const info = await zcash.getBlockchainInfo()
console.log('Zcash network:', info.chain)

The ZcashRPCClient provides full access to Zcash’s shielded infrastructure.

interface ZcashConfig {
host?: string // Node host (default from ZCASH_RPC_HOST)
port?: number // RPC port (default: 8232; testnet: 18232)
username: string // RPC authentication user
password: string // RPC authentication password
testnet?: boolean // Use testnet defaults (default: false)
timeout?: number // Request timeout (ms, default: 30000)
retries?: number // Retry attempts on network error (default: 3)
retryDelay?: number // Base retry delay in ms (default: 1000)
}

Zcash uses HD (Hierarchical Deterministic) accounts for address generation:

// Create a new HD account
const { account } = await zcash.createAccount()
console.log('Account index:', account)
// Generate unified address for the account
const { address } = await zcash.getAddressForAccount(
account,
['sapling', 'orchard'] // Receiver types
)
console.log('Unified address:', address)

For high-level shielded operations, use ZcashShieldedService — it manages the account, balances, sends, and incoming notes on top of the RPC client.

import { createZcashShieldedService } from '@sip-protocol/sdk'
const service = createZcashShieldedService({
rpcConfig: {
host: '127.0.0.1',
port: 8232,
username: process.env.ZCASH_RPC_USER,
password: process.env.ZCASH_RPC_PASS
}
})
await service.initialize() // creates/loads the account + default address
// Get shielded balance (confirmed total + per-pool breakdown, in ZEC)
const balance = await service.getBalance()
console.log('Shielded balance:', balance.confirmed, 'ZEC')
// Send a shielded transaction (returns a txid once the operation completes)
const result = await service.sendShielded({
to: recipientZAddress,
amount: 1.5, // Amount in ZEC
memo: 'Private payment' // Optional encrypted memo (max 512 bytes)
})
console.log('Transaction ID:', result.txid)
// List incoming shielded notes (received transactions)
const received = await service.getReceivedNotes()

Zcash Unified Addresses combine multiple receiver types in a single address:

// Generate address with all receiver types
const { address } = await zcash.getAddressForAccount(
account,
['orchard', 'sapling', 'p2pkh'] // Shielded + transparent
)
// Address format: u1...
// Contains:
// - Orchard receiver (latest shielded pool)
// - Sapling receiver (widely supported)
// - Transparent receiver (for compatibility)

SIP’s viewing key system is inspired by Zcash’s design, enabling selective disclosure for compliance.

TypeSee IncomingSee OutgoingSpend
Full Viewing KeyYesYesNo
Incoming Viewing KeyYesNoNo
Outgoing Viewing KeyNoYesNo
import { generateViewingKey } from '@sip-protocol/sdk'
// Generate a viewing key (optional BIP32-style derivation path, default 'm/0')
const vk = generateViewingKey('m/0')
// vk.key can be shared with auditors; vk.hash identifies the key
// (and is stored on-chain for verification).
console.log('Share with auditor:', vk.key)
console.log('On-chain hash:', vk.hash)

In compliant mode you supply the viewing key — the SDK stores only its hash on-chain (viewingKeyHash). Hold the key itself to encrypt disclosable details for auditors, and share it so they can decrypt.

import {
SIP,
PrivacyLevel,
generateViewingKey,
encryptForViewing,
decryptWithViewing,
} from '@sip-protocol/sdk'
const sip = new SIP({ network: 'mainnet' })
// Generate the viewing key the auditor will receive.
const vk = generateViewingKey('m/0')
// Create a compliant intent, supplying the viewing key.
const intent = await sip.createIntent({
input: {
asset: { chain: 'ethereum', symbol: 'ETH', address: null, decimals: 18 },
amount,
},
output: {
asset: { chain: 'solana', symbol: 'SOL', address: null, decimals: 9 },
minAmount: 0n,
maxSlippage: 0.01,
},
privacy: PrivacyLevel.COMPLIANT,
viewingKey: vk.key,
})
console.log('On-chain viewing key hash:', intent.viewingKeyHash)
// Encrypt the disclosable transaction details for the auditor.
const encrypted = encryptForViewing(
{ sender: '0x...', recipient: '...', amount: amount.toString(), timestamp: Date.now() },
vk,
)
// The auditor (holding vk) decrypts and verifies the details.
const details = decryptWithViewing(encrypted, vk)
console.log('Disclosed amount:', details.amount)

SIP privacy levels map to Zcash concepts:

SIP LevelZcash EquivalentDescription
TRANSPARENTt-addressPublic, on-chain visible
SHIELDEDz-addressFull privacy, hidden amounts
COMPLIANTz-address + viewing keyPrivacy with audit capability
import { PrivacyLevel } from '@sip-protocol/sdk'
// Transparent (public) - like Zcash t-address
await sip.intent()
.privacy(PrivacyLevel.TRANSPARENT)
.build()
// Shielded (private) - like Zcash z-address
await sip.intent()
.privacy(PrivacyLevel.SHIELDED)
.build()
// Compliant (private + auditable) - z-address with viewing key
await sip.intent()
.privacy(PrivacyLevel.COMPLIANT)
.build()

You can route swaps to ZEC so the shielded pool itself provides privacy on the destination side. Configure the Zcash RPC client separately — SIPConfig has no zcashConfig field.

import { SIP, PrivacyLevel, createZcashClient } from '@sip-protocol/sdk'
// Zcash RPC is configured separately from the SIP client.
const zcash = createZcashClient({
host: '127.0.0.1',
port: 8232,
username: process.env.ZCASH_RPC_USER,
password: process.env.ZCASH_RPC_PASS
})
// Production mode is required for real NEAR Intents swaps (mainnet only).
const sip = new SIP({
network: 'mainnet',
mode: 'production',
intentsAdapter: { jwtToken: process.env.NEAR_INTENTS_JWT }
})
// Swap ETH → ZEC. Zcash output uses a transparent (direct) recipient z-address;
// pass it as the transparentRecipient argument to getQuotes().
const params = {
input: {
asset: { chain: 'ethereum', symbol: 'ETH', address: null, decimals: 18 },
amount: ethAmount,
},
output: {
asset: { chain: 'zcash', symbol: 'ZEC', address: null, decimals: 8 },
minAmount: 0n,
maxSlippage: 0.01,
},
privacy: PrivacyLevel.TRANSPARENT,
}
const quotes = await sip.getQuotes(params, undefined, senderEthAddress, zAddress)

SIP’s roadmap includes composing proofs from multiple systems:

┌─────────────────────────────────────────────────────────────┐
│ PROOF COMPOSITION (Phase 3) │
├─────────────────────────────────────────────────────────────┤
│ Zcash (Halo2) → Privacy execution │
│ Mina (Kimchi) → Succinct verification │
│ Noir → Validity proofs │
│ │
│ Combined: Maximum privacy + minimal verification cost │
└─────────────────────────────────────────────────────────────┘
FeatureBenefit
No trusted setupEliminates ceremony risk
Recursive proofsProof aggregation
IPA commitmentsSmaller proof sizes
import { ZcashRPCError } from '@sip-protocol/sdk'
try {
const operationId = await zcash.sendShielded(params)
} catch (error) {
if (error instanceof ZcashRPCError) {
console.error('Zcash RPC error:', error.code, error.message)
// Common error codes
if (error.code === -6) {
console.error('Insufficient funds')
} else if (error.code === -28) {
console.error('Node is still syncing')
}
}
}
OperationTimeNotes
Create account<100msHD derivation
Generate address<100msAddress encoding
Send shielded2-40sProof generation
Verify proof~10msFast verification

Try the live app at app.sip-protocol.org to see SIP privacy features in action.