Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions packages/wasm-utxo/src/bip322/bitgo_psbt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,28 +494,31 @@ fn build_output_script_from_pubkeys(
) -> Result<ScriptBuf, String> {
match script_type {
"p2sh" => {
let redeem_script = build_multisig_script_2_of_3(pubkeys);
let redeem_script = build_multisig_script_2_of_3(pubkeys)
.map_err(|error| error.to_string())?;
Ok(redeem_script.to_p2sh())
}
"p2shP2wsh" => {
let witness_script = build_multisig_script_2_of_3(pubkeys);
let witness_script = build_multisig_script_2_of_3(pubkeys)
.map_err(|error| error.to_string())?;
let redeem_script = witness_script.to_p2wsh();
Ok(redeem_script.to_p2sh())
}
"p2wsh" => {
let witness_script = build_multisig_script_2_of_3(pubkeys);
let witness_script = build_multisig_script_2_of_3(pubkeys)
.map_err(|error| error.to_string())?;
Ok(witness_script.to_p2wsh())
}
"p2tr" => {
let script_p2tr = ScriptP2tr::new(pubkeys, false);
let script_p2tr = ScriptP2tr::new(pubkeys, false).map_err(|error| error.to_string())?;
Ok(script_p2tr.output_script())
}
"p2trMusig2" => {
let script_p2tr = ScriptP2tr::new(pubkeys, true);
let script_p2tr = ScriptP2tr::new(pubkeys, true).map_err(|error| error.to_string())?;
Ok(script_p2tr.output_script())
}
"p2mr" => {
let script_p2mr = ScriptP2mr::new(pubkeys);
let script_p2mr = ScriptP2mr::new(pubkeys).map_err(|error| error.to_string())?;
Ok(script_p2mr.output_script())
}
_ => Err(format!(
Expand Down
20 changes: 20 additions & 0 deletions packages/wasm-utxo/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use core::fmt;

use crate::fixed_script_wallet::bitgo_psbt::zcash_psbt::VerifyV6SignatureError;
use crate::fixed_script_wallet::bitgo_psbt::ParseTransactionError;
use crate::fixed_script_wallet::wallet_scripts::BitGoMusigError;
use crate::fixed_script_wallet::WalletKeyError;

pub trait WasmErrorCode {
fn code(&self) -> String;
Expand All @@ -28,6 +30,8 @@ pub enum WasmUtxoError {
ZcashV6(crate::zcash::v6::ZcashV6Error),
Ironwood(crate::zcash::ironwood_build::IronwoodBuildError),
VerifyV6Signature(VerifyV6SignatureError),
WalletKey(WalletKeyError),
BitGoMusig(BitGoMusigError),
}

impl std::error::Error for WasmUtxoError {}
Expand All @@ -41,6 +45,8 @@ impl fmt::Display for WasmUtxoError {
WasmUtxoError::ZcashV6(e) => write!(f, "{}", e),
WasmUtxoError::Ironwood(e) => write!(f, "{}", e),
WasmUtxoError::VerifyV6Signature(e) => write!(f, "{}", e),
WasmUtxoError::WalletKey(e) => write!(f, "{}", e),
WasmUtxoError::BitGoMusig(e) => write!(f, "{}", e),
}
}
}
Expand All @@ -54,6 +60,8 @@ impl WasmErrorCode for WasmUtxoError {
WasmUtxoError::ZcashV6(e) => e.code(),
WasmUtxoError::Ironwood(e) => e.code(),
WasmUtxoError::VerifyV6Signature(e) => e.code(),
WasmUtxoError::WalletKey(e) => e.code(),
WasmUtxoError::BitGoMusig(e) => e.code(),
}
}
}
Expand Down Expand Up @@ -117,6 +125,18 @@ impl From<VerifyV6SignatureError> for WasmUtxoError {
}
}

impl From<WalletKeyError> for WasmUtxoError {
fn from(err: WalletKeyError) -> Self {
WasmUtxoError::WalletKey(err)
}
}

impl From<BitGoMusigError> for WasmUtxoError {
fn from(err: BitGoMusigError) -> Self {
WasmUtxoError::BitGoMusig(err)
}
}

impl WasmUtxoError {
pub fn new(s: &str) -> WasmUtxoError {
WasmUtxoError::StringError(s.to_string())
Expand Down
39 changes: 26 additions & 13 deletions packages/wasm-utxo/src/fixed_script_wallet/bitgo_psbt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1277,30 +1277,38 @@ impl BitGoPsbt {
// We reuse taproot PSBT fields (tap_tree, tap_key_origins) since
// all tested PSBT parsers accept them on witness v2 outputs.
// No tap_internal_key (P2MR has no internal key or tweak).
psbt_output.tap_tree = Some(build_tap_tree_for_output(&pub_triple, false));
psbt_output.tap_tree = Some(
build_tap_tree_for_output(&pub_triple, false)
.map_err(|error| error.to_string())?,
);
psbt_output.tap_key_origins = create_tap_bip32_derivation_for_output(
wallet_keys,
chain,
derivation_index,
&pub_triple,
false,
);
)
.map_err(|error| error.to_string())?;
}
WalletScripts::P2trLegacy(script) | WalletScripts::P2trMusig2(script) => {
let is_musig2 = matches!(scripts, WalletScripts::P2trMusig2(_));

let internal_key = script.spend_info.internal_key();
psbt_output.tap_internal_key = Some(internal_key);

psbt_output.tap_tree = Some(build_tap_tree_for_output(&pub_triple, is_musig2));
psbt_output.tap_tree = Some(
build_tap_tree_for_output(&pub_triple, is_musig2)
.map_err(|error| error.to_string())?,
);

psbt_output.tap_key_origins = create_tap_bip32_derivation_for_output(
wallet_keys,
chain,
derivation_index,
&pub_triple,
is_musig2,
);
)
.map_err(|error| error.to_string())?;
}
}

Expand Down Expand Up @@ -3673,7 +3681,7 @@ pub fn to_wallet_keys(

for perm in &XPUB_TRIPLE_PERMUTATIONS {
let permuted = [xpubs[perm[0]], xpubs[perm[1]], xpubs[perm[2]]];
let wallet_keys = RootWalletKeys::new(permuted);
let wallet_keys = RootWalletKeys::new(permuted).map_err(|error| error.to_string())?;

let all_match = wallet_inputs.iter().all(|(tx_input, psbt_input)| {
let output_script = psbt_wallet_input::get_output_script_and_value(
Expand Down Expand Up @@ -3770,7 +3778,8 @@ mod tests {
use crate::fixed_script_wallet::test_utils::get_test_wallet_keys;
use crate::zcash::NetworkUpgrade;

let keys = RootWalletKeys::new(get_test_wallet_keys("test_zcash_at_height"));
let keys = RootWalletKeys::new(get_test_wallet_keys("test_zcash_at_height"))
.expect("test wallet xpubs are distinct");

// Test with Nu5 activation height (mainnet)
let nu5_height = NetworkUpgrade::Nu5.mainnet_activation_height();
Expand Down Expand Up @@ -3822,7 +3831,8 @@ mod tests {
use crate::fixed_script_wallet::test_utils::get_test_wallet_keys;
use crate::zcash::NetworkUpgrade;

let keys = RootWalletKeys::new(get_test_wallet_keys("test_zcash_at_height"));
let keys = RootWalletKeys::new(get_test_wallet_keys("test_zcash_at_height"))
.expect("test wallet xpubs are distinct");

// Test with Nu5 activation height (testnet)
let nu5_height = NetworkUpgrade::Nu5.testnet_activation_height();
Expand Down Expand Up @@ -5341,7 +5351,8 @@ mod tests {
use crate::fixed_script_wallet::test_utils::get_test_wallet_keys;
let other_wallet_keys = crate::fixed_script_wallet::RootWalletKeys::new(
get_test_wallet_keys("too many secrets"),
);
)
.expect("test wallet xpubs are distinct");

// Load the original PSBT and parse inputs/outputs using existing methods
let original_psbt = fixture
Expand Down Expand Up @@ -5724,7 +5735,8 @@ mod tests {
use std::str::FromStr;

let wallet_keys =
crate::fixed_script_wallet::RootWalletKeys::new(get_test_wallet_keys("doge_1e19"));
crate::fixed_script_wallet::RootWalletKeys::new(get_test_wallet_keys("doge_1e19"))
.expect("test wallet xpubs are distinct");

let mut psbt = BitGoPsbt::new(Network::Dogecoin, &wallet_keys, Some(2), Some(0));

Expand Down Expand Up @@ -5810,7 +5822,7 @@ mod tests {
use crate::fixed_script_wallet::test_utils::get_test_wallet_keys;

let xpubs = get_test_wallet_keys("test_global_xpubs");
let wallet_keys = RootWalletKeys::new(xpubs);
let wallet_keys = RootWalletKeys::new(xpubs).expect("test wallet xpubs are distinct");
let psbt = BitGoPsbt::new(Network::Bitcoin, &wallet_keys, Some(2), Some(0));

let global = psbt.get_global_xpubs().expect("should have global xpubs");
Expand All @@ -5828,7 +5840,7 @@ mod tests {
use miniscript::bitcoin::hashes::Hash;

let xpubs = get_test_wallet_keys("test_to_wallet_keys");
let wallet_keys = RootWalletKeys::new(xpubs);
let wallet_keys = RootWalletKeys::new(xpubs).expect("test wallet xpubs are distinct");
let mut psbt = BitGoPsbt::new(Network::Bitcoin, &wallet_keys, Some(2), Some(0));

let txid = Txid::all_zeros();
Expand All @@ -5855,7 +5867,7 @@ mod tests {
use miniscript::bitcoin::hashes::Hash;

let xpubs = get_test_wallet_keys("test_to_wallet_keys_shuffled");
let wallet_keys = RootWalletKeys::new(xpubs);
let wallet_keys = RootWalletKeys::new(xpubs).expect("test wallet xpubs are distinct");
let mut psbt = BitGoPsbt::new(Network::Bitcoin, &wallet_keys, Some(2), Some(0));

let txid = Txid::all_zeros();
Expand Down Expand Up @@ -5908,7 +5920,8 @@ mod tests {
let seed = "zcash_block_aligned";
let secp = Secp256k1::new();

let wallet_keys = RootWalletKeys::new(get_test_wallet_keys(seed));
let wallet_keys = RootWalletKeys::new(get_test_wallet_keys(seed))
.expect("test wallet xpubs are distinct");

let sapling_height = NetworkUpgrade::Sapling.testnet_activation_height();
let mut psbt = BitGoPsbt::new_zcash_at_height(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1141,7 +1141,7 @@ pub mod test_helpers {
.collect::<Vec<_>>()
.try_into()
.expect("Failed to convert to XpubTriple");
RootWalletKeys::new(triple)
RootWalletKeys::new(triple).expect("test wallet xpubs are distinct")
}

crate::test_psbt_fixtures!(test_validate_psbt_wallet_inputs, network, format, {
Expand Down Expand Up @@ -1250,7 +1250,7 @@ mod infer_tests {
#[test]
fn tier1_witness_script_2_of_3_no_derivations_is_p2wsh() {
let triple = test_pub_triple();
let multisig = build_multisig_script_2_of_3(&triple);
let multisig = build_multisig_script_2_of_3(&triple).unwrap();
let input = p2wsh_input(multisig);

let result = infer_input_script_type(&input, dummy_prevout()).expect("should classify");
Expand All @@ -1260,7 +1260,7 @@ mod infer_tests {
#[test]
fn tier1_witness_script_plus_redeem_script_is_p2shp2wsh() {
let triple = test_pub_triple();
let multisig = build_multisig_script_2_of_3(&triple);
let multisig = build_multisig_script_2_of_3(&triple).unwrap();
// P2shP2wsh: witness_script = multisig, redeem_script = P2WSH wrapper,
// output = P2SH of the P2WSH wrapper.
let redeem_script = multisig.to_p2wsh();
Expand Down Expand Up @@ -1300,7 +1300,7 @@ mod infer_tests {
#[test]
fn tier1_redeem_script_2_of_3_no_derivations_is_p2sh() {
let triple = test_pub_triple();
let multisig = build_multisig_script_2_of_3(&triple);
let multisig = build_multisig_script_2_of_3(&triple).unwrap();
let output_script = multisig.to_p2sh();
let input = psbt::Input {
redeem_script: Some(multisig),
Expand All @@ -1318,7 +1318,7 @@ mod infer_tests {
#[test]
fn bare_input_with_only_witness_utxo_errors() {
let triple = test_pub_triple();
let output_script = build_multisig_script_2_of_3(&triple).to_p2wsh();
let output_script = build_multisig_script_2_of_3(&triple).unwrap().to_p2wsh();
let input = input_with_output(output_script);

let result = infer_input_script_type(&input, dummy_prevout());
Expand All @@ -1329,7 +1329,7 @@ mod infer_tests {
fn witness_script_shape_cross_check_failure_errors() {
// witness_script parses as 2-of-3, but output is P2SH (not P2WSH).
let triple = test_pub_triple();
let multisig = build_multisig_script_2_of_3(&triple);
let multisig = build_multisig_script_2_of_3(&triple).unwrap();
let p2sh_output = multisig.to_p2sh();
let input = psbt::Input {
witness_script: Some(multisig),
Expand Down
Loading
Loading