Skip to main content
A t2z transaction goes through five distinct phases. Each phase can be performed by different parties or systems, enabling flexible transaction construction workflows.

The Five Phases

Propose

Create the PCZTCombine transparent inputs and payment outputs into a Partially Constructed Zcash Transaction.
  • Define which UTXOs to spend
  • Specify recipient addresses and amounts
  • Set change address and expiry height
  • ZIP 317 fee is calculated automatically
Learn more →

Verify

Validate before signing (optional)Ensure the PCZT matches your original request — important if the PCZT was handled by a third party.
  • Confirm all payments are present
  • Verify amounts match
  • Check for unexpected outputs (malleation)
Learn more →

Sign

Add signaturesSign each transparent input with the corresponding private key.
  • Get sighash for each input
  • Sign externally (hardware wallet, HSM) or internally
  • Append signatures to the PCZT
Learn more →

Prove

Generate ZK proofsCreate Orchard zero-knowledge proofs for any shielded outputs.
  • First call builds proving key (~10 seconds)
  • Subsequent calls are fast (cached)
  • No trusted setup required (Halo 2)
Learn more →

Finalize

Extract transactionPerform final validation and extract the raw transaction bytes.
  • Verify all signatures present
  • Verify all proofs generated
  • Produce transaction ready for broadcast
Learn more →

Parallel Operations

Signing and proving can be done in parallel since they don’t depend on each other: If signing and proving are done by the same party sequentially, the combine step can be skipped.

Example: Complete Flow

  • TypeScript
  • Go
  • Kotlin
import * as t2z from '@d4mr/t2z-wasm';

// 1. PROPOSE
let pczt = t2z.propose_transaction(inputs, payments, changeAddr, network, expiry);

// 2. VERIFY (optional but recommended)
t2z.verify_before_signing(pczt, payments, expectedChange);

// 3. SIGN each input
for (let i = 0; i < inputs.length; i++) {
  const sighash = t2z.get_sighash(pczt, i);
  const signature = await externalSign(sighash, keys[i]);
  pczt = t2z.append_signature(pczt, i, pubkeys[i], signature);
}

// 4. PROVE
pczt = t2z.prove_transaction(pczt);

// 5. FINALIZE
const txHex = t2z.finalize_and_extract_hex(pczt);

Inspecting the PCZT

At any point, you can inspect the PCZT to see its current state:
const info = t2z.inspect_pczt(pczt.to_hex());

console.log({
  totalInput: info.total_input,
  totalOutput: info.total_orchard_output + info.total_transparent_output,
  fee: info.implied_fee,
  signed: info.all_inputs_signed,
  proved: info.has_orchard_proofs,
});
Learn more about inspect_pczt →