A production-ready Rust library for creating and managing Hash Time-Locked Contracts (HTLCs) on Zcash's transparent transaction layer. Built for atomic swaps and cross-chain bridges.
- β ZIP-300 Compliant - Full HTLC script implementation
- β Bitcoin 0.29 Compatible - Works with Zcash transparent transactions
- β Database Persistence - PostgreSQL with Diesel ORM
- β Block Explorer Integration - Query UTXOs without running a full node
- β CLI Tool - Command-line interface for testing and operations
- β Type-Safe - Full Rust type safety with comprehensive error handling
- β Async/Await - Modern async Rust with Tokio
- β Config File Support - TOML/JSON configuration (no environment variables required)
Add to your Cargo.toml:
[dependencies]
zcash-htlc-builder = "0.1.5"
tokio = { version = "1", features = ["full"] }Create zcash-config.toml in your project root:
network = "Testnet" # or "Mainnet"
rpc_url = "http://localhost:18232"
rpc_user = "your-rpc-user"
rpc_password = "your-rpc-password"
database_url = "postgresql://user:password@localhost/zcash_htlc"
database_max_connections = 10
explorer_api = "https://explorer.testnet.z.cash/api"
# Optional: Relayer Configuration (for automated HTLC management)
[relayer]
hot_wallet_privkey = "your-private-key"
hot_wallet_address = "your-zcash-address"
max_tx_per_batch = 10
poll_interval_secs = 10
max_retry_attempts = 3
min_confirmations = 1
network_fee_zec = "0.0001"
β οΈ Security Warning: Never commitzcash-config.tomlwith real credentials to version control. Add it to.gitignoreand usezcash-config.toml.exampleas a template.
# Create PostgreSQL database
createdb zcash_htlc
# Migrations run automatically when you first use the libraryuse zcash_htlc_builder::{
ZcashHTLCClient, ZcashConfig, HTLCParams, UTXO,
database::Database,
};
use std::sync::Arc;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Load configuration from file
let config = ZcashConfig::from_toml_file("zcash-config.toml")?;
// Initialize database
let database = Arc::new(Database::new(
&config.database_url,
config.database_max_connections,
)?);
// Create client
let client = ZcashHTLCClient::new(config, database);
// Generate keys
let recipient_privkey = client.generate_privkey();
let recipient_pubkey = client.derive_pubkey(&recipient_privkey)?;
let refund_privkey = client.generate_privkey();
let refund_pubkey = client.derive_pubkey(&refund_privkey)?;
// Generate secret and hash lock
let secret = hex::encode(rand::random::<[u8; 32]>());
let hash_lock = client.generate_hash_lock(&secret);
// Create HTLC parameters
let params = HTLCParams {
recipient_pubkey,
refund_pubkey,
hash_lock: hash_lock.clone(),
timelock: 500000, // Block height
amount: "0.01".to_string(),
};
// Prepare funding (replace with your actual UTXOs)
let funding_utxos = vec![
UTXO {
txid: "your-txid".to_string(),
vout: 0,
script_pubkey: "script-hex".to_string(),
amount: "0.02".to_string(),
confirmations: 6,
}
];
// Create HTLC
let result = client.create_htlc(
params,
funding_utxos,
"your-change-address",
vec!["your-funding-privkey"],
).await?;
println!("β
HTLC Created!");
println!("π HTLC ID: {}", result.htlc_id);
println!("π TXID: {}", result.txid);
println!("π P2SH Address: {}", result.p2sh_address);
println!("ποΈ Secret: {}", secret);
// Later, redeem the HTLC
let redeem_txid = client.redeem_htlc(
&result.htlc_id,
&secret,
"recipient-address",
&recipient_privkey,
).await?;
println!("β
HTLC Redeemed: {}", redeem_txid);
Ok(())
}You can also use JSON format:
{
"network": "testnet",
"rpc_url": "http://localhost:18232",
"rpc_user": "user",
"rpc_password": "password",
"database_url": "postgresql://localhost/zcash_htlc",
"database_max_connections": 10,
"explorer_api": "https://explorer.testnet.z.cash/api"
}Load with:
let config = ZcashConfig::from_json_file("zcash-config.json")?;The library includes a command-line tool for testing and operations.
cargo install zcash-htlc-builderAll CLI commands use the config file from your project root or via custom path.
zcash-htlc-cli keygen
# Or with custom config:
zcash-htlc-cli keygen ./my-config.tomlzcash-htlc-cli hashlock "my-secret-phrase"Output:
π Hash Lock:
Secret: my-secret-phrase
Hash Lock: 6e9f78c1c24acdee688a360f1212c9b9989e7469d6a6e39e4ed7ca279f0c7846
zcash-htlc-cli createzcash-htlc-cli redeem <htlc_id> <secret> <recipient_address> <privkey>zcash-htlc-cli refund <htlc_id> <refund_address> <privkey>zcash-htlc-cli broadcast <hex-encoded-tx>You can set ZCASH_CONFIG environment variable to specify config file location:
export ZCASH_CONFIG=./production-config.toml
zcash-htlc-cli keygenCheck the examples/ directory for complete working examples:
# Run the full HTLC flow example
cargo run --example test_htlc_flowOutput:
π§ͺ Testing HTLC Flow
π Step 1: Generating Keys
π€ Recipient Private Key: 489175b18cd8f36e...
π€ Recipient Public Key: 02f6b9fc88bf40a5c...
π¦ Relayer Private Key: c980fd0225a51ec8...
π¦ Relayer Public Key: 03bb93b3c358ba56e...
π Step 2: Generating Secret and Hash Lock
ποΈ Secret: 8f2c59d64b11f329...
π Hash Lock: 346a7d2128ff4d1b...
...
βββββββββββββββββββββββββββββββββββββββββββββββ
β ZcashHTLCClient (Main API) β
βββββββββββββββββββββββββββββββββββββββββββββββ€
β β’ create_htlc() β
β β’ redeem_htlc() β
β β’ refund_htlc() β
β β’ generate_privkey() β
β β’ derive_pubkey() β
β β’ generate_hash_lock() β
βββββββββββββββββββββββββββββββββββββββββββββββ
β β β
βΌ βΌ βΌ
ββββββββββββββββ ββββββββββββ ββββββββββββββββ
β Builder β β Signer β β Database β
β β β β β β
β β’ HTLC TX β β β’ Sign β β β’ HTLCs β
β β’ Redeem TX β β β’ Verify β β β’ Operations β
β β’ Refund TX β β β’ Keys β β β’ UTXOs β
ββββββββββββββββ ββββββββββββ ββββββββββββββββ
| Table | Description |
|---|---|
| zcash_htlcs | HTLC state and metadata |
| htlc_operations | Transaction operations (create/redeem/refund) |
| relayer_utxos | UTXOs managed by relayer's hot wallet |
| indexer_checkpoints | Blockchain sync state |
| Field | Type | Required | Description |
|---|---|---|---|
network |
string | β Yes | "testnet" or "mainnet" |
rpc_url |
string | β Yes | Zcash RPC endpoint |
rpc_user |
string | β No | RPC username or API key |
rpc_password |
string | β No | RPC password |
database_url |
string | β Yes | PostgreSQL connection string |
database_max_connections |
number | β No | Max DB connections (default: 10) |
explorer_api |
string | β No | Block explorer API URL |
| Field | Type | Required | Description |
|---|---|---|---|
hot_wallet_privkey |
string | Private key for funding | |
hot_wallet_address |
string | Address for funding | |
max_tx_per_batch |
number | β No | Max transactions per batch (default: 10) |
poll_interval_secs |
number | β No | Polling interval in seconds (default: 10) |
network_fee_zec |
string | β No | Network fee in ZEC (default: "0.0001") |
*Required only if running automated relayer
- β Never commit
zcash-config.tomlwith real keys to version control - π Use hardware wallets for production mainnet operations
- ποΈ Store keys securely (HSM, encrypted storage, environment secrets)
- π Rotate keys regularly
- β° Always set timelocks with sufficient buffer (consider network congestion)
- π Monitor block height before attempting refunds
- β Account for at least 6 confirmations
- π Always verify transactions before signing
- π° Check amounts, addresses, and scripts carefully
- π§ͺ Test on testnet first
- π Use strong PostgreSQL credentials
- π Enable SSL for database connections in production
- πΎ Regularly backup database
| Property | Value |
|---|---|
| RPC Port | 18232 |
| Faucet | testnet.zecfaucet.com |
| Explorer | blockexplorer.one/zcash/testnet |
| Property | Value |
|---|---|
| RPC Port | 8232 |
| Explorer | blockexplorer.one/zcash/mainnet |
# Run all tests
cargo test
# Run specific test
cargo test test_build_htlc_script
# With logging
RUST_LOG=debug cargo test
# Run examples
cargo run --example test_htlc_flow| Crate | Version | Purpose |
|---|---|---|
| bitcoin | 0.29 | Transaction building (Zcash compatible) |
| secp256k1 | 0.24 | Cryptographic signatures |
| diesel | 2.1 | PostgreSQL ORM |
| tokio | 1.0 | Async runtime |
| reqwest | 0.11 | HTTP client for RPC |
| serde | 1.0 | Serialization/deserialization |
| toml | 0.8 | TOML configuration parsing |
- β
Ensure
zcash-config.tomlexists in project root - β Check file permissions
- β Verify TOML syntax with a validator
- β
Verify PostgreSQL is running:
pg_isready - β Check database credentials in config
- β
Ensure database exists:
createdb zcash_htlc
- β Check RPC credentials
- β Ensure correct port (18232 for testnet, 8232 for mainnet)
- β Verify sufficient balance in funding UTXOs
- β Check that UTXOs are confirmed (at least 1 confirmation)
- β Ensure private keys match funding addresses
Contributions welcome! Please:
- π΄ Fork the repository
- πΏ Create a feature branch (
git checkout -b feature/amazing-feature) - β Write tests for new functionality
- π§ͺ Ensure
cargo testandcargo clippypass - π Update documentation
- π Submit a pull request
# Clone repository
git clone https://github.com/Mist-Labs/zcash-htlc-builder.git
cd zcash-htlc-builder
# Install dependencies
cargo build
# Run tests
cargo test
# Run clippy
cargo clippy -- -D warnings
# Format code
cargo fmtSee CHANGELOG.md for version history.
This project is licensed under the Apache-2.0 License - see the LICENSE file for details.
- π ZIP-300: Cross-chain Atomic Transactions
- π Zcash Protocol Specification
- π Bitcoin Developer Reference
- π Diesel ORM Guide
- π Issues: GitHub Issues
- π Docs: docs.rs/zcash-htlc-builder
- π¬ Discussions: GitHub Discussions
Built with β€οΈ for the Zcash ecosystem by Mist Labs
β If you find this library useful, please star the repository!