From 42945f4a96eab3f73211e2704faaa0823b81e97f Mon Sep 17 00:00:00 2001 From: Otto Allmendinger Date: Wed, 17 Dec 2025 11:07:08 +0100 Subject: [PATCH 1/4] docs(wasm-utxo): update feature matrix in README.md Mark FixedScript Wallet Transaction Support for Bitcoin and Litecoin as complete in the feature status table. Issue: BTC-2656 Co-authored-by: llm-git --- packages/wasm-utxo/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wasm-utxo/README.md b/packages/wasm-utxo/README.md index 249196fa959..f4997bae996 100644 --- a/packages/wasm-utxo/README.md +++ b/packages/wasm-utxo/README.md @@ -20,7 +20,7 @@ This project is under active development. | Descriptor Wallet: Address Support | βœ… Complete | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | | Descriptor Wallet: Transaction Support | βœ… Complete | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | | FixedScript Wallet: Address Generation | βœ… Complete | βœ… Complete | βœ… Complete | βœ… Complete | βœ… Complete | βœ… Complete | βœ… Complete | -| FixedScript Wallet: Transaction Support | ⏳ TODO | ⏳ TODO | ⏳ TODO | ⏳ TODO | ⏳ TODO | ⏳ TODO | ⏳ TODO | +| FixedScript Wallet: Transaction Support | βœ… Complete | ⏳ TODO | ⏳ TODO | ⏳ TODO | ⏳ TODO | βœ… Complete | ⏳ TODO | ## Building From 059165850ccc709434600ca1124db5beed2598ed Mon Sep 17 00:00:00 2001 From: Otto Allmendinger Date: Wed, 17 Dec 2025 11:06:08 +0100 Subject: [PATCH 2/4] feat(wasm-utxo): add BCH fork ID support for BCH, XEC, BSV, BTG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement fork ID support for Bitcoin Cash-style networks to enable proper signing and verification. This includes: - Use fork ID-aware signing for BCH (0), BTG (79), XEC (0), and BSV (0) - Update miniscript dependency to use forkid-compatible version - Modify PSBT functions to use the appropriate sighash algorithm - Ensure replay protection inputs use correct sighash calculation - Add tests to verify signβ†’verify roundtrip works correctly Issue: BTC-2656 Co-authored-by: llm-git --- packages/wasm-utxo/Cargo.lock | 5 +- packages/wasm-utxo/Cargo.toml | 2 +- packages/wasm-utxo/cli/Cargo.toml | 2 +- .../src/fixed_script_wallet/bitgo_psbt/mod.rs | 236 ++++++++++++++---- .../bitgo_psbt/psbt_wallet_input.rs | 19 +- 5 files changed, 206 insertions(+), 58 deletions(-) diff --git a/packages/wasm-utxo/Cargo.lock b/packages/wasm-utxo/Cargo.lock index 2f38a1210ff..0957a53a6b8 100644 --- a/packages/wasm-utxo/Cargo.lock +++ b/packages/wasm-utxo/Cargo.lock @@ -157,8 +157,7 @@ checksum = "32637268377fc7b10a8c6d51de3e7fba1ce5dd371a96e342b34e6078db558e7f" [[package]] name = "bitcoin" version = "0.32.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e499f9fc0407f50fe98af744ab44fa67d409f76b6772e1689ec8485eb0c0f66" +source = "git+https://github.com/BitGo/rust-bitcoin?tag=bitcoin-0.32.8-forkid#e1eb843a5f5f28ed7a229bcca59cff44719bbcc1" dependencies = [ "base58ck", "bech32", @@ -779,7 +778,7 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniscript" version = "13.0.0" -source = "git+https://github.com/BitGo/rust-miniscript?tag=miniscript-13.0.0-opdrop#970feb88f5ceae6b1bf4253b77dbeaf0f2e2d7ce" +source = "git+https://github.com/BitGo/rust-miniscript?tag=miniscript-13.0.0-opdrop-forkid#13eccd8bdb83af1a9b63118ceac962aed49906a5" dependencies = [ "bech32", "bitcoin", diff --git a/packages/wasm-utxo/Cargo.toml b/packages/wasm-utxo/Cargo.toml index 703fd6f2868..ba3794808ad 100644 --- a/packages/wasm-utxo/Cargo.toml +++ b/packages/wasm-utxo/Cargo.toml @@ -16,7 +16,7 @@ all = "warn" [dependencies] wasm-bindgen = "0.2" js-sys = "0.3" -miniscript = { git = "https://github.com/BitGo/rust-miniscript", tag = "miniscript-13.0.0-opdrop" } +miniscript = { git = "https://github.com/BitGo/rust-miniscript", tag = "miniscript-13.0.0-opdrop-forkid" } bech32 = "0.11" musig2 = { version = "0.3.1", default-features = false, features = ["k256"] } getrandom = { version = "0.2", features = ["js"] } diff --git a/packages/wasm-utxo/cli/Cargo.toml b/packages/wasm-utxo/cli/Cargo.toml index 08b6e436398..0b95766e870 100644 --- a/packages/wasm-utxo/cli/Cargo.toml +++ b/packages/wasm-utxo/cli/Cargo.toml @@ -16,6 +16,6 @@ base64 = "0.21" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" num-bigint = "0.4" -bitcoin = "0.32" +bitcoin = { git = "https://github.com/BitGo/rust-bitcoin", tag = "bitcoin-0.32.8-forkid" } colored = "2.1" ptree = "0.5" diff --git a/packages/wasm-utxo/src/fixed_script_wallet/bitgo_psbt/mod.rs b/packages/wasm-utxo/src/fixed_script_wallet/bitgo_psbt/mod.rs index 95f8895dc51..e2baf6880f5 100644 --- a/packages/wasm-utxo/src/fixed_script_wallet/bitgo_psbt/mod.rs +++ b/packages/wasm-utxo/src/fixed_script_wallet/bitgo_psbt/mod.rs @@ -314,7 +314,7 @@ impl BitGoPsbt { use miniscript::psbt::PsbtExt; match self { - BitGoPsbt::BitcoinLike(ref mut psbt, _network) => { + BitGoPsbt::BitcoinLike(ref mut psbt, network) => { // Use custom bitgo p2trMusig2 input finalization for MuSig2 inputs if p2tr_musig2_input::Musig2Input::is_musig2_input(&psbt.inputs[input_index]) { let mut ctx = p2tr_musig2_input::Musig2Context::new(psbt, input_index) @@ -322,8 +322,16 @@ impl BitGoPsbt { ctx.finalize_input(secp).map_err(|e| e.to_string())?; return Ok(()); } - // other inputs can be finalized using the standard miniscript::psbt::finalize_input - psbt.finalize_inp_mut(secp, input_index) + + // Check if this network uses SIGHASH_FORKID (BCH, BTG, XEC, BSV) + let fork_id = match network.mainnet() { + Network::BitcoinCash | Network::Ecash | Network::BitcoinSV => Some(0u32), + Network::BitcoinGold => Some(79u32), + _ => None, + }; + + // Finalize with fork_id support for FORKID networks + psbt.finalize_inp_mut_with_fork_id(secp, input_index, fork_id) .map_err(|e| e.to_string())?; Ok(()) } @@ -589,19 +597,56 @@ impl BitGoPsbt { ); } - // Sign the replay protection input with legacy P2SH sighash - let sighash_type = miniscript::bitcoin::sighash::EcdsaSighashType::All; - let cache = SighashCache::new(&psbt.unsigned_tx); - let sighash = cache - .legacy_signature_hash(input_index, redeem_script, sighash_type.to_u32()) - .map_err(|e| format!("Failed to compute sighash: {}", e))?; + // Check if this network uses SIGHASH_FORKID (BCH-style networks) + let fork_id = match network.mainnet() { + Network::BitcoinCash | Network::Ecash | Network::BitcoinSV => Some(0u32), + Network::BitcoinGold => Some(79u32), + _ => None, + }; + + // Get input value for BIP143-style sighash (required for FORKID) + let input = &psbt.inputs[input_index]; + let prevout = psbt.unsigned_tx.input[input_index].previous_output; + let value = psbt_wallet_input::get_output_script_and_value(input, prevout) + .map(|(_, v)| v) + .unwrap_or(miniscript::bitcoin::Amount::ZERO); + + // Compute sighash based on network type + let mut cache = SighashCache::new(&psbt.unsigned_tx); + let (message, sighash_type_u32) = if let Some(fork_id) = fork_id { + // BCH-style BIP143 sighash with FORKID + // SIGHASH_ALL | SIGHASH_FORKID = 0x01 | 0x40 = 0x41 + let sighash_type = 0x41u32; + let sighash = cache + .p2wsh_signature_hash_forkid( + input_index, + redeem_script, + value, + sighash_type, + Some(fork_id), + ) + .map_err(|e| format!("Failed to compute FORKID sighash: {}", e))?; + ( + secp256k1::Message::from_digest(sighash.to_byte_array()), + sighash_type, + ) + } else { + // Legacy P2SH sighash for standard Bitcoin + let sighash_type = miniscript::bitcoin::sighash::EcdsaSighashType::All; + let sighash = cache + .legacy_signature_hash(input_index, redeem_script, sighash_type.to_u32()) + .map_err(|e| format!("Failed to compute sighash: {}", e))?; + ( + secp256k1::Message::from_digest(sighash.to_byte_array()), + sighash_type.to_u32(), + ) + }; // Create ECDSA signature - let message = secp256k1::Message::from_digest(sighash.to_byte_array()); let signature = secp.sign_ecdsa(&message, privkey); let ecdsa_sig = EcdsaSignature { signature, - sighash_type, + sighash_type: sighash_type_u32, }; // Add signature to partial_sigs @@ -688,7 +733,18 @@ impl BitGoPsbt { K: miniscript::bitcoin::psbt::GetKey, { match self { - BitGoPsbt::BitcoinLike(ref mut psbt, _network) => psbt.sign(k, secp), + BitGoPsbt::BitcoinLike(ref mut psbt, network) => { + // Check if this network uses SIGHASH_FORKID + // BCH, XEC, BSV: fork_id = 0 + // BTG: fork_id = 79 + match network.mainnet() { + Network::BitcoinCash | Network::Ecash | Network::BitcoinSV => { + psbt.sign_forkid(k, secp, 0) + } + Network::BitcoinGold => psbt.sign_forkid(k, secp, 79), + _ => psbt.sign(k, secp), + } + } BitGoPsbt::Zcash(_zcash_psbt, _network) => { // Return an error indicating Zcash signing is not implemented Err(( @@ -911,6 +967,7 @@ impl BitGoPsbt { use miniscript::bitcoin::{hashes::Hash, sighash::SighashCache}; let psbt = self.psbt(); + let network = self.network(); // Check input index bounds if input_index >= psbt.inputs.len() { @@ -920,10 +977,9 @@ impl BitGoPsbt { let input = &psbt.inputs[input_index]; let prevout = psbt.unsigned_tx.input[input_index].previous_output; - // Get output script from input - let (output_script, _value) = - psbt_wallet_input::get_output_script_and_value(input, prevout) - .map_err(|e| format!("Failed to get output script: {}", e))?; + // Get output script and value from input + let (output_script, value) = psbt_wallet_input::get_output_script_and_value(input, prevout) + .map_err(|e| format!("Failed to get output script: {}", e))?; // Verify this is a replay protection input if !replay_protection.is_replay_protection_input(output_script) { @@ -951,14 +1007,37 @@ impl BitGoPsbt { return Ok(false); }; - // Compute legacy P2SH sighash - let cache = SighashCache::new(&psbt.unsigned_tx); - let sighash = cache - .legacy_signature_hash(input_index, redeem_script, ecdsa_sig.sighash_type.to_u32()) - .map_err(|e| format!("Failed to compute sighash: {}", e))?; + // Check if this network uses SIGHASH_FORKID + let fork_id = match network.mainnet() { + Network::BitcoinCash | Network::Ecash | Network::BitcoinSV => Some(0u32), + Network::BitcoinGold => Some(79u32), + _ => None, + }; + + // Compute sighash based on network type + let mut cache = SighashCache::new(&psbt.unsigned_tx); + let message = if let Some(fork_id) = fork_id { + // BCH-style BIP143 sighash with FORKID + // Use p2wsh_signature_hash_forkid which handles the forkid encoding + let sighash = cache + .p2wsh_signature_hash_forkid( + input_index, + redeem_script, + value, + ecdsa_sig.sighash_type as u32, + Some(fork_id), + ) + .map_err(|e| format!("Failed to compute FORKID sighash: {}", e))?; + secp256k1::Message::from_digest(sighash.to_byte_array()) + } else { + // Legacy P2SH sighash for standard Bitcoin + let sighash = cache + .legacy_signature_hash(input_index, redeem_script, ecdsa_sig.sighash_type) + .map_err(|e| format!("Failed to compute sighash: {}", e))?; + secp256k1::Message::from_digest(sighash.to_byte_array()) + }; - // Verify the signature using the bitcoin crate's built-in verification - let message = secp256k1::Message::from_digest(sighash.to_byte_array()); + // Verify the signature match secp.verify_ecdsa(&message, &ecdsa_sig.signature, &public_key.inner) { Ok(()) => Ok(true), Err(_) => Ok(false), @@ -986,6 +1065,7 @@ impl BitGoPsbt { public_key: CompressedPublicKey, ) -> Result { let psbt = self.psbt(); + let network = self.network(); let input = &psbt.inputs[input_index]; @@ -999,8 +1079,15 @@ impl BitGoPsbt { ); } + // Determine fork_id based on network + let fork_id = match network.mainnet() { + Network::BitcoinCash | Network::Ecash | Network::BitcoinSV => Some(0u32), + Network::BitcoinGold => Some(79u32), + _ => None, + }; + // Fall back to ECDSA signature verification for legacy/SegWit inputs - psbt_wallet_input::verify_ecdsa_signature(secp, psbt, input_index, public_key) + psbt_wallet_input::verify_ecdsa_signature(secp, psbt, input_index, public_key, fork_id) } /// Verify if a valid signature exists for a given extended public key at the specified input index @@ -1584,6 +1671,62 @@ mod tests { Ok(()) } + /// Test that sign_with_privkey β†’ verify_replay_protection_signature roundtrip works. + /// + /// This test guards against sighash algorithm mismatches between signing and verification. + /// Specifically, it catches the bug where sign_with_privkey used legacy_signature_hash + /// for all networks, but verify_replay_protection_signature used p2wsh_signature_hash_forkid + /// for BCH-like networks (BitcoinCash, BitcoinGold, Ecash). + fn assert_p2shp2pk_sign_verify_roundtrip( + unsigned_fixture: &fixtures::PsbtFixture, + wallet_keys: &fixtures::XprvTriple, + input_index: usize, + network: Network, + ) -> Result<(), String> { + // Get the xpriv for signing (user key) + let xpriv = wallet_keys.user_key(); + let privkey = xpriv.private_key; + + // Deserialize the unsigned PSBT + let original_bytes = BASE64_STANDARD + .decode(&unsigned_fixture.psbt_base64) + .map_err(|e| format!("Failed to decode base64: {}", e))?; + let mut psbt = BitGoPsbt::deserialize(&original_bytes, network) + .map_err(|e| format!("Failed to deserialize PSBT: {:?}", e))?; + + // Sign the p2shP2pk input + psbt.sign_with_privkey(input_index, &privkey) + .map_err(|e| format!("Failed to sign p2shP2pk input: {}", e))?; + + // Get the output script for replay protection verification + let psbt_ref = psbt.psbt(); + let input = &psbt_ref.inputs[input_index]; + let prevout = psbt_ref.unsigned_tx.input[input_index].previous_output; + let (output_script, _value) = + psbt_wallet_input::get_output_script_and_value(input, prevout) + .map_err(|e| format!("Failed to get output script: {}", e))?; + + let replay_protection = + crate::fixed_script_wallet::ReplayProtection::new(vec![output_script.clone()]); + + // Verify the signature + let secp = secp256k1::Secp256k1::new(); + let has_valid_signature = psbt + .verify_replay_protection_signature(&secp, input_index, &replay_protection) + .map_err(|e| format!("Failed to verify signature: {}", e))?; + + if !has_valid_signature { + return Err(format!( + "p2shP2pk signβ†’verify roundtrip failed for {:?}. \ + This indicates a sighash mismatch between sign_with_privkey and \ + verify_replay_protection_signature (e.g., SIGHASH_FORKID handling).", + network + )); + } + + Ok(()) + } + fn assert_signature_count( bitgo_psbt: &BitGoPsbt, wallet_keys: &RootWalletKeys, @@ -1685,6 +1828,17 @@ mod tests { &psbt_input_stages.wallet_keys, psbt_input_stages.input_index, )?; + + // Test signβ†’verify roundtrip from unsigned state. + // This verifies that sign_with_privkey uses the correct sighash algorithm: + // - BCH-like networks (BitcoinCash, BitcoinGold, Ecash): SIGHASH_FORKID | SIGHASH_ALL + // - Standard networks: SIGHASH_ALL (legacy) + assert_p2shp2pk_sign_verify_roundtrip( + &psbt_stages.unsigned, + &psbt_input_stages.wallet_keys, + psbt_input_stages.input_index, + network, + )?; } else { assert_full_signed_matches_wallet_scripts( network, @@ -1722,8 +1876,6 @@ mod tests { crate::test_psbt_fixtures!(test_p2sh_p2pk_suite, network, format, { test_wallet_script_type(fixtures::ScriptType::P2shP2pk, network, format).unwrap(); }, ignore: [ - // TODO: sighash support - BitcoinCash, Ecash, BitcoinGold, // TODO: zec support Zcash, ]); @@ -1731,33 +1883,17 @@ mod tests { crate::test_psbt_fixtures!(test_p2sh_suite, network, format, { test_wallet_script_type(fixtures::ScriptType::P2sh, network, format).unwrap(); }, ignore: [ - // TODO: sighash support - BitcoinCash, Ecash, BitcoinGold, // TODO: zec support Zcash, ]); - crate::test_psbt_fixtures!( - test_p2sh_p2wsh_suite, - network, - format, - { - test_wallet_script_type(fixtures::ScriptType::P2shP2wsh, network, format).unwrap(); - }, - // TODO: sighash support - ignore: [BitcoinGold] - ); + crate::test_psbt_fixtures!(test_p2sh_p2wsh_suite, network, format, { + test_wallet_script_type(fixtures::ScriptType::P2shP2wsh, network, format).unwrap(); + }); - crate::test_psbt_fixtures!( - test_p2wsh_suite, - network, - format, - { - test_wallet_script_type(fixtures::ScriptType::P2wsh, network, format).unwrap(); - }, - // TODO: sighash support - ignore: [BitcoinGold] - ); + crate::test_psbt_fixtures!(test_p2wsh_suite, network, format, { + test_wallet_script_type(fixtures::ScriptType::P2wsh, network, format).unwrap(); + }); crate::test_psbt_fixtures!( test_p2tr_legacy_script_path_suite, @@ -1822,7 +1958,7 @@ mod tests { extracted_transaction_hex, fixture_extracted_transaction, "Extracted transaction should match" ); - }, ignore: [BitcoinGold, BitcoinCash, Ecash, Zcash]); + }, ignore: [Zcash]); #[test] fn test_add_paygo_attestation() { @@ -2116,7 +2252,7 @@ mod tests { parsed.spend_amount > 0, "Spend amount should be greater than 0 when there are external outputs" ); - }, ignore: [BitcoinGold, BitcoinCash, Ecash, Zcash]); + }, ignore: [Zcash]); #[test] fn test_serialize_bitcoin_psbt() { diff --git a/packages/wasm-utxo/src/fixed_script_wallet/bitgo_psbt/psbt_wallet_input.rs b/packages/wasm-utxo/src/fixed_script_wallet/bitgo_psbt/psbt_wallet_input.rs index 33120878f2d..a4aaeb3aafc 100644 --- a/packages/wasm-utxo/src/fixed_script_wallet/bitgo_psbt/psbt_wallet_input.rs +++ b/packages/wasm-utxo/src/fixed_script_wallet/bitgo_psbt/psbt_wallet_input.rs @@ -211,6 +211,7 @@ pub fn verify_taproot_script_signature( /// - `psbt`: The PSBT containing the transaction and inputs /// - `input_index`: The index of the input to verify /// - `public_key`: The compressed public key to verify the signature for +/// - `fork_id`: Optional fork ID for BCH/BTG/XEC networks (0 for BCH/XEC, 79 for BTG) /// /// # Returns /// - `Ok(true)` if a valid ECDSA signature exists for the public key @@ -221,6 +222,7 @@ pub fn verify_ecdsa_signature( psbt: &miniscript::bitcoin::psbt::Psbt, input_index: usize, public_key: miniscript::bitcoin::CompressedPublicKey, + fork_id: Option, ) -> Result { use miniscript::bitcoin::{sighash::SighashCache, PublicKey}; @@ -234,9 +236,20 @@ pub fn verify_ecdsa_signature( if let Some(signature) = input.partial_sigs.get(&public_key_inner) { // Create sighash cache and compute sighash for this input let mut cache = SighashCache::new(&psbt.unsigned_tx); - let (sighash_msg, _sighash_type) = match psbt.sighash_ecdsa(input_index, &mut cache) { - Ok(result) => result, - Err(e) => return Err(format!("Failed to compute sighash: {}", e)), + + // Use appropriate sighash computation based on fork_id + let sighash_msg = if let Some(fid) = fork_id { + // BCH/BTG/XEC: use sighash_forkid + let (msg, _) = psbt + .sighash_forkid(input_index, &mut cache, fid) + .map_err(|e| format!("Failed to compute FORKID sighash: {}", e))?; + msg + } else { + // Standard Bitcoin: use sighash_ecdsa + let (msg, _) = psbt + .sighash_ecdsa(input_index, &mut cache) + .map_err(|e| format!("Failed to compute sighash: {}", e))?; + msg }; // Verify the signature From ef0552750f59b4390161f88c6a8f3b2c4124ca40 Mon Sep 17 00:00:00 2001 From: Otto Allmendinger Date: Wed, 17 Dec 2025 11:07:46 +0100 Subject: [PATCH 3/4] feat(wasm-utxo): mark BCH and BTG transaction support as complete Updates the feature status in README to reflect that Bitcoin Cash and Bitcoin Gold now have complete transaction support in the FixedScript wallet. Issue: BTC-2656 Co-authored-by: llm-git --- packages/wasm-utxo/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wasm-utxo/README.md b/packages/wasm-utxo/README.md index f4997bae996..d3fc2b3e9e5 100644 --- a/packages/wasm-utxo/README.md +++ b/packages/wasm-utxo/README.md @@ -20,7 +20,7 @@ This project is under active development. | Descriptor Wallet: Address Support | βœ… Complete | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | | Descriptor Wallet: Transaction Support | βœ… Complete | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | | FixedScript Wallet: Address Generation | βœ… Complete | βœ… Complete | βœ… Complete | βœ… Complete | βœ… Complete | βœ… Complete | βœ… Complete | -| FixedScript Wallet: Transaction Support | βœ… Complete | ⏳ TODO | ⏳ TODO | ⏳ TODO | ⏳ TODO | βœ… Complete | ⏳ TODO | +| FixedScript Wallet: Transaction Support | βœ… Complete | βœ… Complete | βœ… Complete | ⏳ TODO | ⏳ TODO | βœ… Complete | ⏳ TODO | ## Building From 9cfedc8b19392834a181d75e6888deb1b1dfc172 Mon Sep 17 00:00:00 2001 From: Otto Allmendinger Date: Wed, 17 Dec 2025 11:12:59 +0100 Subject: [PATCH 4/4] feat(wasm-utxo): add network support utilities for fixtures Extract fixture network filtering into a utility function. This improves code organization and reduces duplication across test files. Now includes bitcoincash and bitcoingold in fixture networks. Issue: BTC-2656 Co-authored-by: llm-git --- .../test/fixedScript/finalizeExtract.ts | 14 ++------------ .../test/fixedScript/networkSupport.util.ts | 17 +++++++++++++++++ .../parseTransactionWithWalletKeys.ts | 14 ++------------ .../test/fixedScript/signAndVerifySignature.ts | 14 ++------------ 4 files changed, 23 insertions(+), 36 deletions(-) create mode 100644 packages/wasm-utxo/test/fixedScript/networkSupport.util.ts diff --git a/packages/wasm-utxo/test/fixedScript/finalizeExtract.ts b/packages/wasm-utxo/test/fixedScript/finalizeExtract.ts index bb70403229a..47199ada944 100644 --- a/packages/wasm-utxo/test/fixedScript/finalizeExtract.ts +++ b/packages/wasm-utxo/test/fixedScript/finalizeExtract.ts @@ -7,20 +7,10 @@ import { getExtractedTransactionHex, type Fixture, } from "./fixtureUtil.js"; +import { getFixtureNetworks } from "./networkSupport.util.js"; describe("finalize and extract transaction", function () { - const supportedNetworks = utxolib.getNetworkList().filter((network) => { - return ( - utxolib.isMainnet(network) && - network !== utxolib.networks.bitcoincash && - network !== utxolib.networks.bitcoingold && - network !== utxolib.networks.bitcoinsv && - network !== utxolib.networks.ecash && - network !== utxolib.networks.zcash - ); - }); - - supportedNetworks.forEach((network) => { + getFixtureNetworks().forEach((network) => { const networkName = utxolib.getNetworkName(network); describe(`network: ${networkName}`, function () { diff --git a/packages/wasm-utxo/test/fixedScript/networkSupport.util.ts b/packages/wasm-utxo/test/fixedScript/networkSupport.util.ts new file mode 100644 index 00000000000..275e0497b85 --- /dev/null +++ b/packages/wasm-utxo/test/fixedScript/networkSupport.util.ts @@ -0,0 +1,17 @@ +import * as utxolib from "@bitgo/utxo-lib"; + +/** + * Get networks that have psbt fixtures + */ +export function getFixtureNetworks(): utxolib.Network[] { + return utxolib.getNetworkList().filter((network) => { + return ( + // we only have fixtures for mainnet networks + utxolib.isMainnet(network) && + // we don't have fixtures for bitcoinsv since it is not really supported any longer + network !== utxolib.networks.bitcoinsv && + // we do have zcash fixtures but it is not fully implemented yet + network !== utxolib.networks.zcash + ); + }); +} diff --git a/packages/wasm-utxo/test/fixedScript/parseTransactionWithWalletKeys.ts b/packages/wasm-utxo/test/fixedScript/parseTransactionWithWalletKeys.ts index 2533a9f06df..6531fc62442 100644 --- a/packages/wasm-utxo/test/fixedScript/parseTransactionWithWalletKeys.ts +++ b/packages/wasm-utxo/test/fixedScript/parseTransactionWithWalletKeys.ts @@ -11,6 +11,7 @@ import { loadReplayProtectionKeyFromFixture, type Fixture, } from "./fixtureUtil.js"; +import { getFixtureNetworks } from "./networkSupport.util.js"; function getExpectedInputScriptType(fixtureScriptType: string): InputScriptType { // Map fixture types to InputScriptType values @@ -38,18 +39,7 @@ function getOtherWalletKeys(): utxolib.bitgo.RootWalletKeys { } describe("parseTransactionWithWalletKeys", function () { - const supportedNetworks = utxolib.getNetworkList().filter((network) => { - return ( - utxolib.isMainnet(network) && - network !== utxolib.networks.bitcoincash && - network !== utxolib.networks.bitcoingold && - network !== utxolib.networks.bitcoinsv && - network !== utxolib.networks.ecash && - network !== utxolib.networks.zcash - ); - }); - - supportedNetworks.forEach((network) => { + getFixtureNetworks().forEach((network) => { const networkName = utxolib.getNetworkName(network); describe(`network: ${networkName}`, function () { diff --git a/packages/wasm-utxo/test/fixedScript/signAndVerifySignature.ts b/packages/wasm-utxo/test/fixedScript/signAndVerifySignature.ts index 394c457d0b6..cd95a0a47f7 100644 --- a/packages/wasm-utxo/test/fixedScript/signAndVerifySignature.ts +++ b/packages/wasm-utxo/test/fixedScript/signAndVerifySignature.ts @@ -14,6 +14,7 @@ import { type Fixture, loadReplayProtectionKeyFromFixture, } from "./fixtureUtil.js"; +import { getFixtureNetworks } from "./networkSupport.util.js"; type SignatureStage = "unsigned" | "halfsigned" | "fullsigned"; @@ -279,18 +280,7 @@ function runTestsForFixture( } describe("verifySignature", function () { - const supportedNetworks = utxolib.getNetworkList().filter((network) => { - return ( - utxolib.isMainnet(network) && - network !== utxolib.networks.bitcoincash && - network !== utxolib.networks.bitcoingold && - network !== utxolib.networks.bitcoinsv && - network !== utxolib.networks.ecash && - network !== utxolib.networks.zcash - ); - }); - - supportedNetworks.forEach((network) => { + getFixtureNetworks().forEach((network) => { const networkName = utxolib.getNetworkName(network); describe(`network: ${networkName}`, function () {