Node.js Scripts
Examples for server-side scripts, automation, and backend services.
Setup
bash
npm install @zkprivacy/sdk viem wsBasic Script
typescript
// scripts/check-balance.ts
import {
PrivacyClient,
createProver,
setGlobalProver,
DEPLOYMENTS,
} from '@zkprivacy/sdk';
import { readFileSync } from 'fs';
import { formatEther } from 'viem';
import WebSocket from 'ws';
// Required: WebSocket polyfill for Node.js
(globalThis as any).WebSocket = WebSocket;
async function main() {
// Load prover from local circuit files
const prover = await createProver({
transferCircuit: JSON.parse(
readFileSync('circuits/transfer.json', 'utf-8')
),
unshieldCircuit: JSON.parse(
readFileSync('circuits/unshield.json', 'utf-8')
),
});
setGlobalProver(prover);
// Create client
const client = new PrivacyClient({
rpcUrl: DEPLOYMENTS.remote.rpcUrl,
poolAddress: DEPLOYMENTS.remote.pool,
quickSyncUrl: DEPLOYMENTS.remote.quickSyncUrl,
});
// Connect with spending key from environment
await client.connect({
mode: 'standalone',
spendingKey: BigInt(process.env.SPENDING_KEY!),
});
// Sync and show balance
await client.sync();
console.log('Address:', client.getAddress());
console.log('Balance:', formatEther(client.getBalance()), 'ETH');
// Show all token balances
const balances = client.getAllBalances();
for (const [tokenId, balance] of balances) {
console.log(`Token ${tokenId}: ${balance}`);
}
client.disconnect();
}
main().catch(console.error);Run with:
bash
SPENDING_KEY=0x... npx tsx scripts/check-balance.tsAutomated Transfer Script
typescript
// scripts/scheduled-transfer.ts
import {
PrivacyClient,
createProver,
setGlobalProver,
DEPLOYMENTS,
} from '@zkprivacy/sdk';
import { readFileSync } from 'fs';
import { parseEther, createPublicClient, http } from 'viem';
import WebSocket from 'ws';
(globalThis as any).WebSocket = WebSocket;
interface TransferJob {
recipient: string;
amount: string;
}
async function executeTransfers(jobs: TransferJob[]) {
// Initialize
const prover = await createProver({
transferCircuit: JSON.parse(readFileSync('circuits/transfer.json', 'utf-8')),
unshieldCircuit: JSON.parse(readFileSync('circuits/unshield.json', 'utf-8')),
});
setGlobalProver(prover);
const client = new PrivacyClient({
rpcUrl: DEPLOYMENTS.remote.rpcUrl,
poolAddress: DEPLOYMENTS.remote.pool,
});
const publicClient = createPublicClient({
transport: http(DEPLOYMENTS.remote.rpcUrl),
});
await client.connect({
mode: 'standalone',
spendingKey: BigInt(process.env.SPENDING_KEY!),
});
await client.sync();
console.log('Starting balance:', client.getBalance());
// Execute each transfer
for (const job of jobs) {
console.log(`Transferring ${job.amount} to ${job.recipient.slice(0, 20)}...`);
try {
const txHash = await client.transfer({
recipient: job.recipient,
amount: parseEther(job.amount),
});
console.log('TX submitted:', txHash);
// Wait for confirmation
await publicClient.waitForTransactionReceipt({ hash: txHash });
console.log('Confirmed!');
// Sync after each transfer
await client.sync();
} catch (error) {
console.error('Transfer failed:', error);
}
}
console.log('Final balance:', client.getBalance());
client.disconnect();
}
// Example jobs
const jobs: TransferJob[] = [
{ recipient: 'zks1abc...', amount: '10' },
{ recipient: 'zks1def...', amount: '20' },
];
executeTransfers(jobs);Deposit Service
Backend service that shields tokens on behalf of users:
typescript
// services/deposit-service.ts
import express from 'express';
import {
shieldTo,
DEPLOYMENTS,
encryptNoteForRecipient,
EMT_ABI,
} from '@zkprivacy/sdk';
import {
createWalletClient,
createPublicClient,
http,
parseUnits,
} from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { foundry } from 'viem/chains';
const app = express();
app.use(express.json());
// Service wallet (holds tokens to distribute)
const account = privateKeyToAccount(process.env.SERVICE_KEY as `0x${string}`);
const walletClient = createWalletClient({
account,
chain: foundry,
transport: http(DEPLOYMENTS.remote.rpcUrl),
});
const publicClient = createPublicClient({
chain: foundry,
transport: http(DEPLOYMENTS.remote.rpcUrl),
});
app.post('/deposit', async (req, res) => {
const { recipient, amount, token } = req.body;
if (!recipient || !amount) {
return res.status(400).json({ error: 'Missing recipient or amount' });
}
try {
const tokenAddress = DEPLOYMENTS.remote.tokens[token as keyof typeof DEPLOYMENTS.remote.tokens];
if (!tokenAddress) {
return res.status(400).json({ error: 'Invalid token' });
}
// Shield tokens to recipient
const result = await shieldTo(
{
rpcUrl: DEPLOYMENTS.remote.rpcUrl,
poolAddress: DEPLOYMENTS.remote.pool,
},
{
recipient,
amount,
tokenAddress,
walletClient,
}
);
// Wait for confirmation
await publicClient.waitForTransactionReceipt({ hash: result.txHash });
res.json({
success: true,
txHash: result.txHash,
commitment: result.commitment.toString(),
});
} catch (error) {
console.error('Deposit failed:', error);
res.status(500).json({ error: 'Deposit failed' });
}
});
app.listen(3000, () => {
console.log('Deposit service running on :3000');
});Environment Variables
bash
# .env
SPENDING_KEY=0x... # For automated scripts
SERVICE_KEY=0x... # For deposit serviceRunning with TSX
bash
# Direct execution
npx tsx scripts/check-balance.ts
# With env file
npx tsx --env-file=.env scripts/scheduled-transfer.ts
# Watch mode (for development)
npx tsx watch scripts/my-script.ts