use std::collections::{HashMap, HashSet}; use std::str::FromStr; use anyhow::{Error, Result}; use rand::{thread_rng, Rng}; use sp_client::bitcoin::consensus::deserialize; use sp_client::bitcoin::psbt::raw; use sp_client::bitcoin::{Amount, OutPoint, Psbt}; use sp_client::constants::{ self, DUST_THRESHOLD, PSBT_SP_ADDRESS_KEY, PSBT_SP_PREFIX, PSBT_SP_SUBTYPE, }; use sp_client::silentpayments::utils::SilentPaymentAddress; use sp_client::spclient::{OwnedOutput, Recipient, SpClient, SpWallet}; pub fn create_transaction( mandatory_inputs: Vec, freezed_utxos: &HashSet, sp_wallet: &SpWallet, mut recipients: Vec, payload: Option>, fee_rate: Amount, fee_payer: Option, // None means sender pays everything ) -> Result { let mut available_outpoints: HashMap = sp_wallet .get_outputs() .to_spendable_list() // filter out freezed utxos .into_iter() .filter(|(outpoint, _)| !freezed_utxos.contains(outpoint)) .collect(); let sum_outputs = recipients .iter() .fold(Amount::from_sat(0), |acc, x| acc + x.amount); let zero_value_recipient = recipients .iter_mut() .find(|r| r.amount == Amount::from_sat(0)); let mut inputs: HashMap = HashMap::new(); let mut total_available = Amount::from_sat(0); for outpoint in mandatory_inputs { let (must_outpoint, must_output) = available_outpoints .remove_entry(&outpoint) .ok_or_else(|| Error::msg(format!("Mandatory outpoint unknown: {}", outpoint)))?; total_available += must_output.amount; inputs.insert(must_outpoint, must_output); } let fee_provision = sum_outputs.checked_div(10).unwrap(); for (outpoint, output) in available_outpoints { if total_available > sum_outputs.checked_add(fee_provision).unwrap() { break; } total_available += output.amount; inputs.insert(outpoint, output); } if total_available <= sum_outputs.checked_add(fee_provision).unwrap() { return Err(Error::msg("Not enough available funds")); } if let Some(recipient) = zero_value_recipient { // update the amount for the recipient recipient.amount = total_available; } let mut commitment = [0u8; 32]; if let Some(ref p) = payload { commitment.copy_from_slice(&p); } else { thread_rng().fill(&mut commitment); } let mut new_psbt = sp_wallet .get_client() .create_new_psbt(inputs, recipients, Some(&commitment))?; let sender_address = sp_wallet.get_client().get_receiving_address(); let change_address = sp_wallet.get_client().sp_receiver.get_change_address(); if let Some(address) = fee_payer { SpClient::set_fees(&mut new_psbt, fee_rate, address)?; } else { let candidates: Vec> = new_psbt .outputs .iter() .map(|o| { if let Some(value) = o.proprietary.get(&raw::ProprietaryKey { prefix: PSBT_SP_PREFIX.as_bytes().to_vec(), subtype: PSBT_SP_SUBTYPE, key: PSBT_SP_ADDRESS_KEY.as_bytes().to_vec(), }) { let candidate: String = SilentPaymentAddress::try_from(deserialize::(value).unwrap()) .unwrap() .into(); return Some(candidate); } else { return None; } }) .collect(); let fee_set = candidates.iter().filter_map(|candidate_opt| { candidate_opt.as_ref().and_then(|c| { if *c == change_address { Some(SpClient::set_fees(&mut new_psbt, fee_rate, change_address.clone())) } else if *c == sender_address { Some(SpClient::set_fees(&mut new_psbt, fee_rate, sender_address.clone())) } else { None } }) }).find_map(|result| result.ok()); if fee_set.is_none() { return Err(Error::msg("Must specify payer for fee")); } }; let partial_secret = sp_wallet .get_client() .get_partial_secret_from_psbt(&new_psbt)?; sp_wallet .get_client() .fill_sp_outputs(&mut new_psbt, partial_secret)?; let mut aux_rand = [0u8; 32]; thread_rng().fill(&mut aux_rand); let mut signed = sp_wallet.get_client().sign_psbt(new_psbt, &aux_rand)?; SpClient::finalize_psbt(&mut signed)?; Ok(signed) } pub fn map_outputs_to_sp_address(psbt_str: &str) -> Result>> { let psbt = Psbt::from_str(&psbt_str)?; let mut res: HashMap> = HashMap::new(); for (i, output) in psbt.outputs.iter().enumerate() { if let Some(value) = output.proprietary.get(&raw::ProprietaryKey { prefix: constants::PSBT_SP_PREFIX.as_bytes().to_vec(), subtype: constants::PSBT_SP_SUBTYPE, key: constants::PSBT_SP_ADDRESS_KEY.as_bytes().to_vec(), }) { let sp_address = SilentPaymentAddress::try_from(deserialize::(value)?)?; if let Some(vouts) = res.get_mut::(&sp_address.into()) { vouts.push(i); } else { res.insert(sp_address.into(), vec![i]); } } else { // Not a sp output continue; } } Ok(res) } // #[cfg(test)] // mod tests { // use std::io::Write; // use crate::pcd::Pcd; // use crate::prd::{Prd, PrdType}; // use crate::process::{Member, Process, Role, ValidationRules}; // use super::*; // use serde_json::Value; // use sp_client::bitcoin::hashes::{sha256, Hash}; // use sp_client::bitcoin::hex::FromHex; // use sp_client::bitcoin::secp256k1::PublicKey; // use sp_client::bitcoin::{ScriptBuf, Transaction, Txid}; // use sp_client::silentpayments::utils::receiving::{ // calculate_tweak_data, get_pubkey_from_input, // }; // const ALICE_WALLET: &str = "{\"tx_history\": [],\"client\":{\"network\":\"regtest\",\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]}},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"}}}}"; // const BOB_WALLET: &str = "{\"tx_history\": [],\"client\":{\"network\":\"regtest\",\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]}},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":\"Unspent\"}}}}"; // const ALICE_WALLET_CONFIRMATION: &str = "{\"tx_history\": [],\"client\":{\"network\":\"regtest\",\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]}},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"148e0faa2f203b6e9488e2da696d8a49ebff4212946672f0bb072ced0909360d\"}},\"148e0faa2f203b6e9488e2da696d8a49ebff4212946672f0bb072ced0909360d:1\":{\"blockheight\":0,\"tweak\":\"28994b2f2ee8e5f35d6d2dcdee1580d0455fe3dc37f81e0a36864473ee86f5c4\",\"amount\":3937246,\"script\":\"51207d06144e982b6fd38a85d6152f1f95746b059553258a31e04df97fe6b5f19ea1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"}}}}"; // const BOB_WALLET_CONFIRMATION: &str = "{\"tx_history\": [],\"client\":{\"network\":\"regtest\",\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]}},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"148e0faa2f203b6e9488e2da696d8a49ebff4212946672f0bb072ced0909360d:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":\"Unspent\"},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":\"Unspent\"}}}}"; // const ALICE_WALLET_ANSWER: &str = "{\"tx_history\": [],\"client\":{\"network\":\"regtest\",\"label\":\"default\",\"scan_sk\":\"e3d8922a41a7cb1a84a90f4334e987bb5ea2df6a1fdf44f789b5302de119f9e2\",\"spend_key\":{\"Secret\":\"93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,104,242,105,185,6,124,208,34,44,149,52,163,38,63,221,150,12,198,24,95,143,126,235,37,149,233,88,118,32,86,233,152],\"spend_pubkey\":[3,198,82,196,243,12,59,126,109,143,144,157,128,176,168,94,54,134,232,139,115,102,11,178,128,244,239,251,40,228,67,153,72],\"change_label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"labels\":[[\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",[2,244,223,255,57,50,216,27,133,112,138,69,120,126,85,110,6,242,141,33,136,191,82,164,241,54,179,115,84,161,145,174,154]]]}},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"148e0faa2f203b6e9488e2da696d8a49ebff4212946672f0bb072ced0909360d:1\":{\"blockheight\":0,\"tweak\":\"28994b2f2ee8e5f35d6d2dcdee1580d0455fe3dc37f81e0a36864473ee86f5c4\",\"amount\":3937246,\"script\":\"51207d06144e982b6fd38a85d6152f1f95746b059553258a31e04df97fe6b5f19ea1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"bc207c02bc4f1d4359fcd604296c0938bf1e6ff827662a56410676b8cbd768d9:0\":{\"blockheight\":0,\"tweak\":\"3bf77beab9c053e1ed974288d5d246962376d2badddc623af1f2ef7af57067b7\",\"amount\":1046,\"script\":\"5120646bdb98d89a2573acc6064a5c806d00e34beb65588c91a32733b62255b4dafa\",\"label\":null,\"spend_status\":\"Unspent\"},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"148e0faa2f203b6e9488e2da696d8a49ebff4212946672f0bb072ced0909360d\"}}}}}"; // const BOB_WALLET_ANSWER: &str = "{\"tx_history\": [],\"client\":{\"network\":\"regtest\",\"label\":\"default\",\"scan_sk\":\"0de90b7195c1380d5fde13de3f1d66d53423a9896314839e36ba672653af60b4\",\"spend_key\":{\"Secret\":\"affe686075ecbe17b8ce7de45ec31314804259d0a4bc1c863de21ffd6dc598f8\"},\"mnemonic\":null,\"sp_receiver\":{\"version\":0,\"network\":\"Regtest\",\"scan_pubkey\":[2,85,96,92,243,247,237,192,205,9,178,146,101,237,132,232,15,2,69,138,31,118,76,140,142,207,90,13,192,94,254,150,133],\"spend_pubkey\":[3,5,157,91,250,169,41,61,190,37,30,98,152,253,180,138,250,86,162,102,82,148,130,220,44,153,127,83,43,246,93,17,232],\"change_label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"labels\":[[\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",[2,237,237,247,213,154,87,34,239,168,235,87,122,152,94,41,35,101,184,201,58,201,6,185,58,157,52,208,129,167,2,224,198]]]}},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":\"Unspent\"},\"148e0faa2f203b6e9488e2da696d8a49ebff4212946672f0bb072ced0909360d:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"bc207c02bc4f1d4359fcd604296c0938bf1e6ff827662a56410676b8cbd768d9\"}}}}}"; // const ALICE_ADDRESS: &str = "sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q"; // const BOB_ADDRESS: &str = "sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u"; // const FEE_RATE: Amount = Amount::from_sat(1); // const KEY: &str = "442a5ea418921c4aa8ce3f7a95427d9450059a3ac11db3dced9abb709b2d9f42"; // const INITIAL_COMMIT_TX: &str = "bc7d2ef1820cf67edb900e4c59cae6c692663cd690e691a55df919f002ede841"; // fn helper_get_tweak_data(tx: &Transaction, spk: ScriptBuf) -> PublicKey { // let prevout = tx.input.get(0).unwrap().to_owned(); // let outpoint_data = ( // prevout.previous_output.txid.to_string(), // prevout.previous_output.vout, // ); // let input_pubkey = // get_pubkey_from_input(&vec![], &prevout.witness.to_vec(), spk.as_bytes()).unwrap(); // let tweak_data = // calculate_tweak_data(&vec![&input_pubkey.unwrap()], &vec![outpoint_data]).unwrap(); // tweak_data // } // fn helper_create_commitment(payload_to_hash: String) -> sha256::Hash { // let mut engine = sha256::HashEngine::default(); // engine.write_all(&payload_to_hash.as_bytes()).unwrap(); // let hash = sha256::Hash::from_engine(engine); // hash // } // #[test] // fn it_creates_notification_transaction() { // let recipient = Recipient { // address: BOB_ADDRESS.to_owned(), // amount: Amount::from_sat(1200), // nb_outputs: 1, // }; // let mut alice_wallet: SpWallet = serde_json::from_str(ALICE_WALLET).unwrap(); // let mut bob_wallet: SpWallet = serde_json::from_str(BOB_WALLET).unwrap(); // let pcd = Pcd::new(Value::String("TEST".to_owned())); // let pcd_hash = helper_create_commitment(pcd.to_string()); // let mut key = [0u8; 32]; // key.copy_from_slice(&Vec::from_hex(KEY).unwrap()); // let alice_member = Member::new( // "alice".to_owned(), // alice_wallet.get_client().get_receiving_address().try_into().unwrap(), // alice_wallet.get_client().sp_receiver.get_change_address().try_into().unwrap(), // Role::Admin, // ); // let bob_member = Member::new( // "bob".to_owned(), // bob_wallet.get_client().get_receiving_address().try_into().unwrap(), // bob_wallet.get_client().sp_receiver.get_change_address().try_into().unwrap(), // Role::User, // ); // let validation_rules = ValidationRules::new(0.5, Role::User); // let pcd_template = serde_json::json!({ // "int": 0, // "string": "exemple_data", // "array": [ // "element1", // "element2" // ] // }); // let process = Process::new( // "default".to_owned(), // vec![alice_member, bob_member], // validation_rules, // Txid::from_str(INITIAL_COMMIT_TX).unwrap(), // "".to_owned(), // "".to_owned(), // "".to_owned(), // pcd_template, // ); // let prd = Prd::new( // PrdType::Update, // process, // ALICE_ADDRESS.try_into().unwrap(), // key, // pcd_hash, // ).unwrap(); // let commitment = helper_create_commitment(serde_json::to_string(&prd).unwrap()); // let psbt = create_transaction( // &vec![], // &HashSet::new(), // &alice_wallet, // vec![recipient], // Some(commitment.as_byte_array().to_vec()), // FEE_RATE, // None, // ) // .unwrap(); // let final_tx = psbt.extract_tx().unwrap(); // let spk = "51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1"; // let tweak_data = helper_get_tweak_data(&final_tx, ScriptBuf::from_hex(spk).unwrap()); // // Check that Alice and Bob are both able to find that transaction // let alice_update = alice_wallet // .update_wallet_with_transaction(&final_tx, 0, tweak_data) // .unwrap(); // assert!(alice_update.len() > 0); // let bob_update = bob_wallet // .update_wallet_with_transaction(&final_tx, 0, tweak_data) // .unwrap(); // assert!(bob_update.len() > 0); // println!("{:?}", alice_wallet.get_outputs().to_outpoints_list()); // println!("{:?}", bob_wallet.get_outputs().to_outpoints_list()); // } // #[test] // fn it_creates_confirmation_transaction() { // let mut alice_wallet: SpWallet = serde_json::from_str(ALICE_WALLET_CONFIRMATION).unwrap(); // let mut bob_wallet: SpWallet = serde_json::from_str(BOB_WALLET_CONFIRMATION).unwrap(); // // Bob must spend notification output // let (confirmation_outpoint, _) = bob_wallet // .get_outputs() // .get_outpoint( // OutPoint::from_str( // "148e0faa2f203b6e9488e2da696d8a49ebff4212946672f0bb072ced0909360d:0", // ) // .unwrap(), // ) // .unwrap(); // let recipient = Recipient { // address: ALICE_ADDRESS.to_owned(), // amount: Amount::from_sat(0), // nb_outputs: 1, // }; // let psbt = create_transaction( // &vec![&confirmation_outpoint], // &HashSet::new(), // &bob_wallet, // vec![recipient], // None, // FEE_RATE, // Some(ALICE_ADDRESS.to_owned()), // ) // .unwrap(); // let final_tx = psbt.extract_tx().unwrap(); // // println!( // // "{}", // // serialize::(&final_tx).to_lower_hex_string() // // ); // let spk = "512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c"; // let tweak_data = helper_get_tweak_data(&final_tx, ScriptBuf::from_hex(spk).unwrap()); // // Check that Alice and Bob are both able to find that transaction // let alice_update = alice_wallet // .update_wallet_with_transaction(&final_tx, 0, tweak_data) // .unwrap(); // assert!(alice_update.len() > 0); // let bob_update = bob_wallet // .update_wallet_with_transaction(&final_tx, 0, tweak_data) // .unwrap(); // assert!(bob_update.len() > 0); // println!("{:?}", alice_wallet.get_outputs().to_outpoints_list()); // println!("{:?}", bob_wallet.get_outputs().to_outpoints_list()); // } // #[test] // fn it_creates_answer_transaction() { // let mut alice_wallet: SpWallet = serde_json::from_str(ALICE_WALLET_ANSWER).unwrap(); // let mut bob_wallet: SpWallet = serde_json::from_str(BOB_WALLET_ANSWER).unwrap(); // // Bob must spend notification output // let (confirmation_outpoint, _) = alice_wallet // .get_outputs() // .get_outpoint( // OutPoint::from_str( // "bc207c02bc4f1d4359fcd604296c0938bf1e6ff827662a56410676b8cbd768d9:0", // ) // .unwrap(), // ) // .unwrap(); // let recipient = Recipient { // address: BOB_ADDRESS.to_owned(), // amount: Amount::from_sat(0), // nb_outputs: 1, // }; // let psbt = create_transaction( // &vec![&confirmation_outpoint], // &HashSet::new(), // &alice_wallet, // vec![recipient], // None, // FEE_RATE, // Some(BOB_ADDRESS.to_owned()), // ) // .unwrap(); // let final_tx = psbt.extract_tx().unwrap(); // // println!("{}", serialize::(&final_tx).to_lower_hex_string()); // let spk = "5120646bdb98d89a2573acc6064a5c806d00e34beb65588c91a32733b62255b4dafa"; // let tweak_data = helper_get_tweak_data(&final_tx, ScriptBuf::from_hex(spk).unwrap()); // // Check that Alice and Bob are both able to find that transaction // let alice_update = alice_wallet // .update_wallet_with_transaction(&final_tx, 0, tweak_data) // .unwrap(); // assert!(alice_update.len() > 0); // let bob_update = bob_wallet // .update_wallet_with_transaction(&final_tx, 0, tweak_data) // .unwrap(); // assert!(bob_update.len() > 0); // println!("{:?}", alice_wallet.get_outputs().to_outpoints_list()); // println!("{:?}", bob_wallet.get_outputs().to_outpoints_list()); // } // }