The finalize_and_extract function performs final validation and produces the raw transaction bytes ready to broadcast to the Zcash network.
Prerequisites
Before finalization, ensure:
✅ All transparent inputs are signed
✅ All Orchard proofs are generated
const info = t2z . inspect_pczt ( pczt . to_hex ());
if ( ! info . all_inputs_signed ) {
throw new Error ( 'Not all inputs signed' );
}
if ( ! info . has_orchard_proofs ) {
throw new Error ( 'Orchard proofs not generated' );
}
Function Signature
// Get raw bytes
function finalize_and_extract ( pczt : WasmPczt ) : Uint8Array
// Get hex string (convenient for broadcasting)
function finalize_and_extract_hex ( pczt : WasmPczt ) : string
func FinalizeAndExtract ( pczt * Pczt ) ([] byte , error )
func FinalizeAndExtractHex ( pczt * Pczt ) ( string , error )
fun finalizeAndExtract (pczt: Pczt ): ByteArray
fun finalizeAndExtractHex (pczt: Pczt ): String
Basic Usage
// Get transaction as hex (most common)
const txHex = t2z . finalize_and_extract_hex ( pczt );
console . log ( 'Transaction ready:' , txHex . length / 2 , 'bytes' );
// Or get raw bytes
const txBytes = t2z . finalize_and_extract ( pczt );
txHex , err := t2z . FinalizeAndExtractHex ( pczt )
if err != nil {
log . Fatal ( err )
}
fmt . Printf ( "Transaction ready: %d bytes \n " , len ( txHex ) / 2 )
val txHex = finalizeAndExtractHex (pczt)
println ( "Transaction ready: ${ txHex.length / 2 } bytes" )
What Happens During Finalization
Spend Finalizer
Assembles final script signatures from partial signatures.
Validation
Verifies all required data is present and valid.
Transaction Extractor
Converts the PCZT into a raw Zcash transaction.
Serialization
Produces the final byte representation.
Broadcasting the Transaction
After extraction, broadcast the transaction to the Zcash network:
Using zcash-cli
zcash-cli sendrawtransaction "0500000..."
Using lightwalletd
// gRPC to lightwalletd
const response = await lightwalletClient . sendTransaction ({
data: hexToBytes ( txHex )
});
console . log ( 'Txid:' , response . txid );
Using a Block Explorer
Many block explorers provide a “Broadcast” or “Push TX” feature where you can paste the raw transaction hex.
Using JSON-RPC
const response = await fetch ( 'https://zcash-rpc.example.com' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({
jsonrpc: '2.0' ,
method: 'sendrawtransaction' ,
params: [ txHex ],
id: 1
})
});
Complete Example
import * as t2z from '@d4mr/t2z-wasm' ;
async function buildAndBroadcast () {
// 1. Create PCZT
let pczt = t2z . propose_transaction ( inputs , payments , changeAddr , network , expiry );
// 2. Sign all inputs
for ( let i = 0 ; i < inputs . length ; i ++ ) {
const sighash = t2z . get_sighash ( pczt , i );
const sig = await sign ( sighash , keys [ i ]);
pczt = t2z . append_signature ( pczt , i , pubkeys [ i ], sig );
}
// 3. Generate proofs
pczt = t2z . prove_transaction ( pczt );
// 4. Finalize
const txHex = t2z . finalize_and_extract_hex ( pczt );
// 5. Broadcast
const txid = await broadcast ( txHex );
console . log ( 'Transaction broadcast:' , txid );
return txid ;
}
Transaction Structure
The extracted transaction follows the v5 transaction format:
Field Description Header Version, version group ID Transparent Inputs with signatures, outputs Sapling (empty in t2z transactions) Orchard Actions with proofs, binding signature Expiry Block height expiry
Typical sizes:
1 input → 1 Orchard output: ~2.5 KB
1 input → 2 Orchard outputs: ~5 KB
Common Errors
Not all transparent inputs have been signed. Use inspect_pczt to check which inputs need signing. const info = t2z . inspect_pczt ( pczt . to_hex ());
info . transparent_inputs . forEach (( input , i ) => {
if ( ! input . is_signed ) {
console . log ( `Input ${ i } needs signature` );
}
});
Orchard proofs haven’t been generated. Call prove_transaction first.
The PCZT couldn’t be finalized. This usually means something is inconsistent — try rebuilding from scratch.
After Broadcasting
After a successful broadcast:
Get the txid — Most broadcast methods return the transaction ID
Wait for confirmation — Monitor for inclusion in a block
Verify in explorer — Check the transaction on a block explorer
The recipient can view incoming shielded funds using their full viewing key (not spending key). For Orchard, viewing keys are encoded as uview1... (mainnet) or uviewtest1... (testnet).
🎉 Congratulations!
You’ve completed the full t2z transaction flow:
✅ Proposed the transaction
✅ Verified (optional)
✅ Signed all inputs
✅ Generated proofs
✅ Finalized and broadcast
Try the Demo See this entire flow in action with the interactive demo.