@unionlabs/payments
v0.3.2
Published
TypeScript SDK for Union Private Payments - privacy-preserving transfers using zero-knowledge proofs
Keywords
Readme
Union Private Payments SDK
TypeScript SDK for privacy-preserving transfers using Union's ZK proof system.
Installation
pnpm install @unionlabs/paymentsDevelopment Notes
- Install dependencies with
pnpm i - After API changes, use
pnpm run api:extractto update the doc model. This guarantees that breaking changes are reviewed and all publicly used types are exported.
Quick Start
import { UnionPrivatePayments, generateSecret } from '@unionlabs/payments';
import { createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { base } from 'viem/chains';
// Initialize the client
const client = new UnionPrivatePayments({
proverUrl: 'https://prover.example.com',
sourceRpcUrl: 'https://eth-mainnet.example.com',
destinationRpcUrl: 'https://base-mainnet.example.com',
srcZAssetAddress: '0x...', // ZAsset on source chain
dstZAssetAddress: '0x...', // ZAsset on destination chain
sourceChainId: 1n,
destinationChainId: 8453n,
});
// Generate a secret for deposits
const secret = generateSecret();
// Create wallet client
const walletClient = createWalletClient({
account: privateKeyToAccount('0x...'),
chain: base,
transport: http('https://base-mainnet.example.com'),
});Examples
Examples live in ./examples/* and can be run as:
KEY="0xprivkey" pnpm run example ./examples/base-quick-start.tsBeneficiary Modes
When generating a deposit address, you specify 0-4 beneficiary addresses. This determines who can redeem the funds.
Bounded Mode (1-4 beneficiaries)
The deposit address is derived from secret + beneficiary addresses. Only those addresses can redeem.
Key property: Secret can be safely shared - even if leaked, funds can only go to specified addresses.
Use cases:
- Multisig verification: When paying via a Safe/multisig, signers need to verify the transaction. With bounded mode, signers can see the secret and verify the deposit address is correct without risk - funds can only go to the specified beneficiary.
- Rescue address: Specify recipient + your own address as beneficiaries. If the recipient can't redeem (lost keys, etc.), you can recover the funds.
- Receiving payments as a team: Your organization generates secret with your multisig as beneficiary. Team members can verify the deposit address is correct by checking the secret - safe to share since it's bounded to your multisig.
| Pros | Cons | |------|------| | Secret can be shared with signers | Must know recipient addresses upfront | | Enables rescue/backup addresses | Limited to 4 beneficiaries | | Multi-party verification workflows | Cannot change recipient after deposit |
Unbounded Mode (empty beneficiaries)
Any address can be specified as beneficiary at redemption time.
Key property: Secret must be kept private - anyone with the secret can redeem to any address.
Use cases:
- Personal privacy: Single user controls secret, can redeem to any address
- Address rotation: Redeem to a fresh address each time for maximum privacy
- Deferred decision: Don't need to decide recipient at deposit time
| Pros | Cons | |------|------| | Maximum flexibility | Secret must be absolutely private | | No upfront recipient decision | If secret leaks, funds can be stolen | | Can use fresh addresses | Single-party use only |
Which to Choose?
Use bounded mode when:
- Receiving payments (protects you if payer's systems are compromised)
- Multi-party scenarios (organizations, escrow)
- You know the recipient address upfront
Use unbounded mode when:
- You control the entire flow end-to-end
- You want maximum address flexibility
- You can guarantee secret security
Configuration
The UnionPrivatePayments client accepts the following configuration:
interface UnionPrivatePaymentsConfig {
proverUrl: string; // URL of the ZK prover server
sourceRpcUrl: string; // RPC URL for the source chain
destinationRpcUrl: string; // RPC URL for the destination chain
srcZAssetAddress: Address; // ZAsset contract on source chain
dstZAssetAddress: Address; // ZAsset contract on destination chain
sourceChainId: bigint; // Source chain ID
destinationChainId: bigint; // Destination chain ID
}API Reference
See docs
CLI Reference
The SDK includes a CLI accessible via pnpm dlx payments or after global install.
Configuration File
Most commands require a config file (private-payments.config.json):
{
"proverUrl": "http://localhost:8080",
"sourceRpcUrl": "https://eth-mainnet.example.com",
"destinationRpcUrl": "https://base-mainnet.example.com",
"srcZAssetAddress": "0x...",
"dstZAssetAddress": "0x...",
"sourceChainId": 1,
"destinationChainId": 8453,
"attestorUrl": "https://attestation.example.com",
"attestorApiKey": "your-api-key"
}Commands
generate
Generate a new secret and deposit address.
payments generate [options]| Option | Description |
|--------|-------------|
| --secret <hex> | Use existing 32-byte secret instead of generating |
| --beneficiaries <addresses> | Comma-separated addresses (max 4, empty = unbounded) |
| --config <path> | Config file path (default: ./private-payments.config.json) |
deposit
Wrap underlying tokens and deposit to ZAsset.
payments deposit --amount <amount> --secret <hex> [options]| Option | Description |
|--------|-------------|
| --amount <amount> | Amount in smallest units (required) |
| --secret <hex> | 32-byte secret (required) |
| --beneficiaries <addresses> | Comma-separated beneficiary addresses |
| --private-key <key> | Signing key (or SENDER_PRIVATE_KEY env) |
| --config <path> | Config file path |
balance
Query balance via light client.
payments balance --secret <hex> --client-id <id> [options]| Option | Description |
|--------|-------------|
| --secret <hex> | 32-byte secret (required) |
| --client-id <id> | Light client ID (required) |
| --beneficiaries <addresses> | Comma-separated beneficiary addresses |
| --config <path> | Config file path |
prove
Generate ZK proof for redemption.
payments prove --secret <hex> --beneficiary <addr> --amount <value> --client-ids <ids> --selected-client <id> [options]| Option | Description |
|--------|-------------|
| --secret <hex> | 32-byte secret (required) |
| --beneficiary <address> | Redeem destination (required) |
| --amount <value> | Amount to redeem in smallest units (required) |
| --client-ids <ids> | Comma-separated light client IDs for anonymity set (required) |
| --selected-client <id> | Which client ID to use for proof (required) |
| --beneficiaries <addresses> | For address derivation |
| --output <file> | Save proof JSON to file (default: stdout) |
| --config <path> | Config file path |
redeem
Submit redemption transaction. Can use existing proof or generate on the fly.
# With existing proof
payments redeem --proof <file> [options]
# Generate proof on the fly
payments redeem --secret <hex> --beneficiary <addr> --amount <value> --client-ids <ids> --selected-client <id> [options]| Option | Description |
|--------|-------------|
| --proof <file> | Path to proof JSON file (from prove command) |
| --secret <hex> | 32-byte secret (required if no --proof) |
| --beneficiary <address> | Redeem destination (required if no --proof) |
| --amount <value> | Amount to redeem (required if no --proof) |
| --client-ids <ids> | Light client IDs (required if no --proof) |
| --selected-client <id> | Client ID to use (required if no --proof) |
| --beneficiaries <addresses> | For address derivation |
| --private-key <key> | Signing key (or SENDER_PRIVATE_KEY env) |
| --config <path> | Config file path |
update-client
Update loopback light client to a specific block height.
payments update-client --rpc <url> --client-id <id> --ibc-handler <address> [options]| Option | Description |
|--------|-------------|
| --rpc <url> | RPC URL for the chain (required) |
| --client-id <id> | Light client ID to update (required) |
| --ibc-handler <address> | IBCHandler contract address (required) |
| --height <height> | Block height (default: latest) |
| --private-key <key> | Signing key (or SENDER_PRIVATE_KEY env) |
history
List redemption transactions for a secret.
payments history --secret <hex> [options]| Option | Description |
|--------|-------------|
| --secret <hex> | 32-byte secret (required) |
| --from-block <number> | Start block number (default: earliest) |
| --to-block <number> | End block number (default: latest) |
| --config <path> | Config file path |
export-verifier
Export the Solidity verifier contract from the prover server.
payments export-verifier [options]| Option | Description |
|--------|-------------|
| --prover-url <url> | Prover gRPC-web URL (default: http://localhost:8080) |
| --output <file> | Save verifier to file (default: stdout) |
