diff --git a/src/api.rs b/src/api.rs index 5293d68..bbaf583 100644 --- a/src/api.rs +++ b/src/api.rs @@ -21,12 +21,18 @@ use sdk_common::sp_client::bitcoin::hashes::{sha256, Hash}; use sdk_common::sp_client::bitcoin::hex::{ parse, DisplayHex, FromHex, HexToArrayError, HexToBytesError, }; -use sdk_common::sp_client::bitcoin::key::Secp256k1; +use sdk_common::sp_client::bitcoin::key::{Parity, Secp256k1}; use sdk_common::sp_client::bitcoin::network::ParseNetworkError; +use sdk_common::sp_client::bitcoin::psbt::raw; use sdk_common::sp_client::bitcoin::secp256k1::ecdh::shared_secret_point; -use sdk_common::sp_client::bitcoin::secp256k1::{PublicKey, SecretKey}; +use sdk_common::sp_client::bitcoin::secp256k1::{PublicKey, Scalar, SecretKey}; use sdk_common::sp_client::bitcoin::transaction::ParseOutPointError; -use sdk_common::sp_client::bitcoin::{Amount, Network, OutPoint, Psbt, Transaction, Txid}; +use sdk_common::sp_client::bitcoin::{ + Amount, Network, OutPoint, Psbt, Transaction, Txid, XOnlyPublicKey, +}; +use sdk_common::sp_client::constants::{ + DUST_THRESHOLD, PSBT_SP_ADDRESS_KEY, PSBT_SP_PREFIX, PSBT_SP_SUBTYPE, +}; use sdk_common::sp_client::silentpayments::utils as sp_utils; use sdk_common::sp_client::silentpayments::{ utils::{Network as SpNetwork, SilentPaymentAddress}, @@ -45,15 +51,13 @@ use sdk_common::network::{ }; use sdk_common::silentpayments::{create_transaction, map_outputs_to_sp_address}; -use crate::wallet::generate_sp_wallet; +use crate::wallet::{generate_sp_wallet, lock_freezed_utxos}; use sdk_common::sp_client::spclient::{ derive_keys_from_seed, OutputList, OutputSpendStatus, OwnedOutput, Recipient, SpClient, }; use sdk_common::sp_client::spclient::{SpWallet, SpendKey}; -use crate::user::{ - lock_local_device, lock_spending_client, Device, RevokeOutput, LOCAL_DEVICE, SPENDING_CLIENT, -}; +use crate::user::{lock_local_device, set_new_device, Device, LOCAL_DEVICE}; use crate::{images, lock_messages, CACHEDMESSAGES}; use crate::process::Process; @@ -179,116 +183,98 @@ pub fn get_address() -> ApiResult { let local_device = lock_local_device()?; Ok(local_device - .get_watch_only() + .get_wallet() .get_client() .get_receiving_address()) } #[wasm_bindgen] pub fn restore_device_from_sp_wallet(sp_wallet: String) -> ApiResult { - let wallet: SpWallet = serde_json::from_str(&sp_wallet)?; + let sp_wallet: SpWallet = serde_json::from_str(&sp_wallet)?; - let mut device = Device::new( - wallet.get_client().get_scan_key(), - wallet.get_client().get_spend_key().into(), - wallet.get_client().get_network(), - ); - - let birthday = wallet.get_outputs().get_birthday(); - let outputs = wallet.get_outputs().to_outpoints_list(); - device - .get_watch_only_mut() - .get_mut_outputs() - .set_birthday(birthday); - device - .get_watch_only_mut() - .get_mut_outputs() - .extend_from(outputs); - - let json_return = serde_json::to_string(&device)?; - - // Set the LOCAL_DEVICE const with the new value - let mut local_device = lock_local_device()?; - - if *local_device.get_watch_only().get_client() == SpClient::default() { - *local_device = device; - } else { - return Err(ApiError { - message: "device is already initialized".to_owned(), - }); - } - - // Set the LOGGED_WALLET with the new wallet to keep it in memory while we wait for the linking - let mut spending_client = lock_spending_client()?; - - if *spending_client == SpClient::default() { - *spending_client = wallet.get_client().clone(); - } else { - return Err(ApiError { - message: "device is already initialized".to_owned(), - }); - } - - Ok(json_return) -} - -#[wasm_bindgen] -pub fn create_new_device(birthday: u32, network_str: String) -> ApiResult { - let network = Network::from_core_arg(&network_str)?; - let wallet = generate_sp_wallet(None, Network::Regtest)?; - - // Let's create the new device - let mut device = Device::new( - wallet.get_client().get_scan_key(), - wallet.get_client().get_spend_key().into(), - network, - ); - - device - .get_watch_only_mut() - .get_mut_outputs() - .set_birthday(birthday); - - let our_address = device.get_watch_only().get_client().get_receiving_address(); - - // Set the LOCAL_DEVICE const with the new value - let mut local_device = lock_local_device()?; - - if *local_device.get_watch_only().get_client() == SpClient::default() { - *local_device = device; - } else { - return Err(ApiError { - message: "device is already initialized".to_owned(), - }); - } - - // Set the LOGGED_WALLET with the new wallet to keep it in memory while we wait for the linking - let mut spending_client = lock_spending_client()?; - - if *spending_client == SpClient::default() { - *spending_client = wallet.get_client().clone(); - } else { - return Err(ApiError { - message: "device is already initialized".to_owned(), - }); - } + let our_address = set_new_device(sp_wallet)?; Ok(our_address) } #[wasm_bindgen] -pub fn pair_device( - spend_sk_cipher: Vec, - linked_with: String, - revokation_output: String, -) -> ApiResult<()> { - let mut device = lock_local_device()?; +pub fn restore_device(device_str: String) -> ApiResult<()> { + let device: Device = serde_json::from_str(&device_str)?; - device.new_link( - spend_sk_cipher, - linked_with.try_into()?, - OutPoint::from_str(&revokation_output)?, - ); + let mut local_device = lock_local_device()?; + + *local_device = device; + + Ok(()) +} + +#[wasm_bindgen] +pub fn create_new_device(birthday: u32, network_str: String) -> ApiResult { + let sp_wallet = generate_sp_wallet(None, Network::from_core_arg(&network_str)?)?; + + let our_address = set_new_device(sp_wallet)?; + + Ok(our_address) +} + +#[wasm_bindgen] +pub fn pair_device(message_id: u32, incoming_pairing_txid: String) -> ApiResult<()> { + let mut local_device = lock_local_device()?; + + // check that we're still in pairing phase + if !local_device.is_pairing() { + return Err(ApiError { + message: "Already paired".to_owned(), + }); + } + + let mut messages = lock_messages()?; + + let my_address = local_device + .get_wallet() + .get_client() + .get_receiving_address(); + + if let Some(message) = messages.iter_mut().find(|m| m.id == message_id) { + if message.status != CachedMessageStatus::Pairing { + return Err(ApiError { + message: "Message is not pairing message".to_owned(), + }); + } + let link_with = if Some(my_address.as_str()) == message.sender.as_ref().map(|s| s.as_str()) + { + message.recipient.as_ref().ok_or(ApiError { + message: "Missing recipient".to_owned(), + })? + } else if Some(my_address.as_str()) == message.recipient.as_ref().map(|s| s.as_str()) { + message.sender.as_ref().ok_or(ApiError { + message: "Missing sender".to_owned(), + })? + } else { + // This should never happen + return Err(ApiError { + message: "We're not part of that message".to_owned(), + }); + }; + let revokation_index = message.tied_by.ok_or(ApiError { + message: "Missing tied_by".to_owned(), + })?; + let pairing_tx = message.commited_in.ok_or(ApiError { + message: "Missing commited_in".to_owned(), + })?; + local_device.new_link( + SilentPaymentAddress::try_from(link_with.as_str()).unwrap(), + pairing_tx.txid, + revokation_index, + Txid::from_str(&incoming_pairing_txid)?, + )?; + + message.status = CachedMessageStatus::Closed; + } else { + return Err(ApiError { + message: format!("Can't find message with id {}", message_id), + }); + } Ok(()) } @@ -378,26 +364,66 @@ impl outputs_list { } #[wasm_bindgen] -pub fn login_user(fee_rate: u32) -> ApiResult<()> { - create_login_transaction(fee_rate)?; +pub fn login(message_id: u32, outgoing_pairing_transaction: String) -> ApiResult<()> { + let mut local_device = lock_local_device()?; + let pairing_transaction: Transaction = + deserialize(&Vec::from_hex(&outgoing_pairing_transaction)?)?; + let pairing_transaction_txid = pairing_transaction.txid(); + + let messages = lock_messages()?; + + let login_output = pairing_transaction + .output + .first() + .expect("Transaction has at least one output"); + let new_remote_key = XOnlyPublicKey::from_slice(&login_output.script_pubkey.as_bytes()[2..])?; + + let new_session_key: SecretKey; + let notification_outpoint: OutPoint; + if let Some(message) = messages.iter().find(|m| m.id == message_id) { + notification_outpoint = message + .commited_in + .expect("message without commitment outpoint"); + let sp_wallet = local_device.get_wallet(); + let spendable_outputs = sp_wallet.get_outputs().to_spendable_list(); + + let output = spendable_outputs + .get(¬ification_outpoint) + .ok_or(ApiError { + message: "Unknown outpoint".to_owned(), + })?; + + let spend_key = sp_wallet.get_client().try_get_secret_spend_key()?; + let tweak = SecretKey::from_slice(&Vec::from_hex(&output.tweak)?)?; + new_session_key = spend_key.add_tweak(&tweak.into())?; + } else { + return Err(ApiError { + message: "Unknown message".to_owned(), + }); + } + + local_device.update_session( + new_session_key, + notification_outpoint, + OutPoint::new(pairing_transaction_txid, 1), + new_remote_key, + OutPoint::new(pairing_transaction_txid, 0), + OutPoint::new(notification_outpoint.txid, 1), + ); Ok(()) } #[wasm_bindgen] pub fn logout() -> ApiResult<()> { - let mut spending_client = lock_spending_client()?; - - *spending_client = SpClient::default(); - - Ok(()) + unimplemented!(); } #[wasm_bindgen] -pub fn dump_watch_only_wallet() -> ApiResult { +pub fn dump_wallet() -> ApiResult { let device = lock_local_device()?; - Ok(serde_json::to_string(device.get_watch_only()).unwrap()) + Ok(serde_json::to_string(device.get_wallet()).unwrap()) } #[wasm_bindgen] @@ -441,12 +467,15 @@ pub fn dump_message_cache() -> ApiResult> { Ok(res) } +#[wasm_bindgen] +pub fn dump_device() -> ApiResult { + let local_device = lock_local_device()?; + + Ok(serde_json::to_string(&local_device.clone())?) +} + #[wasm_bindgen] pub fn reset_device() -> ApiResult<()> { - let mut spending_client = lock_spending_client()?; - - *spending_client = SpClient::default(); - let mut device = lock_local_device()?; *device = Device::default(); @@ -456,32 +485,6 @@ pub fn reset_device() -> ApiResult<()> { Ok(()) } -#[wasm_bindgen] -pub fn encrypt_remote_key( - remote_key: String, - aes_key: Option, - nonce: Option, -) -> ApiResult { - let mut device = lock_local_device()?; - let encrypted_key: Vec; - if let (Some(key_hex), Some(nonce_hex)) = (aes_key, nonce) { - // check that the hex we got for key and nonce is valid - let mut key = [0u8; 32]; - let mut nonce = [0u8; 12]; - key.copy_from_slice(&Vec::from_hex(&key_hex)?); - nonce.copy_from_slice(&Vec::from_hex(&nonce_hex)?); - encrypted_key = device.encrypt_for_remote_device( - SecretKey::from_str(&remote_key)?, - Some(key), - Some(nonce), - )?; - } else { - encrypted_key = - device.encrypt_for_remote_device(SecretKey::from_str(&remote_key)?, None, None)?; - } - Ok(encrypted_key.to_lower_hex_string()) -} - fn handle_recover_transaction( updated: HashMap, tx: &Transaction, @@ -536,10 +539,10 @@ fn handle_recover_transaction( // If we are receiver, that's pretty much it message.status = CachedMessageStatus::Trusted; return Ok(message.clone()); - } else if let Some(message) = messages - .iter_mut() - .find(|m| m.commited_in == Some(input.previous_output)) - { + } else if let Some(message) = messages.iter_mut().find(|m| { + m.commited_in == Some(input.previous_output) + && m.status == CachedMessageStatus::SentWaitingConfirmation + }) { // sender needs to spent it back again to receiver let (outpoint, output) = utxo_created.into_iter().next().unwrap(); @@ -558,10 +561,10 @@ fn handle_recover_transaction( ); let shared_secret = AnkSharedSecret::new(shared_point); - debug!( - "Shared secret: {}", - shared_secret.to_byte_array().to_lower_hex_string() - ); + // debug!( + // "Shared secret: {}", + // shared_secret.to_byte_array().to_lower_hex_string() + // ); let mut plaintext: Vec = vec![]; if let Some(message) = messages.iter_mut().find(|m| { @@ -580,6 +583,10 @@ fn handle_recover_transaction( let cipher_msg: CipherMessage = serde_json::from_slice(&plaintext)?; message.commited_in = Some(outpoint.clone()); + // freeze the commitment utxo + let mut freezed_utxos = lock_freezed_utxos()?; + freezed_utxos.insert(*outpoint); + message.shared_secret = Some(shared_secret.to_byte_array().to_lower_hex_string()); message.commitment = Some(commitment_str); message.plaintext.push(cipher_msg.message); @@ -597,6 +604,10 @@ fn handle_recover_transaction( .next() .expect("utxo_created shouldn't be empty"); new_msg.commited_in = Some(outpoint.clone()); + // freeze the commitment utxo + let mut freezed_utxos = lock_freezed_utxos()?; + freezed_utxos.insert(*outpoint); + new_msg.commitment = Some(commitment.to_lower_hex_string()); new_msg.recipient = Some(sp_wallet.get_client().get_receiving_address()); new_msg.shared_secret = Some(shared_secret.to_byte_array().to_lower_hex_string()); @@ -614,7 +625,9 @@ fn handle_recover_transaction( return false; } match m.status { - CachedMessageStatus::SentWaitingConfirmation => { + CachedMessageStatus::SentWaitingConfirmation + | CachedMessageStatus::Pairing + | CachedMessageStatus::Login => { // commitment we're looking for is simply what's in the message m.commitment .as_ref() @@ -670,7 +683,7 @@ fn process_transaction( let tweak_data = PublicKey::from_str(&tweak_data_hex)?; let mut device = lock_local_device()?; - let wallet = device.get_watch_only_mut(); + let wallet = device.get_mut_wallet(); let updated = wallet.update_wallet_with_transaction(&tx, blockheight, tweak_data)?; if updated.len() > 0 { @@ -721,18 +734,16 @@ pub fn parse_network_msg(raw: String, fee_rate: u32) -> ApiResult // let's try to decrypt with keys we found in transactions but haven't used yet let mut messages = lock_messages()?; let cipher = Vec::from_hex(&ank_msg.content.trim_matches('\"'))?; - if let Some(message) = messages.iter_mut().find(|m| { - // debug!("Trying message: {:?}", m); - match m.status { - CachedMessageStatus::TxWaitingCipher | CachedMessageStatus::Trusted => { - m.try_decrypt_cipher(cipher.clone()).is_ok() - } - _ => return false, + if let Some(message) = messages.iter_mut().find(|m| match m.status { + CachedMessageStatus::TxWaitingCipher | CachedMessageStatus::Trusted => { + m.try_decrypt_cipher(cipher.clone()).is_ok() } + _ => return false, }) { let plain = message.try_decrypt_cipher(cipher).unwrap(); - let cipher_msg: CipherMessage = serde_json::from_slice(&plain)?; + debug!("Found message {}", String::from_utf8(plain.clone())?); if message.status == CachedMessageStatus::TxWaitingCipher { + let cipher_msg: CipherMessage = serde_json::from_slice(&plain)?; // does the retrieved message match with the commited hash? let hash = create_commitment(serde_json::to_string(&cipher_msg)?); if Some(hash) != message.commitment { @@ -740,15 +751,24 @@ pub fn parse_network_msg(raw: String, fee_rate: u32) -> ApiResult message: "Message doesn't match commitment".to_owned(), }); } - message.plaintext.push(cipher_msg.message); message.sender = Some(cipher_msg.sender); message.ciphertext = None; - message.status = CachedMessageStatus::ReceivedMustConfirm; + if cipher_msg.message.starts_with("PAIRING") { + // we don't follow the classic confirmation pattern + // set the status to sth else + // if we agree, we must send another notification to remote + // the notification output here will be spent as our first session + message.status = CachedMessageStatus::Pairing; + } else if cipher_msg.message.starts_with("LOGIN") { + message.status = CachedMessageStatus::Login; + } else { + message.status = CachedMessageStatus::ReceivedMustConfirm; + } + message.plaintext.push(cipher_msg.message); } else { // We're receiving a message for some action already engaged - // We could check the sender, but do we really care since we alredy trust it? // Let's update the message by pushing what we just found out - message.plaintext.push(cipher_msg.message); + message.plaintext.push(String::from_utf8(plain)?); } return Ok(message.clone()); } else { @@ -772,7 +792,7 @@ pub fn parse_network_msg(raw: String, fee_rate: u32) -> ApiResult #[wasm_bindgen] pub fn get_outputs() -> ApiResult { let device = lock_local_device()?; - let outputs = device.get_watch_only().get_outputs().clone(); + let outputs = device.get_wallet().get_outputs().clone(); Ok(JsValue::from_serde(&outputs.to_outpoints_list())?) } @@ -780,7 +800,7 @@ pub fn get_outputs() -> ApiResult { pub fn get_available_amount() -> ApiResult { let device = lock_local_device()?; - Ok(device.get_watch_only().get_outputs().get_balance().to_sat()) + Ok(device.get_wallet().get_outputs().get_balance().to_sat()) } #[derive(Debug, Tsify, Serialize, Deserialize, Default)] @@ -819,24 +839,26 @@ pub fn answer_confirmation_transaction( let local_device = lock_local_device()?; - let current_outputs = local_device.get_watch_only().get_outputs().clone(); - - let spending_client = lock_spending_client()?.clone(); - - let sp_wallet = SpWallet::new(spending_client, Some(current_outputs), vec![])?; + let sp_wallet = local_device.get_wallet(); let recipient = Recipient { address: sp_address.into(), - amount: Amount::from_sat(0), // we'll set amount to what's available in the confirmed_by output we don't want change + amount: DUST_THRESHOLD, nb_outputs: 1, }; let confirmed_by = message.confirmed_by.as_ref().unwrap(); + let mut freezed_utxos = lock_freezed_utxos()?; + + // we remove the outpoint we want to spend from our freezed utxos list + freezed_utxos.remove(&confirmed_by); + let signed_psbt = create_transaction( &vec![confirmed_by], - &sp_wallet, - recipient, + &freezed_utxos, + sp_wallet, + vec![recipient], None, Amount::from_sat(fee_rate.into()), message.recipient.clone(), @@ -877,24 +899,28 @@ pub fn create_confirmation_transaction( let sp_address: SilentPaymentAddress = message.sender.as_ref().unwrap().as_str().try_into()?; - let current_outputs = lock_local_device()?.get_watch_only().get_outputs().clone(); + let local_device = lock_local_device()?; - let spending_client = lock_spending_client()?.clone(); - - let sp_wallet = SpWallet::new(spending_client, Some(current_outputs), vec![])?; + let sp_wallet = local_device.get_wallet(); let recipient = Recipient { address: sp_address.into(), - amount: Amount::from_sat(0), + amount: DUST_THRESHOLD, nb_outputs: 1, }; let commited_in = message.commited_in.as_ref().unwrap(); + let mut freezed_utxos = lock_freezed_utxos()?; + + // we remove the outpoint we want to spend from our freezed utxos list + freezed_utxos.remove(&commited_in); + let signed_psbt = create_transaction( &vec![commited_in], + &freezed_utxos, &sp_wallet, - recipient, + vec![recipient], None, Amount::from_sat(fee_rate.into()), message.sender.clone(), @@ -921,64 +947,138 @@ pub fn create_confirmation_transaction( }) } +#[wasm_bindgen] +pub fn create_login_transaction(fee_rate: u32) -> ApiResult { + // First thing is to check that all the revokation outpoints are still unspent + // We assume it has been checked before calling this function + let local_device = lock_local_device()?; + if !local_device.is_linked() { + return Err(ApiError { + message: "No linked device".to_owned(), + }); + } + + let sp_wallet = local_device.get_wallet(); + let paired_device = local_device.get_paired_device_info().unwrap(); + + let mut outpoint_to_spend = local_device.get_next_output_to_spend(); + + if outpoint_to_spend == OutPoint::default() { + // First login + outpoint_to_spend = OutPoint::new( + Txid::from_byte_array(paired_device.incoming_pairing_transaction), + 0, + ); + } + + debug!("outpoint_to_spend: {}", outpoint_to_spend); + + debug!("outputs: {:?}", sp_wallet.get_outputs().to_outpoints_list()); + + let cipher_msg = CipherMessage::new( + local_device + .get_wallet() + .get_client() + .get_receiving_address(), + "LOGIN".to_owned(), + ); + + let commitment = create_commitment(serde_json::to_string(&cipher_msg)?); + + let recipient_address = SilentPaymentAddress::try_from(paired_device.address.as_str()).unwrap(); + + let recipient = Recipient { + address: recipient_address.into(), + amount: Amount::from_sat(1200), + nb_outputs: 1, + }; + + let mut freezed_utxos = lock_freezed_utxos()?; + + // we remove the outpoint we want to spend from our freezed utxos list + freezed_utxos.remove(&outpoint_to_spend); + + let signed_psbt = create_transaction( + &vec![&outpoint_to_spend], + &freezed_utxos, + sp_wallet, + vec![recipient], + Some(Vec::from_hex(&commitment)?), + Amount::from_sat(fee_rate.into()), + None, + )?; + + let partial_secret = sp_wallet + .get_client() + .get_partial_secret_from_psbt(&signed_psbt)?; + + let shared_point = sp_utils::sending::calculate_ecdh_shared_secret( + &recipient_address.get_scan_key(), + &partial_secret, + ); + + let shared_secret = AnkSharedSecret::new(shared_point); + + let cipher = encrypt_with_key( + serde_json::to_string(&cipher_msg)?, + shared_secret.to_byte_array().to_lower_hex_string(), + )?; + + // update our cache + let sp_address2vouts = map_outputs_to_sp_address(&signed_psbt.to_string())?; + let recipients_vouts = sp_address2vouts + .get::(&recipient_address.into()) + .expect("recipients didn't change") + .as_slice(); + + let final_tx = signed_psbt.extract_tx()?; + + let mut new_msg = CachedMessage::new(); + new_msg.plaintext.push(cipher_msg.message); + new_msg.ciphertext = Some(cipher); + new_msg.commitment = Some(commitment); + new_msg.commited_in = Some(OutPoint { + txid: final_tx.txid(), + vout: recipients_vouts[0] as u32, + }); + new_msg.shared_secret = Some(shared_secret.to_byte_array().to_lower_hex_string()); + new_msg.recipient = Some(recipient_address.into()); + new_msg.sender = Some(cipher_msg.sender); + new_msg.tied_by = Some(1); // for now we just assume that's the second utxo, first being the notification itself + new_msg.status = CachedMessageStatus::Login; + lock_messages()?.push(new_msg.clone()); + + return Ok(createTransactionReturn { + txid: final_tx.txid().to_string(), + transaction: serialize(&final_tx).to_lower_hex_string(), + new_network_msg: new_msg, + }); +} + #[wasm_bindgen] pub fn create_pairing_transaction( address: String, fee_rate: u32, ) -> ApiResult { - let message: CipherMessage; - { - let mut spending_client = lock_spending_client()?; + let my_address = lock_local_device()? + .get_wallet() + .get_client() + .get_receiving_address(); - let our_address = spending_client.get_receiving_address(); - let spend_sk: SecretKey = spending_client.get_spend_key().try_into()?; + let cipher_message = CipherMessage::new(my_address, "PAIRING".to_owned()); - message = CipherMessage::new(our_address, format!("{}", spend_sk.display_secret())); - } + let mut res = create_notification_transaction(address, cipher_message, fee_rate)?; - let mut res = create_notification_transaction(address, message, fee_rate); - - // we slightly alter the message - if let Ok(ref mut new_msg) = res { - new_msg.new_network_msg.plaintext = vec![]; // we don't want to let that information available - new_msg.new_network_msg.status = CachedMessageStatus::Trusted; - } else { - return res; - } - - // Update the msg in cache let mut messages = lock_messages()?; - let mut updated = res.as_ref().unwrap().new_network_msg.clone(); - let pos = messages.iter().position(|m| m.id == updated.id).unwrap(); - // clone the cached message and erase the ciphertext - updated.ciphertext = None; - messages[pos] = updated; - // we forget our own wallet - let mut spending_client = lock_spending_client()?; - *spending_client = SpClient::default(); - - res -} - -#[wasm_bindgen] -pub fn create_login_transaction(fee_rate: u32) -> ApiResult { - let address = lock_local_device()?.get_remote_address().ok_or(ApiError { - message: "Wallet is not linked".to_owned(), - })?; - - let message: CipherMessage; - { - let device = lock_local_device()?; - - let our_address = device.get_watch_only().get_client().get_receiving_address(); - - let encrypted_key = device.get_encrypted_key().to_lower_hex_string(); - - message = CipherMessage::new(our_address, encrypted_key); + if let Some(m) = messages.iter_mut().find(|m| m.id == res.new_network_msg.id) { + m.status = CachedMessageStatus::Pairing; + res.new_network_msg = m.clone(); + } else { + unreachable!("We don't have in cache the message we just created"); } - create_notification_transaction(address, message, fee_rate) + Ok(res) } #[wasm_bindgen] @@ -991,11 +1091,7 @@ pub fn create_notification_transaction( let local_device = lock_local_device()?; - let current_outputs = local_device.get_watch_only().get_outputs().clone(); - - let spending_client = lock_spending_client()?.clone(); - - let sp_wallet = SpWallet::new(spending_client, Some(current_outputs), vec![])?; + let sp_wallet = local_device.get_wallet(); let recipient = Recipient { address: sp_address.into(), @@ -1005,10 +1101,13 @@ pub fn create_notification_transaction( let commitment = create_commitment(serde_json::to_string(&cipher_message)?); + let freezed_utxos = lock_freezed_utxos()?; + let signed_psbt = create_transaction( &vec![], - &sp_wallet, - recipient, + &freezed_utxos, + sp_wallet, + vec![recipient], Some(Vec::from_hex(&commitment)?), Amount::from_sat(fee_rate.into()), None, @@ -1025,11 +1124,6 @@ pub fn create_notification_transaction( let shared_secret = AnkSharedSecret::new(shared_point); - // debug!( - // "Created transaction with secret {}", - // shared_secret.to_byte_array().to_lower_hex_string() - // ); - let cipher = encrypt_with_key( serde_json::to_string(&cipher_message)?, shared_secret.to_byte_array().to_lower_hex_string(), @@ -1054,6 +1148,7 @@ pub fn create_notification_transaction( new_msg.shared_secret = Some(shared_secret.to_byte_array().to_lower_hex_string()); new_msg.recipient = Some(address); new_msg.sender = Some(cipher_message.sender); + new_msg.tied_by = Some(1); // for now we just assume that's the second utxo, first being the notification itself new_msg.status = CachedMessageStatus::SentWaitingConfirmation; lock_messages()?.push(new_msg.clone()); @@ -1135,7 +1230,7 @@ pub fn try_decrypt_with_key(cipher: String, key: String) -> ApiResult { #[wasm_bindgen] pub fn create_faucet_msg() -> ApiResult { let sp_address = lock_local_device()? - .get_watch_only() + .get_wallet() .get_client() .get_receiving_address(); diff --git a/src/user.rs b/src/user.rs index 10c7594..f244aa2 100644 --- a/src/user.rs +++ b/src/user.rs @@ -1,13 +1,18 @@ use anyhow::{Error, Result}; use rand::{self, thread_rng, Rng, RngCore}; +use sdk_common::sp_client::bitcoin::consensus::{deserialize, serialize}; use sdk_common::sp_client::bitcoin::hashes::{Hash, HashEngine}; use sdk_common::sp_client::bitcoin::hex::{DisplayHex, FromHex}; +use sdk_common::sp_client::bitcoin::key::{Parity, Secp256k1}; use sdk_common::sp_client::bitcoin::secp256k1::{PublicKey, SecretKey, ThirtyTwoByteHash}; -use sdk_common::sp_client::bitcoin::{Network, OutPoint, ScriptBuf}; +use sdk_common::sp_client::bitcoin::{ + Network, OutPoint, ScriptBuf, Transaction, Txid, XOnlyPublicKey, +}; use sdk_common::sp_client::spclient::SpClient; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; use tsify::Tsify; +use wasm_bindgen::convert::VectorFromWasmAbi; use wasm_bindgen::prelude::*; use std::collections::HashMap; @@ -30,172 +35,165 @@ use sdk_common::crypto::{ pub static LOCAL_DEVICE: OnceLock> = OnceLock::new(); +pub fn set_new_device(sp_wallet: SpWallet) -> Result { + let mut device = Device::new(sp_wallet); + + let mut local_device = lock_local_device()?; + if *local_device.get_wallet().get_client() != SpClient::default() { + return Err(Error::msg("Device already initialized".to_owned())); + } else { + *local_device = device; + } + + let our_address = local_device + .get_wallet() + .get_client() + .get_receiving_address(); + + Ok(our_address) +} + pub fn lock_local_device() -> Result> { LOCAL_DEVICE .get_or_init(|| Mutex::new(Device::default())) .lock_anyhow() } -pub static SPENDING_CLIENT: OnceLock> = OnceLock::new(); - -pub fn lock_spending_client() -> Result> { - SPENDING_CLIENT - .get_or_init(|| Mutex::new(SpClient::default())) - .lock_anyhow() +#[derive(Debug, Serialize, Deserialize, Clone, Default, Tsify)] +#[tsify(into_wasm_abi, from_wasm_abi)] +pub struct PairedDevice { + pub address: String, + pub outgoing_pairing_transaction: [u8; 32], + pub revokation_index: u32, + pub incoming_pairing_transaction: [u8; 32], + pub current_remote_key: [u8; 32], + pub current_session_outpoint: OutPoint, // This will be spend by remote device to notify us of next login + pub current_session_revokation_outpoint: OutPoint, // remote device can revoke current session by spending this } -#[derive(Debug, Clone, Serialize, Deserialize, Default)] -pub struct RevokeOutput { - key: [u8; 32], - spk: ScriptBuf, - outpoint: OutPoint, -} +impl PairedDevice { + pub fn new(address: SilentPaymentAddress, pairing_txid: Txid, revokation_index: u32) -> Self { + let mut pairing_transaction_buf = [0u8; 32]; + pairing_transaction_buf.copy_from_slice(&serialize(&pairing_txid)); -impl RevokeOutput { - pub fn new(key: [u8; 32], spk: ScriptBuf, outpoint: OutPoint) -> Self { - Self { key, spk, outpoint } + Self { + address: address.into(), + outgoing_pairing_transaction: pairing_transaction_buf, + revokation_index, + incoming_pairing_transaction: [0u8; 32], + current_session_revokation_outpoint: OutPoint::default(), + current_session_outpoint: OutPoint::default(), + current_remote_key: [0u8; 32], + } } } #[derive(Debug, Serialize, Deserialize, Clone, Default, Tsify)] #[tsify(into_wasm_abi, from_wasm_abi)] pub struct Device { - watch_only_wallet: SpWallet, - spend_sk_cipher: Vec, - // Key used to encrypt the remote device spend_sk in the 2FA scheme - remote_device_key: [u8; 32], - remote_address: Option, - revokation_output: Option, + sp_wallet: SpWallet, + current_session_outpoint: OutPoint, // This is the notification output of incoming login tx + current_session_key: [u8; 32], + current_session_revokation_outpoint: OutPoint, // This is the revokation outpoint of outgoing login tx + paired_device: Option, } impl Device { - pub fn new(scan_sk: SecretKey, spend_pk: PublicKey, network: Network) -> Self { - let watch_only_client = SpClient::new( - "default".to_owned(), - scan_sk, - SpendKey::Public(spend_pk), - None, - network, - ) - .expect("watch_only_client creation failed"); - - let mut watch_only_wallet = - SpWallet::new(watch_only_client, None, vec![]).expect("watch_only_wallet creation failed"); - - let spend_sk_cipher = vec![]; - let remote_device_key = [0; 32]; - + pub fn new(sp_wallet: SpWallet) -> Self { Self { - watch_only_wallet, - spend_sk_cipher, - remote_device_key, - remote_address: None, - revokation_output: None, + sp_wallet, + current_session_outpoint: OutPoint::default(), + current_session_key: [0u8; 32], + current_session_revokation_outpoint: OutPoint::default(), + paired_device: None, } } - pub fn get_watch_only(&self) -> &SpWallet { - &self.watch_only_wallet + pub fn get_wallet(&self) -> &SpWallet { + &self.sp_wallet } - pub fn get_watch_only_mut(&mut self) -> &mut SpWallet { - &mut self.watch_only_wallet + pub fn get_mut_wallet(&mut self) -> &mut SpWallet { + &mut self.sp_wallet } pub fn is_linked(&self) -> bool { - self.remote_address.is_some() && self.spend_sk_cipher.len() != 0 + self.paired_device.is_some() } - pub fn get_remote_address(&self) -> Option { - self.remote_address.clone() + pub fn is_pairing(&self) -> bool { + self.current_session_key == [0u8; 32] } - pub fn get_encrypted_key(&self) -> Vec { - self.spend_sk_cipher.clone() + pub fn get_paired_device_info(&self) -> Option { + self.paired_device.clone() } - pub fn encrypt_for_remote_device( - &mut self, - remote_spend_sk: SecretKey, - aes_key: Option<[u8; 32]>, - nonce: Option<[u8; 12]>, - ) -> Result> { - let encryption: Aes256Encryption; - match (aes_key, nonce) { - (Some(key), Some(nonce)) => { - encryption = Aes256Encryption::import_key( - Purpose::ThirtyTwoBytes, - remote_spend_sk.secret_bytes().to_vec(), - key, - nonce, - )?; - } - (None, None) => { - encryption = Aes256Encryption::new( - Purpose::ThirtyTwoBytes, - remote_spend_sk.secret_bytes().to_vec(), - )?; - } - _ => { - return Err(Error::msg( - "aes_key and nonce must either both be set or empty", - )) - } - } - let remote_spend_sk_cipher = encryption.encrypt_with_aes_key(); - self.remote_device_key = encryption.export_key(); - remote_spend_sk_cipher + pub fn get_next_output_to_spend(&self) -> OutPoint { + self.current_session_outpoint + } + + pub fn get_session_revokation_outpoint(&self) -> OutPoint { + self.current_session_revokation_outpoint + } + + pub fn sign_with_current_session_key(&self) -> Result<()> { + unimplemented!(); + } + + pub fn encrypt_with_current_session_key(&self) -> Result<()> { + unimplemented!(); } pub fn new_link( &mut self, - spend_sk_cipher: Vec, - linked_with: SilentPaymentAddress, - revokation_output: OutPoint, - ) { - self.spend_sk_cipher = spend_sk_cipher; - self.remote_address = Some(linked_with.into()); - self.revokation_output = Some(revokation_output); - } - - pub fn login(spend_sk: SecretKey) -> Result<()> { - let mut locked_client = lock_spending_client()?; - if *locked_client != SpClient::default() { - // We already have a key charged - return Err(Error::msg("We're already logged in")); + link_with: SilentPaymentAddress, + outgoing_pairing_tx: Txid, + revokation_output: u32, + incoming_pairing_tx: Txid, + ) -> Result<()> { + let address_looked_for: String = link_with.into(); + if let Some(paired_device) = self.paired_device.as_ref() { + return Err(Error::msg(format!( + "Found an already paired device with address {} and revokable by {}:{}", + paired_device.address, + Txid::from_byte_array(paired_device.outgoing_pairing_transaction), + paired_device.revokation_index + ))); + } else { + let mut new_device = + PairedDevice::new(link_with, outgoing_pairing_tx, revokation_output); + new_device.incoming_pairing_transaction = incoming_pairing_tx.to_byte_array(); + self.paired_device = Some(new_device); } - let device = lock_local_device()?; - - let watch_only = device.get_watch_only().get_client(); - - let label = watch_only.label.clone(); - let scan_sk = watch_only.get_scan_key(); - let network = match watch_only.sp_receiver.network { - SpNetwork::Mainnet => Network::Bitcoin, - SpNetwork::Regtest => Network::Regtest, - SpNetwork::Testnet => Network::Testnet, - }; - - let spending_client = - SpClient::new(label, scan_sk, SpendKey::Secret(spend_sk), None, network)?; - - // check that we loaded the right key - if spending_client.get_receiving_address() != watch_only.get_receiving_address() { - return Err(Error::msg("Provided the wrong spending key")); - } - - *locked_client = spending_client; - Ok(()) } - pub fn logout() -> Result<()> { - if let Ok(mut client) = lock_spending_client() { - *client = SpClient::default(); - Ok(()) - } else { - Err(Error::msg("Failed to lock CONNECTED_USER")) + // We call that when we spent to the remote device and it similarly spent to us + pub fn update_session( + &mut self, + new_session_key: SecretKey, + new_session_outpoint: OutPoint, + new_revokation_outpoint: OutPoint, + new_remote_key: XOnlyPublicKey, + new_remote_session_outpoint: OutPoint, + new_remote_revokation_outpoint: OutPoint, + ) -> Result<()> { + if !self.is_linked() { + return Err(Error::msg("Can't update an unpaired device")); } + self.paired_device + .as_mut() + .map(|d| { + d.current_remote_key = new_remote_key.serialize(); + d.current_session_outpoint = new_remote_session_outpoint; + d.current_session_revokation_outpoint = new_remote_revokation_outpoint; + }); + self.current_session_key = new_session_key.secret_bytes(); + self.current_session_outpoint = new_session_outpoint; + self.current_session_revokation_outpoint = new_revokation_outpoint; + + Ok(()) } } diff --git a/src/wallet.rs b/src/wallet.rs index 188c610..6114274 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -1,10 +1,26 @@ +use std::{ + collections::HashSet, + sync::{Mutex, MutexGuard, OnceLock}, +}; + +use anyhow::Error; use rand::Rng; use sdk_common::sp_client::{ - bitcoin::Network, + bitcoin::{Network, OutPoint}, silentpayments::utils::SilentPaymentAddress, spclient::{derive_keys_from_seed, SpClient, SpWallet, SpendKey}, }; +use crate::MutexExt; + +pub static FREEZED_UTXOS: OnceLock>> = OnceLock::new(); + +pub fn lock_freezed_utxos() -> Result>, Error> { + FREEZED_UTXOS + .get_or_init(|| Mutex::new(HashSet::new())) + .lock_anyhow() +} + pub fn generate_sp_wallet(label: Option, network: Network) -> anyhow::Result { let mut seed = [0u8; 64]; rand::thread_rng().fill(&mut seed); diff --git a/tests/browser.rs b/tests/browser.rs index b46542b..dad67f9 100644 --- a/tests/browser.rs +++ b/tests/browser.rs @@ -2,20 +2,22 @@ use std::collections::HashMap; use log::debug; use sdk_client::api::{ - answer_confirmation_transaction, create_confirmation_transaction, - create_notification_transaction, encrypt_remote_key, get_outputs, pair_device, - parse_network_msg, reset_device, restore_device_from_sp_wallet, set_message_cache, setup, + create_login_transaction, create_pairing_transaction, dump_device, dump_message_cache, + dump_wallet, encrypt_with_key, encrypt_with_new_key, get_outputs, login, pair_device, + parse_network_msg, reset_device, reset_message_cache, restore_device, + restore_device_from_sp_wallet, set_message_cache, setup, }; use sdk_common::network::{ - AnkNetworkMsg, CachedMessage, CipherMessage, NewTxMessage, TrustedChannel, + AnkNetworkMsg, CachedMessage, CachedMessageStatus, CipherMessage, NewTxMessage, TrustedChannel, }; use sdk_common::sp_client::bitcoin::consensus::deserialize; use sdk_common::sp_client::bitcoin::hex::FromHex; +use sdk_common::sp_client::bitcoin::secp256k1::PublicKey; use sdk_common::sp_client::bitcoin::{OutPoint, ScriptBuf, Transaction}; use sdk_common::sp_client::silentpayments::utils::receiving::{ calculate_tweak_data, get_pubkey_from_input, }; -use sdk_common::sp_client::spclient::{OwnedOutput, SpWallet}; +use sdk_common::sp_client::spclient::{OutputSpendStatus, OwnedOutput, SpWallet}; use serde_json; use tsify::JsValueSerdeExt; @@ -24,25 +26,40 @@ use wasm_bindgen_test::*; wasm_bindgen_test_configure!(run_in_browser); // We're using alice and bob for clarity, but it's important to remember that here Alice and Bob are the same person -const ALICE_START_WALLET: &str = "{\"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 ALICE_CHALLENGE_WALLET: &str = "{\"client\":{\"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]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":0,\"outputs\":{\"d5edbf1f60ae4fd7d698626b44ed1e85edddf65b45f62e5f82928a9e12759db9:1\":{\"blockheight\":0,\"tweak\":\"28994b2f2ee8e5f35d6d2dcdee1580d0455fe3dc37f81e0a36864473ee86f5c4\",\"amount\":3937246,\"script\":\"51207d06144e982b6fd38a85d6152f1f95746b059553258a31e04df97fe6b5f19ea1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"d5edbf1f60ae4fd7d698626b44ed1e85edddf65b45f62e5f82928a9e12759db9\"}}}}}"; -const ALICE_ANSWER_WALLET: &str = "{\"client\":{\"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]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":0,\"outputs\":{\"57ca073676fa6130397ce1e4738278952483cee943daa1664b9a1807d4700066:0\":{\"blockheight\":0,\"tweak\":\"b99660cd873026aebeb378ae2ff32aa1c79a5946c462a36a01247f8afcfc5dba\",\"amount\":1046,\"script\":\"51209b80b6e8b3e93437c82a26c977860fb4d2bef9f27f6332f811a41187592502ed\",\"label\":null,\"spend_status\":\"Unspent\"},\"d5edbf1f60ae4fd7d698626b44ed1e85edddf65b45f62e5f82928a9e12759db9:1\":{\"blockheight\":0,\"tweak\":\"28994b2f2ee8e5f35d6d2dcdee1580d0455fe3dc37f81e0a36864473ee86f5c4\",\"amount\":3937246,\"script\":\"51207d06144e982b6fd38a85d6152f1f95746b059553258a31e04df97fe6b5f19ea1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"d5edbf1f60ae4fd7d698626b44ed1e85edddf65b45f62e5f82928a9e12759db9\"}}}}}"; -const BOB_START_WALLET: &str = "{\"client\":{\"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]]]},\"network\":\"regtest\"},\"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 BOB_CHALLENGE_WALLET: &str = "{\"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\":0,\"outputs\":{\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":\"Unspent\"},\"d5edbf1f60ae4fd7d698626b44ed1e85edddf65b45f62e5f82928a9e12759db9:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":\"Unspent\"}}}}"; -const BOB_ANSWER_WALLET: &str = "{\"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\":0,\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":0,\"outputs\":{\"d5edbf1f60ae4fd7d698626b44ed1e85edddf65b45f62e5f82928a9e12759db9:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"57ca073676fa6130397ce1e4738278952483cee943daa1664b9a1807d4700066\"}},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":\"Unspent\"}}}}"; +const ALICE_START_WALLET: &str = "{\"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\"}}},\"tx_history\":[]}"; +const ALICE_CHALLENGE_WALLET: &str = "{\"client\":{\"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]]]},\"network\":\"regtest\"},\"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\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":\"Unspent\"}}},\"tx_history\":[]}"; +const ALICE_ANSWER_WALLET: &str = "{\"client\":{\"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]]]},\"network\":\"regtest\"},\"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\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":\"Unspent\"}}},\"tx_history\":[]}"; +const ALICE_LOGIN_WALLET: &str = "{\"client\":{\"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]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":\"Unspent\"},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}}}},\"tx_history\":[]}"; +const ALICE_PAIRED_WALLET: &str = "{\"client\":{\"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]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e34824b0de3f00416caf295dd919fd695404c34334a36b9e7b81917c64fc9701\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":\"Unspent\"},\"e34824b0de3f00416caf295dd919fd695404c34334a36b9e7b81917c64fc9701:2\":{\"blockheight\":0,\"tweak\":\"8a1c96e8c723fd6ca0bb5e02fe59e0f87e1e7ef22399dc1c20273f90b8ff4488\",\"amount\":3935151,\"script\":\"51207d4a9230b989b8ea963701b985a1b5b9741c3d79db9fb78ca01b2c21c522dfb7\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}},\"e34824b0de3f00416caf295dd919fd695404c34334a36b9e7b81917c64fc9701:1\":{\"blockheight\":0,\"tweak\":\"624024a2506e52d6be8266c89cbe6936a556c076f814bb9f38a484a8cb426a0c\",\"amount\":306,\"script\":\"5120f53d418e01044021f4da574e67cb367e31c9e97ab9a1bc75be3879f41733ef70\",\"label\":null,\"spend_status\":\"Unspent\"}}},\"tx_history\":[]}"; +const BOB_START_WALLET: &str = "{\"client\":{\"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]]]},\"network\":\"regtest\"},\"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\"}}},\"tx_history\":[]}"; +const BOB_CHALLENGE_WALLET: &str = "{\"client\":{\"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]]]},\"network\":\"regtest\"},\"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\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":\"Unspent\"}}},\"tx_history\":[]}"; +const BOB_ANSWER_WALLET: &str = "{\"client\":{\"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]]]},\"network\":\"regtest\"},\"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\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"}}},\"tx_history\":[]}"; +const BOB_LOGIN_WALLET: &str = "{\"client\":{\"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]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":\"Unspent\"}}},\"tx_history\":[]}"; +const BOB_PAIRED_WALLET: &str = "{\"client\":{\"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]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":{\"Spent\":\"a70e0a70c4df32e9e2bde88b9623eead5e24f25260ecb14252f0f0dd3094164a\"}},\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":{\"Spent\":\"a70e0a70c4df32e9e2bde88b9623eead5e24f25260ecb14252f0f0dd3094164a\"}},\"e34824b0de3f00416caf295dd919fd695404c34334a36b9e7b81917c64fc9701:0\":{\"blockheight\":0,\"tweak\":\"49ab242529118b90ee3db481f7f979588bea59abaf71f6fdb1326156ec95d1f9\",\"amount\":1200,\"script\":\"51204d4dafb5ba432c6ecffc2db7965c901b20312e1beb08132ef9893073e0cbb1bd\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}},\"a70e0a70c4df32e9e2bde88b9623eead5e24f25260ecb14252f0f0dd3094164a:1\":{\"blockheight\":0,\"tweak\":\"70265572d5f239fb96022c48c49ba73dc0c544cfe4a2a77900aae12476258e7c\",\"amount\":191,\"script\":\"5120e3c9e3a1a606214c0b2138efe90bf394a92f3210062899ad11e58b35dbf12d9d\",\"label\":null,\"spend_status\":\"Unspent\"},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":{\"Spent\":\"a70e0a70c4df32e9e2bde88b9623eead5e24f25260ecb14252f0f0dd3094164a\"}},\"a70e0a70c4df32e9e2bde88b9623eead5e24f25260ecb14252f0f0dd3094164a:2\":{\"blockheight\":0,\"tweak\":\"dc37abf37053e241d71f6c401b056d8e6f944f06811daa18494387001f20faed\",\"amount\":99895946,\"script\":\"512050de7190c8b7dd4d6268e716f89a9be001674b8779574bed42be53fa02531c68\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"}}},\"tx_history\":[]}"; const ALICE_SPK: &str = "51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1"; const REVOKATION_OUTPUT: &str = "3dd51588af6cc2e4ff8e405fd2620f19c8f4e09e05692ad57a9208a061687295:3"; -const ALICE_CHALLENGE_CACHE: &str = "{\"id\":1283337801,\"status\":\"SentWaitingConfirmation\",\"ciphertext\":\"d53ec574b09068cc661a76e6934cb9131df1b8d84b0ec791cb2c2789c42aae53bf2e7d514a00b2c27a78a786fee97f55dd022a99551770c4f05edfc4296993b2f82104933f61cd0d7c2e02a21188c58b492ac0a190e711ddc697505e106df087f8f9d3591aa30798608c2a0eb1e7c124d54e88dd9271884a3fe7f24f628a150d0dc90ded4753f9aa4e2730c7a339bfd7ef0faa02ee6d4cd3b1de36f8796485bd6bd8eee0e78c1e6d6c822dd9532df4c963835ea412bb36827cd89d3466\",\"plaintext\":[\"TEST\"],\"commited_in\":\"d5edbf1f60ae4fd7d698626b44ed1e85edddf65b45f62e5f82928a9e12759db9:0\",\"tie_by\":null,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"5a28562161f939bf77983df807dd914e73f02ea67a21ed976d214452887ae43e\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1720966687785,\"error\":null}"; -const ALICE_ANSWER_CACHE: &str = "{\"id\":1283337801,\"status\":\"MustSpendConfirmation\",\"ciphertext\":\"d53ec574b09068cc661a76e6934cb9131df1b8d84b0ec791cb2c2789c42aae53bf2e7d514a00b2c27a78a786fee97f55dd022a99551770c4f05edfc4296993b2f82104933f61cd0d7c2e02a21188c58b492ac0a190e711ddc697505e106df087f8f9d3591aa30798608c2a0eb1e7c124d54e88dd9271884a3fe7f24f628a150d0dc90ded4753f9aa4e2730c7a339bfd7ef0faa02ee6d4cd3b1de36f8796485bd6bd8eee0e78c1e6d6c822dd9532df4c963835ea412bb36827cd89d3466\",\"plaintext\":[\"TEST\"],\"commited_in\":\"d5edbf1f60ae4fd7d698626b44ed1e85edddf65b45f62e5f82928a9e12759db9:0\",\"tie_by\":null,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"5a28562161f939bf77983df807dd914e73f02ea67a21ed976d214452887ae43e\",\"key\":null,\"confirmed_by\":\"57ca073676fa6130397ce1e4738278952483cee943daa1664b9a1807d4700066:0\",\"timestamp\":1720966687785,\"error\":null}"; -const BOB_CHALLENGE_CACHE: &str = "{\"id\":2639151119,\"status\":\"ReceivedMustConfirm\",\"ciphertext\":null,\"plaintext\":[\"TEST\"],\"commited_in\":\"d5edbf1f60ae4fd7d698626b44ed1e85edddf65b45f62e5f82928a9e12759db9:0\",\"tie_by\":null,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"5a28562161f939bf77983df807dd914e73f02ea67a21ed976d214452887ae43e\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1721315780531,\"error\":null}"; -const BOB_ANSWER_CACHE: &str = "{\"id\":2639151119,\"status\":\"ReceivedMustConfirm\",\"ciphertext\":null,\"plaintext\":[\"TEST\"],\"commited_in\":\"d5edbf1f60ae4fd7d698626b44ed1e85edddf65b45f62e5f82928a9e12759db9:0\",\"tie_by\":null,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"5a28562161f939bf77983df807dd914e73f02ea67a21ed976d214452887ae43e\",\"key\":null,\"confirmed_by\":\"57ca073676fa6130397ce1e4738278952483cee943daa1664b9a1807d4700066:0\",\"timestamp\":1721315780531,\"error\":null}"; +const ALICE_CHALLENGE_CACHE: &str = "{\"id\":589363040,\"status\":\"SentWaitingConfirmation\",\"ciphertext\":\"756bcdca605b478fd7b27076b3c770e0cd2edaa2d52d817b19b7070b404680384546139dc9a5a88fd5389095e72f60b07ad0e279dc33a51132ccacc8013717645c7055cec0eaefa1999ba7edfc62d62fa84ada991677a389014f7ba02ec1d9d144df3f4205624a6fcd1d7d35bc53a94de06be0f9a3d435de76e3b00d56a7fd62404db7c9db60d6649133bbc1e37fb3cedb271b1ea682fa02eff88b6edc2790a08550dd049030da2f14247f777757414dd9890535021ee633df7bfd12ab\",\"plaintext\":[\"TEST\"],\"commited_in\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\",\"tied_by\":1,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"5a28562161f939bf77983df807dd914e73f02ea67a21ed976d214452887ae43e\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1722020264716,\"error\":null}"; +const ALICE_ANSWER_CACHE: &str = "{\"id\":589363040,\"status\":\"MustSpendConfirmation\",\"ciphertext\":\"756bcdca605b478fd7b27076b3c770e0cd2edaa2d52d817b19b7070b404680384546139dc9a5a88fd5389095e72f60b07ad0e279dc33a51132ccacc8013717645c7055cec0eaefa1999ba7edfc62d62fa84ada991677a389014f7ba02ec1d9d144df3f4205624a6fcd1d7d35bc53a94de06be0f9a3d435de76e3b00d56a7fd62404db7c9db60d6649133bbc1e37fb3cedb271b1ea682fa02eff88b6edc2790a08550dd049030da2f14247f777757414dd9890535021ee633df7bfd12ab\",\"plaintext\":[\"TEST\"],\"commited_in\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\",\"tied_by\":1,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"5a28562161f939bf77983df807dd914e73f02ea67a21ed976d214452887ae43e\",\"key\":null,\"confirmed_by\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\",\"timestamp\":1722020264716,\"error\":null}"; +const ALICE_FINAL_CACHE: &str = "{\"id\":589363040,\"status\":\"Trusted\",\"ciphertext\":\"756bcdca605b478fd7b27076b3c770e0cd2edaa2d52d817b19b7070b404680384546139dc9a5a88fd5389095e72f60b07ad0e279dc33a51132ccacc8013717645c7055cec0eaefa1999ba7edfc62d62fa84ada991677a389014f7ba02ec1d9d144df3f4205624a6fcd1d7d35bc53a94de06be0f9a3d435de76e3b00d56a7fd62404db7c9db60d6649133bbc1e37fb3cedb271b1ea682fa02eff88b6edc2790a08550dd049030da2f14247f777757414dd9890535021ee633df7bfd12ab\",\"plaintext\":[\"TEST\"],\"commited_in\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\",\"tied_by\":1,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"5a28562161f939bf77983df807dd914e73f02ea67a21ed976d214452887ae43e\",\"key\":null,\"confirmed_by\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\",\"timestamp\":1722020264716,\"error\":null}"; +// const ALICE_PAIRING_CACHE: &str = "{\"id\":1283337801,\"status\":\"Pairing\",\"ciphertext\":null,\"plaintext\":[\"PAIRING\"],\"commited_in\":\"d5edbf1f60ae4fd7d698626b44ed1e85edddf65b45f62e5f82928a9e12759db9:0\",\"tied_by\":1,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"5a28562161f939bf77983df807dd914e73f02ea67a21ed976d214452887ae43e\",\"key\":null,\"confirmed_by\":\"57ca073676fa6130397ce1e4738278952483cee943daa1664b9a1807d4700066:0\",\"timestamp\":1720966687785,\"error\":null}"; +const BOB_CHALLENGE_CACHE: &str = "{\"id\":1777910913,\"status\":\"ReceivedMustConfirm\",\"ciphertext\":null,\"plaintext\":[\"TEST\"],\"commited_in\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\",\"tied_by\":null,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"5a28562161f939bf77983df807dd914e73f02ea67a21ed976d214452887ae43e\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1722020264775,\"error\":null}"; +const BOB_ANSWER_CACHE: &str = "{\"id\":1777910913,\"status\":\"ReceivedMustConfirm\",\"ciphertext\":null,\"plaintext\":[\"TEST\"],\"commited_in\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\",\"tied_by\":null,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"5a28562161f939bf77983df807dd914e73f02ea67a21ed976d214452887ae43e\",\"key\":null,\"confirmed_by\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\",\"timestamp\":1722020264775,\"error\":null}"; +const BOB_FINAL_CACHE: &str = "{\"id\":1777910913,\"status\":\"Trusted\",\"ciphertext\":null,\"plaintext\":[\"TEST\"],\"commited_in\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\",\"tied_by\":null,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"5a28562161f939bf77983df807dd914e73f02ea67a21ed976d214452887ae43e\",\"key\":null,\"confirmed_by\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\",\"timestamp\":1722020264775,\"error\":null}"; +// const BOB_PAIRING_CACHE: &str = "{\"id\":2639151119,\"status\":\"Pairing\",\"ciphertext\":null,\"plaintext\":[\"PAIRING\"],\"commited_in\":\"6525a5487853e13a99b94302a1bbc94601ae91a0129cfd39ea4b2c32a441eef7:0\",\"tied_by\":3,\"commitment\":\"d12f3c5b37240bc3abf2976f41fdf9a594f0680aafd2781ac448f80440fbeb99\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"5a28562161f939bf77983df807dd914e73f02ea67a21ed976d214452887ae43e\",\"key\":null,\"confirmed_by\":\"57ca073676fa6130397ce1e4738278952483cee943daa1664b9a1807d4700066:0\",\"timestamp\":1721315780531,\"error\":null}"; + +const BOB_PAIRING_CACHE: &str = "[{\"id\":2853916441,\"status\":\"Pairing\",\"ciphertext\":null,\"plaintext\":[\"PAIRING\"],\"commited_in\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\",\"tied_by\":null,\"commitment\":\"7f340cd5f070a4bd8d16077214a0488e43bd41d64d8b2b39ab0fc016c1093eba\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"a86c30250a8e6a8dc9581b3ab2dacafda6446f6c65f4debe124f5870b6796ea1\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1722436062445,\"error\":null}, {\"id\":1045548533,\"status\":\"Closed\",\"ciphertext\":\"bd2acbc73fc402a8cb57121153f2667b944fe31f67ccdd6031e7d9481642f42ebdae00b572b1be6735ff413ceedccf29d2f0700021c6cf61b954891912968a449e6cb735e9344d90db21268ff596f844db358bc4852358ac89a71e81179b249b499a6b70bef341ff71737ea0a9a7e3f2a90bb41d376272410a18ec367d5b6f417420d6d6ee06a132c263269cba281c1fa6e644b5beed716783e973594f5e9da76c28bdc10968ec7e49031924fb8051ec80d27f87e943f884263cb1a273b18f79\",\"plaintext\":[\"PAIRING\"],\"commited_in\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\",\"tied_by\":1,\"commitment\":\"213c1295d6721f3194745063190487e73853c21373218255d2af20c4b1ba6a7b\",\"sender\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"recipient\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"shared_secret\":\"094849bcf340d0791fa0bae31c9b58b8572ad3c9bd028de3a26e501b578cb24b\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1722436062534,\"error\":null}]"; +const ALICE_PAIRING_CACHE: &str = "[{\"id\":2059106889,\"status\":\"Closed\",\"ciphertext\":\"6634050737f9dc18b187c69872943f9a11764252bac9e163fcb7480fd0aa3cf543f7b0b7eef9579d1ddba0b79fdf8c59747050313d0518ea4c8d23d2665948549efd72d0fde7bc8e7a02936de78b7406a31072429d9a81751d5665e9333f8c429c59e47a11b8993583fc5806c8e8695db970247761d11782188c550bd19f7a2c60172104c2892a463f79c19e4173852279012003edf3f777e7c1a95e7d87863d155bcaee1fc4c1b0cb69cab42a45ad5c6271a9c9ba4f79e49a3de2e0fa0aa9bc\",\"plaintext\":[\"PAIRING\"],\"commited_in\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\",\"tied_by\":1,\"commitment\":\"7f340cd5f070a4bd8d16077214a0488e43bd41d64d8b2b39ab0fc016c1093eba\",\"sender\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"recipient\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"shared_secret\":\"a86c30250a8e6a8dc9581b3ab2dacafda6446f6c65f4debe124f5870b6796ea1\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1722436062375,\"error\":null}, {\"id\":3841225687,\"status\":\"Pairing\",\"ciphertext\":null,\"plaintext\":[\"PAIRING\"],\"commited_in\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\",\"tied_by\":null,\"commitment\":\"213c1295d6721f3194745063190487e73853c21373218255d2af20c4b1ba6a7b\",\"sender\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"recipient\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"shared_secret\":\"094849bcf340d0791fa0bae31c9b58b8572ad3c9bd028de3a26e501b578cb24b\",\"key\":null,\"confirmed_by\":null,\"timestamp\":1722436062605,\"error\":null}]"; + +const ALICE_PAIRED_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"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]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\":{\"blockheight\":0,\"tweak\":\"dac814c1ceff86cac3476e028ffa6eda0d9858bd74288a0e6e9e5cef271f723c\",\"amount\":1200,\"script\":\"51205e349be9fff1dc0c8e6bae3d35679029c57d9e554f0bb9705b71491d9b7569f1\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:2\":{\"blockheight\":0,\"tweak\":\"6ebffdcaf1da7b160b167caed039e795f8b6d5168903972f9436aaedef574f28\",\"amount\":3935806,\"script\":\"5120fe0ec587ba0a8f8b1ef7c708a8b67723e55d45fb8e5c12ffc8874d61dedc3c16\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:1\":{\"blockheight\":0,\"tweak\":\"cfea493360d6ffe2bfd13e4c5c2f677351e0c038f1ce0cd5383fadad6adc79f1\",\"amount\":191,\"script\":\"51200f008ff13f876bf328c69f10ad8621c9770ff8d5eb1861cb67199189a6308bb9\",\"label\":null,\"spend_status\":\"Unspent\"}}},\"tx_history\":[]},\"current_session_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"current_session_key\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"current_session_revokation_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"paired_device\":{\"address\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"outgoing_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"revokation_index\":1,\"incoming_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"current_remote_key\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"current_session_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"current_session_revokation_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\"}}"; +const BOB_PAIRED_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"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]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\":{\"blockheight\":0,\"tweak\":\"898284108952bd8b0e74030e00b81c1b387ee151a810ca3b40143da227707df2\",\"amount\":1200,\"script\":\"5120c0ff94a1318f0061960a713c927ff175a0d71a791497e94e70601c3baae739b8\",\"label\":null,\"spend_status\":\"Unspent\"},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:1\":{\"blockheight\":0,\"tweak\":\"a68aed757eb3aca6bcbd0deb749eb26767963401e07d568b19f05f9945fce9b3\",\"amount\":248,\"script\":\"5120d3a39aed25fccd3338aa8c9d40c015febfb4361cffb6cfdcede3032317dc26ff\",\"label\":null,\"spend_status\":\"Unspent\"},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:2\":{\"blockheight\":0,\"tweak\":\"e02bb8059b6c787d22715be95de87ea75c120e0f4e0507233bb3e1547b50d98b\",\"amount\":99895292,\"script\":\"51203207d027bb48df9a7c5798091b8bd4912c436c19ea41f04b48ea5dad31118183\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}}}},\"tx_history\":[]},\"current_session_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"current_session_key\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"current_session_revokation_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"paired_device\":{\"address\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"outgoing_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"revokation_index\":1,\"incoming_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"current_remote_key\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"current_session_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\",\"current_session_revokation_outpoint\":\"0000000000000000000000000000000000000000000000000000000000000000:4294967295\"}}"; + +const ALICE_LOGGED_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"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]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[187,119,108,230,171,125,106,11],\"birthday\":1620,\"last_scan\":2146,\"outputs\":{\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\":{\"blockheight\":0,\"tweak\":\"2e3636950174a42842da254d7936f589e8c9ded6e17c90656bb759467fff9ea0\",\"amount\":1200,\"script\":\"51209c3a71193f7fc52482fd516a1a36f4df55f646a15f15ecc4f55497262b06e7c8\",\"label\":null,\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:1\":{\"blockheight\":0,\"tweak\":\"7c84a3074c18c23a65eceaca49a327989ef6e7240e0e080421afb80f06906d73\",\"amount\":306,\"script\":\"5120eb78084d7a2ccbdb7eb7e9bba7cf875c4e54a5aba0beac57c5d3e41133bd8fdd\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:0\":{\"blockheight\":0,\"tweak\":\"6e5c1d4690b9ff4fa26e5185ada25af5c2987650e629a518db8a43fdaad7a26c\",\"amount\":349,\"script\":\"512088ac90e180c87b7fa6aa33db4c72a8620cd08fda3ba1c71430b904eb068c587f\",\"label\":null,\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:2\":{\"blockheight\":0,\"tweak\":\"86a78efb4f522790d46096df9261435e3f7cab5f5129efe4ff77562fb4834a0c\",\"amount\":3935451,\"script\":\"5120c314279d078acaa41b5d897f98b81f09546001b6422e90e0b3f902ac7442a6b7\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":\"Unspent\"},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\":{\"blockheight\":0,\"tweak\":\"49471984d232f62afb7421c904a26ec073b968e76e3e1b8f4371f2f730ba627f\",\"amount\":191,\"script\":\"51203b12839f99ca62bd09eb277bab720b9bb506003ed5b3fa6654f37a42f3cf1825\",\"label\":null,\"spend_status\":\"Unspent\"},\"9a4a67cc5a40bf882d8b300d91024d7c97024b3b68b2df7745a5b9ea1df1888c:1\":{\"blockheight\":1620,\"tweak\":\"b8b63b3ed97d297b744135cfac2fb4a344c881a77543b71f1fcd16bc67514f26\",\"amount\":3938643,\"script\":\"51205b7b324bb71d411e32f2c61fda5d1db23f5c7d6d416a77fab87c913a1b120be1\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:1\":{\"blockheight\":0,\"tweak\":\"cfea493360d6ffe2bfd13e4c5c2f677351e0c038f1ce0cd5383fadad6adc79f1\",\"amount\":191,\"script\":\"51200f008ff13f876bf328c69f10ad8621c9770ff8d5eb1861cb67199189a6308bb9\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:2\":{\"blockheight\":0,\"tweak\":\"6ebffdcaf1da7b160b167caed039e795f8b6d5168903972f9436aaedef574f28\",\"amount\":3935806,\"script\":\"5120fe0ec587ba0a8f8b1ef7c708a8b67723e55d45fb8e5c12ffc8874d61dedc3c16\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:2\":{\"blockheight\":0,\"tweak\":\"e3e21d551e933199f8c977bc0362616bdfb128da7ca9728bd7254977541c39cc\",\"amount\":3936897,\"script\":\"5120df3af55a63bd056c5d6d09f47a3a19c382d938c08db8bc41a59c5235970209ad\",\"label\":\"ac14a827e2d023b8f7804303a47259366117d99ed932b641d4a8eaf1b82cc992\",\"spend_status\":{\"Spent\":\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:0\":{\"blockheight\":0,\"tweak\":\"dac814c1ceff86cac3476e028ffa6eda0d9858bd74288a0e6e9e5cef271f723c\",\"amount\":1200,\"script\":\"51205e349be9fff1dc0c8e6bae3d35679029c57d9e554f0bb9705b71491d9b7569f1\",\"label\":null,\"spend_status\":{\"Spent\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c\"}}}},\"tx_history\":[]},\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_key\":[193,95,100,240,34,120,208,149,63,78,80,240,135,212,31,167,234,42,121,233,178,209,49,231,189,60,70,89,71,185,1,187],\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\",\"paired_device\":{\"address\":\"sprt1qqf2kqh8n7lkupngfk2fxtmvyaq8sy3v2ramyeryweadqmsz7l6tg2qc9n4dl42ff8klz28nznr7mfzh6263xv555stwzextl2v4lvhg3aqq7ru8u\",\"outgoing_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"revokation_index\":1,\"incoming_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"current_remote_key\":[16,187,49,126,30,231,11,43,228,86,96,159,92,122,234,168,16,107,97,83,38,34,15,14,115,173,94,120,208,50,47,34],\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\"}}"; +const BOB_LOGGED_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"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]]]},\"network\":\"regtest\"},\"outputs\":{\"wallet_fingerprint\":[203,200,4,248,139,36,241,232],\"birthday\":2146,\"last_scan\":2146,\"outputs\":{\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\":{\"blockheight\":0,\"tweak\":\"73cd0a0ebe8e61c3f5ec6b414107934238c4642924272823fb630ef828c14a97\",\"amount\":248,\"script\":\"51202c1f1be3cff73416dc34de0d5f7760095a51f6b4a7bfa118441221718394beea\",\"label\":null,\"spend_status\":\"Unspent\"},\"78e97c940d3353718864c251489da99be99441323cabe619522169d22b030fb8:0\":{\"blockheight\":0,\"tweak\":\"898284108952bd8b0e74030e00b81c1b387ee151a810ca3b40143da227707df2\",\"amount\":1200,\"script\":\"5120c0ff94a1318f0061960a713c927ff175a0d71a791497e94e70601c3baae739b8\",\"label\":null,\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f:1\":{\"blockheight\":0,\"tweak\":\"f0ad83734cdc7d73575e5a32651390cf30b92cc7e44cf94ec37da46900ecaf71\",\"amount\":654,\"script\":\"5120230cc1e85829be238e666f469653cbc2f1c0e3675a9bf33e1d1f91115f5dd306\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:2\":{\"blockheight\":0,\"tweak\":\"b13107995241e7daaf13e89ff62a007dd592173c02284a46c9d40778e9fd8165\",\"amount\":99894746,\"script\":\"5120fc7226dc54ed54144d7f6081726fa1d6b5d0fc6aca09a0cc689cc9552e81db14\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":\"Unspent\"},\"e2c6ff9927c8a5f7a60087117732c07ab7cd82c0c65462e9c780eb5ce9c35292:0\":{\"blockheight\":0,\"tweak\":\"0e3395ff27bde9187ffaeeb2521f6277d3b83911f16ccbaf59a1a68d99a0ab93\",\"amount\":1200,\"script\":\"512010f06f764cbc923ec3198db946307bf0c06a1b4f09206055e47a6fec0a33d52c\",\"label\":null,\"spend_status\":{\"Spent\":\"576c2e53fe924d68deb7262cfc0e4023b5889652dec35671e1e7cf255d61c28f\"}},\"93722ea2fb9b74954210b4cdd1360e280b7ff1bc156d6b75f847e62411c588fb:0\":{\"blockheight\":0,\"tweak\":\"da5e3aa2378e3a257f99eb1e0ae4c672916f6a2f32a8ed9a8e146f2074da981b\",\"amount\":443,\"script\":\"51209eb9e950127b6a7d81668f25b4d5b164b42dafe59ce40b80e6c489ec983540d7\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:1\":{\"blockheight\":0,\"tweak\":\"a68aed757eb3aca6bcbd0deb749eb26767963401e07d568b19f05f9945fce9b3\",\"amount\":248,\"script\":\"5120d3a39aed25fccd3338aa8c9d40c015febfb4361cffb6cfdcede3032317dc26ff\",\"label\":null,\"spend_status\":\"Unspent\"},\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d:2\":{\"blockheight\":0,\"tweak\":\"e02bb8059b6c787d22715be95de87ea75c120e0f4e0507233bb3e1547b50d98b\",\"amount\":99895292,\"script\":\"51203207d027bb48df9a7c5798091b8bd4912c436c19ea41f04b48ea5dad31118183\",\"label\":\"56572fc770b52096879662f97f98263d3e126f5a4a38f00f2895a9dde4c47c1c\",\"spend_status\":{\"Spent\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f\"}},\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\":{\"blockheight\":0,\"tweak\":\"ac6c259ddf88509b3663a412f4d40403cafb3a89c8a6922770384ba1806ecda0\",\"amount\":1200,\"script\":\"512010bb317e1ee70b2be456609f5c7aeaa8106b615326220f0e73ad5e78d0322f22\",\"label\":null,\"spend_status\":\"Unspent\"},\"fbd9c63e0dd08c2569b51a0d6095a79ee2acfcac66acdb594328a095f1fadb63:1\":{\"blockheight\":2146,\"tweak\":\"678dbcbdb40cd3733c8dbbd508761a0937009cf75a9f466e3c98877e79037cbc\",\"amount\":99896595,\"script\":\"5120deab0c5a3d23de30477b0b5a95a261c96e29afdd9813c665d2bf025ad2b3f919\",\"label\":null,\"spend_status\":{\"Spent\":\"23a09cb1af6a2d350f02c38e9e8727f8ec0e75181f19f781ef6985862577792d\"}}}},\"tx_history\":[]},\"current_session_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:0\",\"current_session_key\":[92,106,141,254,85,117,14,178,239,50,33,247,83,151,23,25,144,142,183,115,190,26,14,113,238,72,13,18,29,254,37,87],\"current_session_revokation_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:1\",\"paired_device\":{\"address\":\"sprt1qqf50y6deqe7dqg3vj562xf3lmktqe3sct78ha6e9jh54sa3q2m5esq7x2tz0xrpm0ekclyyaszc2sh3ksm5gkumxpwegpa80lv5wgsuefqaufx8q\",\"outgoing_pairing_transaction\":[45,121,119,37,134,133,105,239,129,247,25,31,24,117,14,236,248,39,135,158,142,195,2,15,53,45,106,175,177,156,160,35],\"revokation_index\":1,\"incoming_pairing_transaction\":[184,15,3,43,210,105,33,82,25,230,171,60,50,65,148,233,155,169,157,72,81,194,100,136,113,83,51,13,148,124,233,120],\"current_remote_key\":[156,58,113,25,63,127,197,36,130,253,81,106,26,54,244,223,85,246,70,161,95,21,236,196,245,84,151,38,43,6,231,200],\"current_session_outpoint\":\"4b7a78bb8a715fa4875543025182b3f0bb1bc5ca44b852cab57c2929231ddf3f:0\",\"current_session_revokation_outpoint\":\"5e18963dcdd5e94b4b5dfaa147a6e62889a367d9fc1a016973f84c07a192982c:1\"}}"; fn helper_switch_device(wallet: String) { reset_device().unwrap(); - // debug!("{}", wallet); restore_device_from_sp_wallet(wallet.clone()).unwrap(); - // debug!("Restored device with wallet {}", wallet); } fn helper_get_alice_address() -> String { @@ -55,24 +72,38 @@ fn helper_get_bob_address() -> String { wallet.get_client().get_receiving_address() } -fn helper_get_tweak_data(transaction: &str, spk: ScriptBuf) -> String { +fn helper_get_tweak_data(transaction: &str, outpoints: HashMap) -> String { let tx = deserialize::(&Vec::from_hex(transaction).unwrap()).unwrap(); - 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(); + let mut outpoint_data = vec![]; + let mut witnesses = vec![]; + let mut spks = vec![]; + for prevout in tx.input { + outpoint_data.push(( + prevout.previous_output.txid.to_string(), + prevout.previous_output.vout, + )); + witnesses.push(prevout.witness); + if let Some(output) = outpoints.get(&prevout.previous_output) { + spks.push(ScriptBuf::from_hex(&output.script).unwrap()); + } + } + let mut input_pubkeys = vec![]; + for (spk, witness) in spks.iter().zip(witnesses) { + let input_pubkey = + get_pubkey_from_input(&vec![], &witness.to_vec(), spk.as_bytes()).unwrap(); + input_pubkeys.push(input_pubkey.unwrap()); + } + let ref_pubkeys: Vec<&PublicKey> = input_pubkeys.iter().collect(); + let tweak_data = calculate_tweak_data(&ref_pubkeys, &outpoint_data).unwrap(); tweak_data.to_string() } -fn helper_parse_transaction(transaction: &str, tweak_data: String) -> CachedMessage { - let new_tx_msg = - serde_json::to_string(&NewTxMessage::new(transaction.to_owned(), Some(tweak_data))) - .unwrap(); +fn helper_parse_transaction(transaction: &str, tweak_data: &str) -> CachedMessage { + let new_tx_msg = serde_json::to_string(&NewTxMessage::new( + transaction.to_owned(), + Some(tweak_data.to_owned()), + )) + .unwrap(); let network_msg = serde_json::to_string(&AnkNetworkMsg::new( sdk_common::network::AnkFlag::NewTx, &new_tx_msg, @@ -93,387 +124,364 @@ fn helper_parse_ank_msg(ank_network_msg: String) -> CachedMessage { }; } -fn helper_link_alice() { - const ALICE_SPEND_KEY: &str = - "93292e5b21042c6cfc742ba30e9d2a1e01609b12d154a1825184ed12c7b9631b"; - let encrypted_alice_key = encrypt_remote_key( - ALICE_SPEND_KEY.to_owned(), - Some("073ec0cd90cd77f5486cbfb586ed639c4d435d39bb038dc905d7a65762d29ff9".to_owned()), - Some("46b4e8e9cfb1b6fd139d480f".to_owned()), - ) - .unwrap(); - pair_device( - Vec::from_hex(&encrypted_alice_key).unwrap(), - helper_get_alice_address(), - REVOKATION_OUTPUT.to_owned(), - ) - .unwrap(); -} - -fn helper_link_bob() { - const BOB_ENCRYPTED_KEY: &str = "62f10cffb1ed127ef88826c0e65d21dc337c763db53a3d814e1bf21460b53d84d612995ab3b272ac395221bf49cb54df6250502fc8941ba06d85bd58"; - pair_device( - Vec::from_hex(BOB_ENCRYPTED_KEY).unwrap(), - helper_get_alice_address(), - REVOKATION_OUTPUT.to_owned(), - ) - .unwrap(); -} - -// #[wasm_bindgen_test] -// fn test_pairing_transaction() { -// setup(); - -// helper_switch_bob(); - -// // bob sends pairing transaction to alice -// let result = create_pairing_transaction(helper_get_alice_address(), 1); -// let bob_pairing_transaction = match result { -// Ok(t) => t, -// Err(e) => { -// panic!("create_pairing_transaction failed with {}", e.message); -// } -// }; - -// // get the tweak data to add to the transaction -// let bob_pairing_tweak_data = helper_get_tweak_data( -// &bob_pairing_transaction.transaction, -// ScriptBuf::from_hex(BOB_SPK).unwrap(), -// ); - -// // dump bob message cache -// let bob_msg_cache = dump_message_cache().unwrap(); -// reset_message_cache().unwrap(); - -// // switch to alice -// helper_switch_alice(); - -// // alice receives and parses that transaction -// helper_parse_transaction(&bob_pairing_transaction.transaction, bob_pairing_tweak_data); - -// // alice receives and parses the message -// let bob_sent_ank_msg = AnkNetworkMsg::new( -// sdk_common::network::AnkFlag::Cipher, -// &bob_pairing_transaction.new_network_msg.ciphertext.unwrap(), -// ); -// let mut pairing_msg = helper_parse_ank_msg(bob_sent_ank_msg.to_string()); - -// // Alice takes the key out of the plaintext cached message and returns it encrypted to Bob -// let bob_key = pairing_msg.plaintext.pop().unwrap(); -// let encrypted_bob_key = encrypt_remote_key( -// bob_key, -// Some("d8ac223089c8f5e575a06bc0e7071a0dc1124688722ecb34ccf9b3c95e5baaa8".to_owned()), -// Some("62f10cffb1ed127ef88826c0".to_owned()), -// ) -// .unwrap(); -// let cipher_msg = CipherMessage::new(helper_get_alice_address(), encrypted_bob_key.clone()); -// let encrypted_payload = -// encrypt_with_key(cipher_msg.to_string(), pairing_msg.shared_secret.unwrap()).unwrap(); -// let alice_response_msg = -// AnkNetworkMsg::new(sdk_common::network::AnkFlag::Cipher, &encrypted_payload).to_string(); - -// // same switch back to Bob -// // let alice_msg_cache = dump_message_cache().unwrap(); -// reset_message_cache().unwrap(); - -// helper_switch_bob(); - -// set_message_cache(bob_msg_cache).unwrap(); - -// let bob_received_msg = helper_parse_ank_msg(alice_response_msg); -// assert!(*bob_received_msg.plaintext.get(0).unwrap() == encrypted_bob_key); - -// // take the revokation output -// let keypair = Keypair::from_seckey_str( -// &Secp256k1::signing_only(), -// &bob_received_msg.shared_secret.clone().unwrap(), -// ) -// .unwrap(); -// let spk = ScriptBuf::new_p2tr_tweaked(keypair.x_only_public_key().0.dangerous_assume_tweaked()); -// let pairing_transaction = -// deserialize::(&Vec::from_hex(&bob_pairing_transaction.transaction).unwrap()) -// .unwrap(); - -// let vout = pairing_transaction -// .output -// .iter() -// .position(|o| o.script_pubkey == spk) -// .unwrap(); - -// let revokation_outpoint = -// OutPoint::new(pairing_transaction.txid(), vout.try_into().unwrap()).to_string(); - -// pair_device( -// Vec::from_hex(bob_received_msg.plaintext.get(0).unwrap()).unwrap(), -// bob_received_msg.recipient.clone().unwrap(), -// revokation_outpoint.clone(), -// ) -// .unwrap(); - -// // Now we can set a trusted channel, which is basically the pairing -// let mut trusted_channel = TrustedChannel::new(bob_received_msg.recipient.unwrap()).unwrap(); -// trusted_channel -// .set_revokation(revokation_outpoint, bob_received_msg.shared_secret.unwrap()) -// .unwrap(); -// } - #[wasm_bindgen_test] -fn test_alice_notifies_bob() { +fn test_pairing() { setup(); - debug!("==============================================\nStarting test_alice_notifies_bob\n=============================================="); + debug!("==============================================\nStarting test_pairing\n=============================================="); - // Alice notifies Bob - helper_switch_device(ALICE_START_WALLET.to_owned()); - helper_link_alice(); + // ========================= Alice + helper_switch_device(ALICE_LOGIN_WALLET.to_owned()); - let cipher_msg = CipherMessage::new(helper_get_alice_address(), "TEST".to_owned()); + debug!("Alice sends a pairing transaction to Bob"); + let alice_pairing_tx = create_pairing_transaction(helper_get_bob_address(), 1).unwrap(); - debug!("Alice notifies Bob"); - let notification_tx = - create_notification_transaction(helper_get_bob_address(), cipher_msg, 1).unwrap(); + debug!("Alice pairing tx: {}", alice_pairing_tx.txid); - // debug!("new_network_msg: {:?}", notification_tx.new_network_msg); - // debug!("notification_tx: {}", serde_json::to_string(¬ification_tx).unwrap()); - - let notification_tweak_data = helper_get_tweak_data( - ¬ification_tx.transaction, - ScriptBuf::from_hex(ALICE_SPK).unwrap(), - ); - - let ank_msg = AnkNetworkMsg::new( + // This is sent on 4nk network along with the transaction + let alice_pairing_cipher = AnkNetworkMsg::new( sdk_common::network::AnkFlag::Cipher, - ¬ification_tx.new_network_msg.ciphertext.unwrap(), + &alice_pairing_tx.new_network_msg.ciphertext.unwrap(), ); - debug!("Alice parse her own notification transaction"); - // Alice parse her own transaction to update her utxos - helper_parse_transaction( - ¬ification_tx.transaction, - notification_tweak_data.clone(), - ); - - // debug!("Alice parsed transaction {}", notification_tx.txid); - // debug!("alice_wallet_dump: {:?}", dump_watch_only_wallet().unwrap()); - - reset_device().unwrap(); - helper_switch_device(BOB_START_WALLET.to_owned()); - helper_link_bob(); - - debug!( - "Bob parses notification transaction {}", - notification_tx.txid - ); - // bob parse the transaction and the message - helper_parse_transaction(¬ification_tx.transaction, notification_tweak_data); - helper_parse_ank_msg(ank_msg.to_string()); -} - -#[wasm_bindgen_test] -fn test_bob_challenges_alice() { - setup(); - debug!("==============================================\nStarting test_bob_challenges_alice\n=============================================="); - helper_switch_device(BOB_CHALLENGE_WALLET.to_owned()); - helper_link_bob(); - - set_message_cache(vec![BOB_CHALLENGE_CACHE.to_owned()]).unwrap(); - let notification_msg: CachedMessage = serde_json::from_str(BOB_CHALLENGE_CACHE).unwrap(); - - let commited_in = notification_msg.commited_in.unwrap(); - - let get_outputs_result = get_outputs().unwrap(); - - let bob_outputs: HashMap = get_outputs_result.into_serde().unwrap(); - - let bob_spk = &bob_outputs.get(&commited_in).unwrap().script; - - debug!("Bob sends a challenge transaction back to Alice"); - let confirmation_tx = create_confirmation_transaction(notification_msg.id, 1).unwrap(); - - let confirmation_tweak_data = helper_get_tweak_data( - &confirmation_tx.transaction, - ScriptBuf::from_hex(&bob_spk).unwrap(), - ); - - debug!("Bob parsing its own confirmation tx"); - helper_parse_transaction( - &confirmation_tx.transaction, - confirmation_tweak_data.clone(), - ); - - reset_device().unwrap(); - helper_switch_device(ALICE_CHALLENGE_WALLET.to_owned()); - helper_link_alice(); - - set_message_cache(vec![ALICE_CHALLENGE_CACHE.to_owned()]).unwrap(); - - debug!("Alice parsing confirmation tx"); - helper_parse_transaction(&confirmation_tx.transaction, confirmation_tweak_data); -} - -#[wasm_bindgen_test] -fn test_alice_answers_bob() { - setup(); - debug!("==============================================\nStarting test_alice_answers_bob\n=============================================="); - helper_switch_device(ALICE_ANSWER_WALLET.to_owned()); - helper_link_alice(); - - set_message_cache(vec![ALICE_ANSWER_CACHE.to_owned()]).unwrap(); - let challenge_msg: CachedMessage = serde_json::from_str(ALICE_ANSWER_CACHE).unwrap(); - - debug!("Alice answers bob's challenge"); - let answer_tx = answer_confirmation_transaction(challenge_msg.id, 1).unwrap(); - - // debug!("answer_tx: {:?}", answer_tx.new_network_msg); - let confirmed_by = challenge_msg.confirmed_by.unwrap(); - debug!("confirmed_by: {}", confirmed_by); - let get_outputs_result = get_outputs().unwrap(); let alice_outputs: HashMap = get_outputs_result.into_serde().unwrap(); - let alice_spk = &alice_outputs.get(&confirmed_by).unwrap().script; + let alice_pairing_tweak_data = + helper_get_tweak_data(&alice_pairing_tx.transaction, alice_outputs); - let answer_tweak_data = helper_get_tweak_data( - &answer_tx.transaction, - ScriptBuf::from_hex(&alice_spk).unwrap(), + // Alice parse her own transaction + let alice_msg_id = + helper_parse_transaction(&alice_pairing_tx.transaction, &alice_pairing_tweak_data).id; + + let alice_wallet = dump_wallet().unwrap(); + let alice_cache = dump_message_cache().unwrap(); + + // ======================= Bob + reset_device().unwrap(); + helper_switch_device(BOB_LOGIN_WALLET.to_owned()); + + // Bob receives Alice pairing transaction + // if he agrees, he must send another pairing transaction to Alice + // he can also spend the output that notified him that will become Alice first session key + debug!("Bob parses Alice pairing transaction"); + helper_parse_transaction(&alice_pairing_tx.transaction, &alice_pairing_tweak_data); + let alice_pairing_res = helper_parse_ank_msg(alice_pairing_cipher.to_string()); + + assert!(alice_pairing_res.status == CachedMessageStatus::Pairing); + + // Bob takes the txid of the incoming transaction from Alice, he will need it for pairing + let incoming_txid = alice_pairing_res.commited_in.unwrap().txid; + + // At this point, user must validate the pairing proposal received from Alice + + debug!("Bob sends a pairing transaction back"); + let bob_pairing_tx = create_pairing_transaction(alice_pairing_res.sender.unwrap(), 1).unwrap(); + + let bob_pairing_cipher = AnkNetworkMsg::new( + sdk_common::network::AnkFlag::Cipher, + &bob_pairing_tx.new_network_msg.ciphertext.unwrap(), ); - debug!("Alice parsing its own answer tx"); - debug!( - "message: {}", - serde_json::to_string(&answer_tx.new_network_msg).unwrap() + let get_outputs_result = get_outputs().unwrap(); + + let bob_outputs: HashMap = get_outputs_result.into_serde().unwrap(); + + let bob_pairing_tweak_data = helper_get_tweak_data(&bob_pairing_tx.transaction, bob_outputs); + + helper_parse_transaction(&bob_pairing_tx.transaction, &bob_pairing_tweak_data); + + debug!("Bob pairs device with Alice"); + pair_device(bob_pairing_tx.new_network_msg.id, incoming_txid.to_string()).unwrap(); + + // ======================== Alice + reset_device().unwrap(); + helper_switch_device(alice_wallet); + set_message_cache(alice_cache).unwrap(); + + // parse Bob's pairing transaction + helper_parse_transaction(&bob_pairing_tx.transaction, &bob_pairing_tweak_data); + let bob_pairing_msg = helper_parse_ank_msg(bob_pairing_cipher.to_string()); + + assert!(bob_pairing_msg.status == CachedMessageStatus::Pairing); + + debug!("Alice pairs device"); + pair_device(alice_msg_id, bob_pairing_tx.txid).unwrap(); +} + +#[wasm_bindgen_test] +fn test_first_login() { + setup(); + debug!("==============================================\nStarting test_first_login\n=============================================="); + + restore_device(BOB_PAIRED_DEVICE.to_owned()).unwrap(); + set_message_cache( + serde_json::from_str::>(BOB_PAIRING_CACHE) + .unwrap() + .into_iter() + .map(|v| v.to_string()) + .collect(), + ) + .unwrap(); + + // Bob can now spend the notification output, that will become Alice's first session key + debug!("Bob first login"); + let bob_first_login_tx = create_login_transaction(1).unwrap(); + let bob_login_cipher = AnkNetworkMsg::new( + sdk_common::network::AnkFlag::Cipher, + &bob_first_login_tx.new_network_msg.ciphertext.unwrap(), ); - helper_parse_transaction(&answer_tx.transaction, answer_tweak_data.clone()); + + let get_outputs_result = get_outputs().unwrap(); + + let bob_outputs: HashMap = get_outputs_result.into_serde().unwrap(); + + let bob_login_tweak_data = helper_get_tweak_data(&bob_first_login_tx.transaction, bob_outputs); + + debug!("Bob parses his own login transaction"); + helper_parse_transaction(&bob_first_login_tx.transaction, &bob_login_tweak_data); + + let bob_device = dump_device().unwrap(); + let bob_cache = dump_message_cache().unwrap(); + + // ======================== Alice + reset_device().unwrap(); + restore_device(ALICE_PAIRED_DEVICE.to_owned()).unwrap(); + set_message_cache( + serde_json::from_str::>(ALICE_PAIRING_CACHE) + .unwrap() + .into_iter() + .map(|v| v.to_string()) + .collect(), + ) + .unwrap(); + + debug!("Alice finds out the login demand from Bob"); + helper_parse_transaction(&bob_first_login_tx.transaction, &bob_login_tweak_data); + let bob_login_msg = helper_parse_ank_msg(bob_login_cipher.to_string()); + + // At this point Alice can fire up the revokation output if the login demand is illegitimate + // OR she must answer with a login transaction to Bob + debug!("Alice first login"); + let alice_first_login_tx = create_login_transaction(1).unwrap(); + let alice_login_cipher = AnkNetworkMsg::new( + sdk_common::network::AnkFlag::Cipher, + &alice_first_login_tx.new_network_msg.ciphertext.unwrap(), + ); + + let get_outputs_result = get_outputs().unwrap(); + + let alice_outputs: HashMap = get_outputs_result.into_serde().unwrap(); + + let alice_login_tweak_data = + helper_get_tweak_data(&alice_first_login_tx.transaction, alice_outputs); + + helper_parse_transaction(&alice_first_login_tx.transaction, &alice_login_tweak_data); + + login(bob_login_msg.id, alice_first_login_tx.transaction.clone()).unwrap(); + + // ======================= Bob + reset_device().unwrap(); + restore_device(bob_device).unwrap(); + set_message_cache(bob_cache).unwrap(); + + helper_parse_transaction(&alice_first_login_tx.transaction, &alice_login_tweak_data); + let alice_login_msg = helper_parse_ank_msg(alice_login_cipher.to_string()); + + assert!(alice_login_msg.status == CachedMessageStatus::Login); + + login(alice_login_msg.id, bob_first_login_tx.transaction).unwrap(); +} + +#[wasm_bindgen_test] +fn test_login() { + setup(); + debug!("==============================================\nStarting test_login\n=============================================="); + + restore_device(ALICE_LOGGED_DEVICE.to_owned()).unwrap(); + + debug!("Alice sends a login transaction to Bob, which creates a new key for him"); + let login_tx = create_login_transaction(1).unwrap(); + + let get_outputs_result = get_outputs().unwrap(); + + let alice_outputs: HashMap = get_outputs_result.into_serde().unwrap(); + + let login_tweak_data = helper_get_tweak_data( + &login_tx.transaction, + alice_outputs + ); + + helper_parse_transaction(&login_tx.transaction, &login_tweak_data); reset_device().unwrap(); - helper_switch_device(BOB_ANSWER_WALLET.to_owned()); - helper_link_bob(); + restore_device(BOB_LOGGED_DEVICE.to_owned()).unwrap(); - set_message_cache(vec![BOB_ANSWER_CACHE.to_owned()]).unwrap(); + helper_parse_transaction(&login_tx.transaction, &login_tweak_data); - debug!("Bob parses answer transaction {}", answer_tx.txid); - let answer_msg = helper_parse_transaction(&answer_tx.transaction, answer_tweak_data); - debug!( - "bob's message: {}", - serde_json::to_string(&answer_msg).unwrap() - ); + // Bob must confirm that he agrees to log in + + // Boutons "login" ou "Refuser" + // At this point Bob can fire up the revokation output if the login demand is illegitimate + // revoke_paired_device(1).unwrap(); + // OR she must answer with a login transaction to Alice + create_login_transaction(1).unwrap(); } // #[wasm_bindgen_test] -// fn test_linking_devices() { +// fn test_alice_sends_message_through_trusted_channel() { // setup(); -// helper_switch_bob(); +// debug!("==============================================\nStarting test_alice_sends_message_through_trusted_channel\n=============================================="); -// // bob sends pairing transaction to alice -// let result = create_pairing_transaction(helper_get_alice_address(), 1); -// let bob_pairing_transaction = match result { -// Ok(t) => t, -// Err(e) => { -// panic!("create_pairing_transaction failed with {}", e.message); -// } -// }; +// restore_device(ALICE_PAIRED_DEVICE.to_owned()).unwrap(); -// // get the tweak data to add to the transaction -// let bob_pairing_tweak_data = helper_get_tweak_data( -// &bob_pairing_transaction.transaction, -// ScriptBuf::from_hex(BOB_SPK).unwrap(), -// ); +// set_message_cache(vec![ALICE_FINAL_CACHE.to_owned()]).unwrap(); +// let answered_msg: CachedMessage = serde_json::from_str(ALICE_FINAL_CACHE).unwrap(); -// // alice receives and parses that transaction -// helper_switch_alice(); +// debug!("Alice cache: {:?}", answered_msg); -// helper_parse_transaction(&bob_pairing_transaction.transaction, bob_pairing_tweak_data); +// // Bob sends a message to Alice +// let secret_msg = "Hello Alice"; +// let cipher = +// encrypt_with_key(secret_msg.to_owned(), answered_msg.shared_secret.unwrap()).unwrap(); +// let bob_msg = AnkNetworkMsg::new(sdk_common::network::AnkFlag::Cipher, &cipher); -// // alice receives and parses the message -// let pairing_msg = -// helper_parse_cipher_msg(bob_pairing_transaction.new_network_msg.ciphertext.unwrap()); - -// // and sends the encrypted key back in a confirm transaction -// let result = create_confirmation_transaction(pairing_msg.id, 1); -// let alice_confirm_transaction = match result { -// Ok(r) => r, -// Err(e) => { -// panic!("create_pairing_transaction failed with {}", e.message); -// } -// }; - -// // get the tweak data to add to the transaction -// let alice_confirm_tweak_data = helper_get_tweak_data( -// &alice_confirm_transaction.transaction, -// helper_get_spk( -// bob_pairing_transaction.transaction, -// alice_confirm_transaction -// .new_network_msg -// .commited_in -// .unwrap(), -// ), -// ); - -// // alice parses her own transaction to update her utxoset -// helper_parse_transaction( -// &alice_confirm_transaction.transaction, -// alice_confirm_tweak_data.clone(), -// ); - -// // alice sends her own pairing transaction -// let result = create_pairing_transaction(helper_get_bob_address(), 1); -// let alice_pairing_transaction = match result { -// Ok(t) => t, -// Err(e) => { -// panic!("create_pairing_transaction failed with {}", e.message); -// } -// }; - -// // get the tweak data to add to the transaction -// let alice_pairing_tweak_data = helper_get_tweak_data( -// &alice_pairing_transaction.transaction, -// ScriptBuf::from_hex(ALICE_SPK).unwrap(), -// ); - -// helper_switch_bob(); - -// // bob receives the spend_key from alice and does the same thing -// helper_parse_transaction( -// &alice_pairing_transaction.transaction, -// alice_pairing_tweak_data, -// ); - -// let pairing_msg = helper_parse_cipher_msg( -// alice_pairing_transaction -// .new_network_msg -// .ciphertext -// .unwrap(), -// ); - -// // let result = create_confirmation_transaction(pairing_msg.id, 1); -// // let bob_confirm_transaction = match result { -// // Ok(r) => r, -// // Err(e) => { -// // panic!("create_pairing_transaction failed with {}", e.message); -// // } -// // }; - -// // bob also received the confirmation transaction from alice, containing his own encrypted key -// log::debug!("Parsing alice confirmation transaction"); -// helper_parse_transaction( -// &alice_confirm_transaction.transaction, -// alice_confirm_tweak_data, -// ); - -// log::debug!("Parsing the message that goes with it"); -// let confirmation_msg = helper_parse_cipher_msg( -// alice_confirm_transaction -// .new_network_msg -// .ciphertext -// .unwrap(), -// ); -// log::debug!("{:?}", confirmation_msg); - -// // bob can now update its device with the linking information -// pair_device( -// confirmation_msg.plaintext.get(0).unwrap().to_owned().into(), -// confirmation_msg.recipient.unwrap(), -// OutPoint::null().to_string(), -// ) -// .unwrap(); +// // Alice can find the message +// let mut result = helper_parse_ank_msg(bob_msg.to_string()); +// assert!(result.plaintext.pop() == Some(secret_msg.to_owned())); +// } + +// #[wasm_bindgen_test] +// fn test_alice_notifies_bob() { +// setup(); +// debug!("==============================================\nStarting test_alice_notifies_bob\n=============================================="); + +// // Alice notifies Bob +// helper_switch_device(ALICE_START_WALLET.to_owned()); +// helper_link_alice(); + +// let cipher_msg = CipherMessage::new(helper_get_alice_address(), "TEST".to_owned()); + +// debug!("Alice notifies Bob"); +// let notification_tx = +// create_notification_transaction(helper_get_bob_address(), cipher_msg, 1).unwrap(); + +// let get_outputs_result = get_outputs().unwrap(); + +// let alice_outputs: HashMap = get_outputs_result.into_serde().unwrap(); +// let notification_tweak_data = helper_get_tweak_data( +// ¬ification_tx.transaction, +// alice_outputs +// ); + +// let ank_msg = AnkNetworkMsg::new( +// sdk_common::network::AnkFlag::Cipher, +// ¬ification_tx.new_network_msg.ciphertext.unwrap(), +// ); + +// debug!("Alice parse her own notification transaction"); +// // Alice parse her own transaction to update her utxos +// helper_parse_transaction( +// ¬ification_tx.transaction, +// notification_tweak_data.clone(), +// ); + +// // debug!("Alice parsed transaction {}", notification_tx.txid); +// debug!("alice cache: {:?}", dump_message_cache().unwrap()); + +// reset_device().unwrap(); +// helper_switch_device(BOB_START_WALLET.to_owned()); +// helper_link_bob(); + +// debug!( +// "Bob parses notification transaction {}", +// notification_tx.txid +// ); +// // bob parse the transaction and the message +// helper_parse_transaction(¬ification_tx.transaction, notification_tweak_data); +// helper_parse_ank_msg(ank_msg.to_string()); +// debug!("bob cache: {:?}", dump_message_cache().unwrap()); +// } + +// #[wasm_bindgen_test] +// fn test_bob_challenges_alice() { +// setup(); +// debug!("==============================================\nStarting test_bob_challenges_alice\n=============================================="); +// helper_switch_device(BOB_CHALLENGE_WALLET.to_owned()); +// helper_link_bob(); + +// set_message_cache(vec![BOB_CHALLENGE_CACHE.to_owned()]).unwrap(); +// let notification_msg: CachedMessage = serde_json::from_str(BOB_CHALLENGE_CACHE).unwrap(); + +// let get_outputs_result = get_outputs().unwrap(); + +// let bob_outputs: HashMap = get_outputs_result.into_serde().unwrap(); + +// debug!("Bob sends a challenge transaction back to Alice"); +// let confirmation_tx = create_confirmation_transaction(notification_msg.id, 1).unwrap(); + +// let confirmation_tweak_data = helper_get_tweak_data( +// &confirmation_tx.transaction, +// bob_outputs +// ); + +// debug!("Bob parsing its own confirmation tx"); +// helper_parse_transaction( +// &confirmation_tx.transaction, +// confirmation_tweak_data.clone(), +// ); + +// debug!("bob wallet: {:?}", dump_wallet().unwrap()); +// debug!("bob cache: {:?}", dump_message_cache().unwrap()); +// reset_device().unwrap(); +// helper_switch_device(ALICE_CHALLENGE_WALLET.to_owned()); +// helper_link_alice(); + +// set_message_cache(vec![ALICE_CHALLENGE_CACHE.to_owned()]).unwrap(); + +// debug!("Alice parsing confirmation tx"); +// helper_parse_transaction(&confirmation_tx.transaction, confirmation_tweak_data); +// debug!("alice wallet: {:?}", dump_wallet().unwrap()); +// debug!("alice cache: {:?}", dump_message_cache().unwrap()); +// } + +// #[wasm_bindgen_test] +// fn test_alice_answers_bob() { +// setup(); +// debug!("==============================================\nStarting test_alice_answers_bob\n=============================================="); +// helper_switch_device(ALICE_ANSWER_WALLET.to_owned()); +// helper_link_alice(); + +// set_message_cache(vec![ALICE_ANSWER_CACHE.to_owned()]).unwrap(); +// let challenge_msg: CachedMessage = serde_json::from_str(ALICE_ANSWER_CACHE).unwrap(); + +// debug!("Alice answers bob's challenge"); +// let answer_tx = answer_confirmation_transaction(challenge_msg.id, 1).unwrap(); + +// // debug!("answer_tx: {:?}", answer_tx.transaction); +// let get_outputs_result = get_outputs().unwrap(); + +// let alice_outputs: HashMap = get_outputs_result.into_serde().unwrap(); + +// let answer_tweak_data = helper_get_tweak_data( +// &answer_tx.transaction, +// alice_outputs, +// ); + +// debug!("Alice final wallet: {:?}", dump_wallet().unwrap()); +// debug!("Alice cache: {:?}", dump_message_cache().unwrap()); +// reset_device().unwrap(); +// helper_switch_device(BOB_ANSWER_WALLET.to_owned()); +// helper_link_bob(); + +// set_message_cache(vec![BOB_ANSWER_CACHE.to_owned()]).unwrap(); + +// debug!("Bob parses answer transaction {}", answer_tx.txid); +// let answer_msg = helper_parse_transaction(&answer_tx.transaction, answer_tweak_data); +// // debug!( +// // "bob's message: {}", +// // serde_json::to_string(&answer_msg).unwrap() +// // ); +// debug!("Bob final wallet: {:?}", dump_wallet().unwrap()); +// debug!("Bob cache: {:?}", dump_message_cache().unwrap()); // }