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]
|
#[wasm_bindgen]
|
||||||
pub fn parse_4nk_msg(raw: String) -> Option<String>{
|
pub fn get_outpoints_for_user(pre_id: String) -> ApiResult<outputs_list> {
|
||||||
if let Ok(msg) = AnkNetworkMsg::new(&raw) {
|
let connected_users = lock_connected_users()?;
|
||||||
match msg.topic {
|
let user = connected_users.get(&pre_id).ok_or(ApiError {
|
||||||
AnkTopic::Faucet => {
|
message: "Can't find user".to_owned(),
|
||||||
match Txid::from_str(msg.content) {
|
})?;
|
||||||
Ok(txid) => {
|
Ok(outputs_list(user.get_all_outputs()))
|
||||||
// return the txid for verification
|
}
|
||||||
Some(txid.to_string())
|
|
||||||
},
|
#[wasm_bindgen]
|
||||||
Err(e) => {
|
pub fn is_tx_owned_by_user(pre_id: String, tx: String) -> ApiResult<bool> {
|
||||||
log::error!("Invalid txid with a \"faucet\" message: {}", e.to_string());
|
let transaction = deserialize::<Transaction>(&Vec::from_hex(&tx)?)?;
|
||||||
None
|
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 {
|
} else {
|
||||||
log::debug!("Can't parse message as a valid 4nk message: {}", raw);
|
Ok(false)
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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 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::silentpayments::utils::receiving::calculate_shared_secret;
|
||||||
|
use sp_backend::spclient::{OutputList, OwnedOutput, Recipient, SpClient};
|
||||||
use sp_backend::{
|
use sp_backend::{
|
||||||
bitcoin::{
|
bitcoin::{
|
||||||
secp256k1::{PublicKey, Scalar, XOnlyPublicKey},
|
secp256k1::{PublicKey, Scalar, XOnlyPublicKey},
|
||||||
@ -15,9 +21,79 @@ use crate::user::{lock_connected_users, CONNECTED_USERS};
|
|||||||
|
|
||||||
type FoundOutputs = HashMap<Option<Label>, HashMap<XOnlyPublicKey, Scalar>>;
|
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 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(
|
pub fn check_transaction(
|
||||||
tx: &Transaction,
|
tx: &Transaction,
|
||||||
blockheight: u32,
|
blockheight: u32,
|
||||||
|
@ -740,6 +740,30 @@ class Services {
|
|||||||
return null;
|
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;
|
export default Services;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user