diff --git a/packages/wasm-utxo/js/fixedScriptWallet/ZcashBitGoPsbt.ts b/packages/wasm-utxo/js/fixedScriptWallet/ZcashBitGoPsbt.ts index fc588ecc2ae..31291680708 100644 --- a/packages/wasm-utxo/js/fixedScriptWallet/ZcashBitGoPsbt.ts +++ b/packages/wasm-utxo/js/fixedScriptWallet/ZcashBitGoPsbt.ts @@ -1,4 +1,4 @@ -import { BitGoPsbt as WasmBitGoPsbt } from "../wasm/wasm_utxo.js"; +import { BitGoPsbt as WasmBitGoPsbt, zcash_branch_id_for_height } from "../wasm/wasm_utxo.js"; import { type WalletKeysArg, RootWalletKeys } from "./RootWalletKeys.js"; import { BitGoPsbt, type CreateEmptyOptions, type HydrationUnspent } from "./BitGoPsbt.js"; import { ZcashTransaction, type ITransaction } from "../transaction.js"; @@ -264,6 +264,22 @@ export class ZcashBitGoPsbt extends BitGoPsbt { return this.wasm.expiry_height(); } + /** + * Get the Zcash consensus branch ID stored in the PSBT proprietary map. + * Returns undefined for v5 PSBTs or PSBTs without the key. + */ + get consensusBranchId(): number | undefined { + return this.wasm.consensus_branch_id(); + } + + /** + * Return the Zcash consensus branch ID active at `height` on `network`. + * Returns undefined if `height` is before Overwinter activation. + */ + static branchIdForHeight(network: ZcashNetworkName, height: number): number | undefined { + return zcash_branch_id_for_height(network, height); + } + /** * Extract the final Zcash transaction from a finalized PSBT * diff --git a/packages/wasm-utxo/src/wasm/fixed_script_wallet/mod.rs b/packages/wasm-utxo/src/wasm/fixed_script_wallet/mod.rs index 8c021f32cee..0a8675beeb8 100644 --- a/packages/wasm-utxo/src/wasm/fixed_script_wallet/mod.rs +++ b/packages/wasm-utxo/src/wasm/fixed_script_wallet/mod.rs @@ -961,6 +961,17 @@ impl BitGoPsbt { } } + /// Get the Zcash consensus branch ID from the PSBT proprietary map (returns None for non-Zcash PSBTs) + pub fn consensus_branch_id(&self) -> Option { + use crate::fixed_script_wallet::bitgo_psbt::{ + propkv::get_zec_consensus_branch_id, BitGoPsbt as InnerBitGoPsbt, + }; + match &self.psbt { + InnerBitGoPsbt::Zcash(z, _) => get_zec_consensus_branch_id(&z.psbt), + _ => None, + } + } + pub fn get_outputs_with_address(&self) -> Result { crate::wasm::psbt::get_outputs_with_address_from_psbt(self.psbt.psbt(), self.psbt.network()) } @@ -1943,3 +1954,23 @@ impl BitGoPsbt { } impl_wasm_psbt_ops!(BitGoPsbt, psbt); + +/// Return the Zcash consensus branch ID active at `height` on `network`. +/// +/// `network`: "zcash" / "zec" for mainnet, "zcashTest" / "tzec" for testnet. +/// Returns `None` if `height` is before Overwinter activation. +/// Throws if `network` is not a recognised Zcash network name. +#[wasm_bindgen] +pub fn zcash_branch_id_for_height(network: &str, height: u32) -> Result, JsValue> { + let is_mainnet = match network { + "zcash" | "zec" => true, + "zcashTest" | "tzec" => false, + _ => { + return Err(JsValue::from_str(&format!( + "unknown Zcash network {:?}: expected \"zcash\", \"zec\", \"zcashTest\", or \"tzec\"", + network + ))) + } + }; + Ok(crate::zcash::branch_id_for_height(height, is_mainnet)) +}