add notify address for message
This commit is contained in:
parent
a6f4a5122c
commit
8f6918748d
@ -355,24 +355,69 @@ pub fn parse_network_msg(raw: String) -> ApiResult<parseNetworkMsgReturn> {
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn parse_4nk_msg(raw: String) -> Option<String>{
|
||||
if let Ok(msg) = AnkNetworkMsg::new(&raw) {
|
||||
match msg.topic {
|
||||
AnkTopic::Faucet => {
|
||||
match Txid::from_str(msg.content) {
|
||||
Ok(txid) => {
|
||||
// return the txid for verification
|
||||
Some(txid.to_string())
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Invalid txid with a \"faucet\" message: {}", e.to_string());
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn get_outpoints_for_user(pre_id: String) -> ApiResult<outputs_list> {
|
||||
let connected_users = lock_connected_users()?;
|
||||
let user = connected_users.get(&pre_id).ok_or(ApiError {
|
||||
message: "Can't find user".to_owned(),
|
||||
})?;
|
||||
Ok(outputs_list(user.get_all_outputs()))
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn is_tx_owned_by_user(pre_id: String, tx: String) -> ApiResult<bool> {
|
||||
let transaction = deserialize::<Transaction>(&Vec::from_hex(&tx)?)?;
|
||||
let txid = transaction.txid();
|
||||
let connected_users = lock_connected_users()?;
|
||||
let user = connected_users.get(&pre_id).ok_or(ApiError {
|
||||
message: "Can't find user".to_owned(),
|
||||
})?;
|
||||
|
||||
if let Some(_) = user
|
||||
.recover
|
||||
.get_outputs()
|
||||
.to_outpoints_list()
|
||||
.iter()
|
||||
.find(|(outpoint, output)| outpoint.txid == txid)
|
||||
{
|
||||
Ok(true)
|
||||
} else {
|
||||
log::debug!("Can't parse message as a valid 4nk message: {}", raw);
|
||||
None
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Tsify, Serialize, Deserialize)]
|
||||
#[tsify(into_wasm_abi, from_wasm_abi)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct createNotificationTransactionReturn {
|
||||
pub transaction: String,
|
||||
pub spaddress2secret: HashMap<String, String>,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn create_notification_transaction(
|
||||
user_pre_id: String,
|
||||
recipient: String,
|
||||
message: String,
|
||||
) -> ApiResult<createNotificationTransactionReturn> {
|
||||
let sp_address: SilentPaymentAddress = recipient.try_into()?;
|
||||
|
||||
let (transaction, notification_information) =
|
||||
create_transaction_for_address(user_pre_id, sp_address, message)?;
|
||||
|
||||
// The secret is an ecc point and *must* be hashed to produce a proper ecdh secret
|
||||
// For now we propose to implement a tagged hash for it
|
||||
// It could be interesting to add some piece of data to allow for the derivation of multiple secrets
|
||||
|
||||
let spaddress2secret = notification_information
|
||||
.into_iter()
|
||||
.map(|(address, shared_pubkey)| {
|
||||
let shared_secret = AnkSharedSecret::new_from_public_key(shared_pubkey);
|
||||
(address.into(), shared_secret.to_string())
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(createNotificationTransactionReturn {
|
||||
transaction: serialize(&transaction).to_lower_hex_string(),
|
||||
spaddress2secret,
|
||||
})
|
||||
}
|
||||
|
@ -1,8 +1,14 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::Result;
|
||||
use anyhow::{Error, Result};
|
||||
|
||||
use rand::Rng;
|
||||
use sp_backend::bitcoin::policy::DUST_RELAY_TX_FEE;
|
||||
use sp_backend::bitcoin::secp256k1::ecdh::SharedSecret;
|
||||
use sp_backend::bitcoin::{block, Amount, OutPoint};
|
||||
use sp_backend::silentpayments::sending::SilentPaymentAddress;
|
||||
use sp_backend::silentpayments::utils::receiving::calculate_shared_secret;
|
||||
use sp_backend::spclient::{OutputList, OwnedOutput, Recipient, SpClient};
|
||||
use sp_backend::{
|
||||
bitcoin::{
|
||||
secp256k1::{PublicKey, Scalar, XOnlyPublicKey},
|
||||
@ -15,9 +21,79 @@ use crate::user::{lock_connected_users, CONNECTED_USERS};
|
||||
|
||||
type FoundOutputs = HashMap<Option<Label>, HashMap<XOnlyPublicKey, Scalar>>;
|
||||
|
||||
pub fn check_transaction(tx: Transaction, tweak_data: PublicKey) -> Result<FoundOutputs> {
|
||||
type NotificationInformation = (Transaction, Vec<(SilentPaymentAddress, PublicKey)>);
|
||||
|
||||
pub fn create_transaction_for_address(
|
||||
send_as: String,
|
||||
sp_address: SilentPaymentAddress,
|
||||
message: String,
|
||||
) -> Result<NotificationInformation> {
|
||||
let connected_users = lock_connected_users()?;
|
||||
|
||||
let sender = connected_users
|
||||
.get(&send_as)
|
||||
.ok_or(Error::msg("Unknown sender"))?;
|
||||
|
||||
let sp_wallet = if sp_address.is_testnet() {
|
||||
&sender.recover
|
||||
} else {
|
||||
if let Some(main) = &sender.main {
|
||||
main
|
||||
} else {
|
||||
return Err(Error::msg("Can't spend on mainnet"));
|
||||
}
|
||||
};
|
||||
|
||||
let available_outpoints = sender.recover.get_outputs().to_spendable_list();
|
||||
|
||||
// Here we need to add more heuristics about which outpoint we spend
|
||||
// For now let's keep it simple
|
||||
|
||||
let mut inputs: HashMap<OutPoint, OwnedOutput> = HashMap::new();
|
||||
|
||||
let total_available =
|
||||
available_outpoints
|
||||
.into_iter()
|
||||
.try_fold(Amount::from_sat(0), |acc, (outpoint, output)| {
|
||||
let new_total = acc + output.amount;
|
||||
inputs.insert(outpoint, output);
|
||||
if new_total > Amount::from_sat(1000) {
|
||||
Err(new_total)
|
||||
} else {
|
||||
Ok(new_total)
|
||||
}
|
||||
});
|
||||
|
||||
match total_available {
|
||||
Err(total) => log::debug!("Spending {} outputs totaling {} sats", inputs.len(), total),
|
||||
Ok(_) => return Err(Error::msg("Not enought fund available")),
|
||||
}
|
||||
|
||||
let recipient = Recipient {
|
||||
address: sp_address.into(),
|
||||
amount: Amount::from_sat(1000),
|
||||
nb_outputs: 1,
|
||||
};
|
||||
|
||||
let mut new_psbt = sp_wallet
|
||||
.get_client()
|
||||
.create_new_psbt(inputs, vec![recipient], None)?;
|
||||
log::debug!("Created psbt: {}", new_psbt);
|
||||
SpClient::set_fees(&mut new_psbt, Amount::from_sat(1000), sp_address.into())?;
|
||||
let shared_secrets: Vec<(SilentPaymentAddress, PublicKey)> =
|
||||
sp_wallet.get_client().fill_sp_outputs(&mut new_psbt)?;
|
||||
log::debug!("Definitive psbt: {}", new_psbt);
|
||||
let mut aux_rand = [0u8; 32];
|
||||
rand::thread_rng().fill(&mut aux_rand);
|
||||
let mut signed = sp_wallet.get_client().sign_psbt(new_psbt, &aux_rand)?;
|
||||
log::debug!("signed psbt: {}", signed);
|
||||
SpClient::finalize_psbt(&mut signed)?;
|
||||
|
||||
let final_tx = signed.extract_tx()?;
|
||||
|
||||
Ok((final_tx, shared_secrets))
|
||||
}
|
||||
|
||||
pub fn check_transaction(
|
||||
tx: &Transaction,
|
||||
blockheight: u32,
|
||||
|
@ -740,6 +740,30 @@ class Services {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async notify_address_for_message(sp_address: string, message: string): Promise<createNotificationTransactionReturn | null> {
|
||||
const services = await Services.getInstance();
|
||||
let user: User;
|
||||
try {
|
||||
let possibleUser = await services.getUserInfo();
|
||||
if (!possibleUser) {
|
||||
console.error("No user loaded, please first create a new user or login");
|
||||
return null;
|
||||
} else {
|
||||
user = possibleUser;
|
||||
}
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
try {
|
||||
let notificationInfo: createNotificationTransactionReturn = services.sdkClient.create_notification_transaction(user, sp_address, message);
|
||||
return notificationInfo;
|
||||
} catch {
|
||||
console.error("Failed to create notification transaction for user", user);
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Services;
|
||||
|
Loading…
x
Reference in New Issue
Block a user