Skip to main content
The propose_transaction function creates a PCZT by combining the Creator, Constructor, and IO Finalizer roles from ZIP 374.

Function Signature

  • TypeScript
  • Go
  • Kotlin
function propose_transaction(
  inputs: WasmTransparentInput[],
  payments: WasmPayment[],
  change_address: string | null,
  network: 'mainnet' | 'testnet',
  expiry_height: number
): WasmPczt

Parameters

inputs
TransparentInput[]
required
Array of transparent UTXOs to spend. Each input requires:
FieldTypeDescription
pubkeystring33-byte compressed public key (hex)
prevoutTxidstring32-byte transaction ID (little-endian hex)
prevoutIndexnumberOutput index in previous transaction
valuebigintValue in zatoshis
scriptPubkeystringP2PKH scriptPubkey (hex)
sequencenumber?Sequence number (default: 0xffffffff)
payments
Payment[]
required
Array of outputs to create. Each payment requires:
FieldTypeDescription
addressstringUnified address (Orchard) or transparent address
amountbigintAmount in zatoshis
memostring?Hex-encoded memo for shielded outputs (max 512 bytes)
labelstring?Optional display label
change_address
string | null
Address to receive change. Can be:
  • Unified address with Orchard receiver (recommended for privacy)
  • Transparent P2PKH address (t1... or tm...)
  • null if no change expected
If total_input > total_payments + fee, a change address is required.
network
string
required
Network to use: 'mainnet' or 'testnet'
expiry_height
number
required
Block height at which the transaction expires. Must be:
  • After Nu5 activation (mainnet: 1,687,104 / testnet: 1,842,420)
  • At least current_height + 40 to avoid “tx-expiring-soon” errors

Example

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

// Prepare inputs
const inputs = [
  new t2z.WasmTransparentInput(
    '03abc123...',                    // Compressed pubkey (33 bytes hex)
    'ce15f716...1338',                // Txid (little-endian)
    0,                                 // Output index
    1_000_000n,                        // 0.01 ZEC
    '76a914...88ac',                  // P2PKH scriptPubkey
    null                               // Default sequence
  )
];

// Prepare payments
const payments = [
  new t2z.WasmPayment(
    'u1abc...',                        // Unified address with Orchard
    800_000n,                          // 0.008 ZEC
    Buffer.from('Hello!').toString('hex'),  // Memo
    'Payment for services'             // Label
  )
];

// Get current block height (in production, fetch from lightwalletd)
const currentHeight = 3_720_000;
const expiryHeight = currentHeight + 100;

// Create the PCZT
const pczt = t2z.propose_transaction(
  inputs,
  payments,
  'u1change...',   // Change goes to Orchard (shielded)
  'testnet',
  expiryHeight
);

// Inspect what was created
const info = t2z.inspect_pczt(pczt.to_hex());
console.log('Fee:', info.implied_fee, 'zatoshis');

What Happens Internally

  1. Validation — Inputs and payment addresses are validated
  2. Fee Calculation — ZIP 317 fee is computed based on transaction structure
  3. Change Calculationchange = total_input - total_payments - fee
  4. Builder Construction — Zcash transaction builder creates the structure
  5. PCZT Creation — Builder output is converted to PCZT format
  6. IO Finalization — Input/output metadata is finalized

Fee Calculation

Fees are calculated automatically according to ZIP 317:
fee = 5000 × max(2, logical_actions)
logical_actions = max(transparent_inputs, transparent_outputs) + orchard_actions
ScenarioFee
1 input → 1 Orchard output10,000 zats
1 input → 1 Orchard output + Orchard change10,000 zats
2 inputs → 1 Orchard output10,000 zats
3 inputs → 2 Orchard outputs15,000 zats

Common Errors

The expiry height is before Nu5 activation. Use a height after:
  • Mainnet: 1,687,104
  • Testnet: 1,842,420
Total input value is less than payments + fee. Either:
  • Add more inputs
  • Reduce payment amounts
There’s leftover value but no change address provided. Pass a change address.
The address couldn’t be parsed. Ensure it’s a valid:
  • Unified address (u1... or utest1...)
  • Transparent address (t1... or tm...)

Next Step

After creating the PCZT, you can optionally verify it before signing, or proceed directly to signing.