Skip to main content
Available The Kotlin SDK is available at github.com/d4mr/t2z/sdks/kotlin. It uses UniFFI bindings to the Rust core and works on Android and JVM.

Prerequisites

  • Java 11+ (JDK)
  • Rust (nightly toolchain)

Installation

Since the Kotlin SDK requires the native libt2z_uniffi library, you need to build from source:
# Clone the repository
git clone https://github.com/d4mr/t2z
cd t2z/sdks/kotlin

# Build the native library and generate Kotlin bindings
./scripts/build.sh

# Run tests to verify (requires Java)
./scripts/test.sh

Gradle Dependency

Add JNA dependency to your project:
dependencies {
    implementation("net.java.dev.jna:jna:5.14.0")
}
Copy the generated source files from src/main/kotlin/uniffi/t2z_uniffi/ to your project.

Quick Start

import uniffi.t2z_uniffi.*

fun main() {
    // 1. Create transparent input
    val input = UniffiTransparentInput(
        pubkey = "03abc123...",      // 33-byte compressed pubkey (hex)
        prevoutTxid = "ce15f716...", // 32-byte txid (little-endian hex)
        prevoutIndex = 0u,
        value = 1_000_000uL,         // 0.01 ZEC in zatoshis
        scriptPubkey = "76a914...88ac", // P2PKH script (hex)
        sequence = null
    )

    // 2. Create payment
    val payment = UniffiPayment(
        address = "u1recipient...", // Unified address with Orchard
        amount = 900_000uL,
        memo = null,
        label = null
    )

    val request = UniffiTransactionRequest(
        payments = listOf(payment)
    )

    // 3. Propose transaction
    var pczt = proposeTransaction(
        inputsToSpend = listOf(input),
        transactionRequest = request,
        changeAddress = "u1change...",
        network = "testnet",
        expiryHeight = 3720100u
    )

    // 4. Sign transparent inputs (external signing)
    val sighash = getSighash(pczt, 0u)
    
    // Sign the sighash with your key (ECDSA secp256k1)
    val signature = sign(sighash, privateKey) // Your signing logic
    
    pczt = appendSignature(pczt, 0u, pubkeyHex, signature)

    // 5. Generate Orchard proofs (~10 seconds first time)
    pczt = proveTransaction(pczt)

    // 6. Finalize and get raw transaction
    val txHex = finalizeAndExtractHex(pczt)

    println("Transaction ready: $txHex")
}

API Reference

Transaction Construction

FunctionDescription
proposeTransactionCreate a PCZT from inputs and payments
verifyBeforeSigningVerify PCZT matches original request

Signing

FunctionDescription
getSighashGet sighash for external signing
appendSignatureAdd a pre-computed signature
signTransparentInputSign with in-memory private key

Proving & Finalization

FunctionDescription
proveTransactionGenerate Orchard ZK proofs
finalizeAndExtractExtract final transaction bytes
finalizeAndExtractHexExtract as hex string
combinePcztsCombine multiple PCZTs

Utilities

FunctionDescription
prebuildProvingKeyPre-build proving key at startup
isProvingKeyReadyCheck if proving key is cached
versionGet library version

Types

UniffiTransparentInput

data class UniffiTransparentInput(
    val pubkey: String,       // 33-byte compressed pubkey (hex)
    val prevoutTxid: String,  // 32-byte txid (little-endian hex)
    val prevoutIndex: UInt,   // Output index
    val value: ULong,         // Value in zatoshis
    val scriptPubkey: String, // P2PKH scriptPubkey (hex)
    val sequence: UInt?       // Optional sequence number
)

UniffiPayment

data class UniffiPayment(
    val address: String,  // Unified or transparent address
    val amount: ULong,    // Amount in zatoshis
    val memo: String?,    // Optional memo (hex-encoded)
    val label: String?    // Optional label
)

UniffiExpectedTxOut

data class UniffiExpectedTxOut(
    val address: String, // Expected address
    val amount: ULong    // Expected amount (0 = wildcard)
)

Error Handling

All functions throw UniffiException on error:
try {
    val pczt = proposeTransaction(inputs, request, changeAddr, network, expiry)
} catch (e: UniffiException) {
    println("Error: ${e.message}")
}

Performance Tips

Pre-build Proving Key

The first proof generation takes ~10 seconds. Pre-build at startup:
fun initT2z() {
    if (!isProvingKeyReady()) {
        println("Building Orchard proving key...")
        prebuildProvingKey()
        println("Proving key ready")
    }
}

Android Integration

For Android, ensure the native library is placed in the correct jniLibs directory:
app/src/main/jniLibs/
├── arm64-v8a/
│   └── libt2z_uniffi.so
├── armeabi-v7a/
│   └── libt2z_uniffi.so
└── x86_64/
    └── libt2z_uniffi.so
Add to build.gradle.kts:
android {
    sourceSets {
        getByName("main") {
            jniLibs.srcDirs("src/main/jniLibs")
        }
    }
}

ProGuard / R8

Add to your proguard-rules.pro:
-keep class uniffi.t2z_uniffi.** { *; }
-keepclassmembers class uniffi.t2z_uniffi.** { *; }

Minimum SDK

  • Minimum SDK: 21 (Android 5.0)
  • Target SDK: 34

Java Interop

The SDK is fully usable from Java:
import uniffi.t2z_uniffi.*;
import java.util.List;

public class Example {
    public static void main(String[] args) {
        UniffiTransparentInput input = new UniffiTransparentInput(
            "03abc123...",
            "ce15f716...",
            0,
            1_000_000L,
            "76a914...88ac",
            null
        );
        
        UniffiPayment payment = new UniffiPayment(
            "u1recipient...",
            800_000L,
            null,
            null
        );
        
        UniffiTransactionRequest request = new UniffiTransactionRequest(
            List.of(payment)
        );
        
        UniffiPczt pczt = T2zUniffiKt.proposeTransaction(
            List.of(input),
            request,
            "u1change...",
            "testnet",
            3720100
        );
        
        // ... sign, prove, finalize
    }
}

Type Mappings

TypeScriptKotlinJava
WasmTransparentInputUniffiTransparentInputUniffiTransparentInput
WasmPaymentUniffiPaymentUniffiPayment
WasmPcztUniffiPcztUniffiPczt
bigintULonglong
string (hex)StringString
nullnullnull

Building from Source

# Clone the repository
git clone https://github.com/d4mr/t2z
cd t2z/crates

# Build the UniFFI library
cargo build --release -p t2z-uniffi

# Generate Kotlin bindings
cargo run -p t2z-uniffi --bin uniffi-bindgen -- \
    generate --library target/release/libt2z_uniffi.dylib \
    --language kotlin \
    --out-dir ../sdks/kotlin/src/main/kotlin