Update faucet

This commit is contained in:
Sosthene00 2024-04-17 08:58:28 +02:00
parent 0d42c289cb
commit 8fb517c107
4 changed files with 103 additions and 123 deletions

View File

@ -3,15 +3,18 @@ use std::collections::HashMap;
use std::str::FromStr;
use std::sync::{Mutex, OnceLock, PoisonError};
use log::debug;
use rand::Rng;
use anyhow::Error as AnyhowError;
use sdk_common::crypto::AnkSharedSecret;
use serde_json::Error as SerdeJsonError;
use shamir::SecretData;
use sp_backend::bitcoin::consensus::deserialize;
use sp_backend::bitcoin::hex::{FromHex, HexToBytesError};
use sp_backend::bitcoin::consensus::{deserialize, serialize};
use sp_backend::bitcoin::hex::{parse, DisplayHex, FromHex, HexToBytesError};
use sp_backend::bitcoin::secp256k1::ecdh::SharedSecret;
use sp_backend::bitcoin::secp256k1::{PublicKey, SecretKey};
use sp_backend::bitcoin::{Transaction, Txid};
use sp_backend::bitcoin::{OutPoint, Transaction, Txid};
use sp_backend::silentpayments::Error as SpError;
use serde::{Deserialize, Serialize};
@ -20,12 +23,13 @@ use tsify::Tsify;
use wasm_bindgen::convert::FromWasmAbi;
use wasm_bindgen::prelude::*;
use sp_backend::spclient::{derive_keys_from_seed, OutputList, SpClient};
use sdk_common::network::{AnkFlag, AnkNetworkMsg, NewTxMessage};
use sp_backend::spclient::{derive_keys_from_seed, OutputList, OwnedOutput, SpClient};
use sp_backend::spclient::{SpWallet, SpendKey};
use crate::images;
use crate::network::{BitcoinNetworkMsg, BitcoinTopic, AnkNetworkMsg, AnkTopic};
use crate::silentpayments::check_transaction;
use crate::silentpayments::{check_transaction, create_transaction_for_address};
use crate::user::{lock_connected_users, User, UserWallets, CONNECTED_USERS};
use crate::process::Process;
@ -264,7 +268,7 @@ impl shamir_shares {
}
#[derive(Debug, Tsify, Serialize, Deserialize)]
#[tsify(from_wasm_abi)]
#[tsify(from_wasm_abi, into_wasm_abi)]
#[allow(non_camel_case_types)]
pub struct outputs_list(Vec<OutputList>);
@ -296,30 +300,58 @@ pub fn login_user(
#[wasm_bindgen]
pub fn check_transaction_for_silent_payments(
tx_hex: String,
blockheight: u32,
tweak_data_hex: String,
) -> ApiResult<()> {
) -> ApiResult<String> {
let tx = deserialize::<Transaction>(&Vec::from_hex(&tx_hex)?)?;
let tweak_data = PublicKey::from_str(&tweak_data_hex)?;
check_transaction(tx, tweak_data);
let updated_user = check_transaction(&tx, blockheight, tweak_data)?;
Ok(())
Ok(updated_user)
}
#[derive(Tsify, Serialize, Deserialize)]
#[tsify(into_wasm_abi, from_wasm_abi)]
#[allow(non_camel_case_types)]
pub struct parseNetworkMsgReturn {
topic: String,
message: String,
}
#[wasm_bindgen]
pub fn parse_bitcoin_network_msg(msg: Vec<u8>) -> ApiResult<()> {
let parsed_msg = BitcoinNetworkMsg::new(&msg)?;
match parsed_msg.topic {
BitcoinTopic::RawTx => {
let tx = deserialize::<Transaction>(parsed_msg.data)?;
let tweak_data = PublicKey::from_slice(parsed_msg.addon)?;
check_transaction(tx, tweak_data);
pub fn parse_network_msg(raw: String) -> ApiResult<parseNetworkMsgReturn> {
if let Ok(ank_msg) = serde_json::from_str::<AnkNetworkMsg>(&raw) {
match ank_msg.flag {
AnkFlag::NewTx => {
let tx_message = serde_json::from_str::<NewTxMessage>(&ank_msg.content)?;
let tx = deserialize::<Transaction>(&Vec::from_hex(&tx_message.transaction)?)?;
if tx_message.tweak_data.is_none() {
return Err(ApiError {
message: "Missing tweak_data".to_owned(),
});
}
let partial_tweak = PublicKey::from_str(&tx_message.tweak_data.unwrap())?;
let txid = check_transaction(&tx, 0, partial_tweak)?;
return Ok(parseNetworkMsgReturn {
topic: AnkFlag::NewTx.as_str().to_owned(),
message: txid,
});
}
AnkFlag::Faucet => unimplemented!(),
AnkFlag::Error => {
return Ok(parseNetworkMsgReturn {
topic: AnkFlag::Error.as_str().to_owned(),
message: ank_msg.content.to_owned(),
})
}
_ => unimplemented!(),
}
BitcoinTopic::RawBlock => (),
} else {
Err(ApiError {
message: format!("Can't parse message as a valid 4nk message: {}", raw),
})
}
Ok(())
}
#[wasm_bindgen]

View File

@ -18,59 +18,33 @@ type FoundOutputs = HashMap<Option<Label>, HashMap<XOnlyPublicKey, Scalar>>;
pub fn check_transaction(tx: Transaction, tweak_data: PublicKey) -> Result<FoundOutputs> {
let connected_users = lock_connected_users()?;
let pubkeys_to_check: HashMap<XOnlyPublicKey, u32> = (0u32..)
.zip(tx.output)
.filter_map(|(i, o)| {
if o.script_pubkey.is_p2tr() {
let xonly = XOnlyPublicKey::from_slice(&o.script_pubkey.as_bytes()[2..])
.expect("Transaction is invalid");
Some((xonly, i))
} else {
None
}
})
.collect();
pub fn check_transaction(
tx: &Transaction,
blockheight: u32,
tweak_data: PublicKey,
) -> Result<String> {
let connected_users = lock_connected_users()?;
let txid = tx.txid().to_string();
// Check the transaction for all connected users
for (pre_id, keys) in connected_users.clone() {
let recover = keys.recover;
let shared_secret =
calculate_shared_secret(tweak_data, recover.get_client().get_scan_key())?;
let res = recover
.get_client()
.sp_receiver
.scan_transaction(&shared_secret, pubkeys_to_check.keys().cloned().collect())?;
if res.len() > 0 {
return Ok(res);
let mut recover = keys.recover;
if recover.update_wallet_with_transaction(tx, blockheight, tweak_data)? > 0 {
return Ok(txid);
}
if let Some(main) = keys.main {
let shared_secret =
calculate_shared_secret(tweak_data, main.get_client().get_scan_key())?;
let res = main
.get_client()
.sp_receiver
.scan_transaction(&shared_secret, pubkeys_to_check.keys().cloned().collect())?;
if res.len() > 0 {
return Ok(res);
if let Some(mut main) = keys.main {
if main.update_wallet_with_transaction(tx, blockheight, tweak_data)? > 0 {
return Ok(txid);
}
}
if let Some(revoke) = keys.revoke {
let shared_secret =
calculate_shared_secret(tweak_data, revoke.get_client().get_scan_key())?;
let res = revoke
.get_client()
.sp_receiver
.scan_transaction(&shared_secret, pubkeys_to_check.keys().cloned().collect())?;
if res.len() > 0 {
return Ok(res);
if let Some(mut revoke) = keys.revoke {
if revoke.update_wallet_with_transaction(tx, blockheight, tweak_data)? > 0 {
return Ok(txid);
}
}
}
Ok(HashMap::new())
return Err(Error::msg("No new outputs found"));
}

View File

@ -177,18 +177,6 @@ class Services {
return imageBytes;
}
public async parseBitcoinMessage(raw: Blob): Promise<string | null> {
try {
const buffer = await raw.arrayBuffer();
const uint8Array = new Uint8Array(buffer);
const msg: string = this.sdkClient.parse_bitcoin_network_msg(uint8Array);
return msg;
} catch (error) {
console.error("Error processing the blob:", error);
return null;
}
}
public async displayRevoke(): Promise<void> {
const services = await Services.getInstance();
await services.revokeInjectHtml();
@ -211,30 +199,15 @@ class Services {
services.attachSubmitListener("form4nk", services.updateAnId);
}
public async parse4nkMessage(raw: string): Promise<string | null> {
const msg: string = this.sdkClient.parse_4nk_msg(raw);
public async parseNetworkMessage(raw: string): Promise<parseNetworkMsgReturn | null> {
const services = await Services.getInstance();
try {
const msg: parseNetworkMsgReturn = services.sdkClient.parse_network_msg(raw);
return msg;
}
public injectUpdateAnIdHtml(bodyToInject: string, styleToInject: string, scriptToInject: string) {
console.log("JS html : "+bodyToInject);
const body = document.getElementsByTagName('body')[0];
if (!body) {
console.error("No body tag");
return;
} catch (error) {
console.error(error);
return null;
}
body.innerHTML = styleToInject + bodyToInject;
const script = document.createElement("script");
script.innerHTML = scriptToInject;
document.body.appendChild(script);
script.onload = () => {
console.log('Script loaded successfuly');
};
script.onerror = () => {
console.log('Error loading script');
};
}
public async updateAnId(event: Event): Promise<void> {
@ -288,11 +261,13 @@ class Services {
return [];
}
}
public async checkTransaction(tx: string): Promise<string | null> {
public async checkTransaction(tx: string, tweak_data: string, blkheight: number): Promise<string | null> {
const services = await Services.getInstance();
try {
return services.sdkClient.check_network_transaction(tx);
const updated_user: string = services.sdkClient.check_transaction_for_silent_payments(tx, blkheight, tweak_data);
await services.updateOwnedOutputsForUser(updated_user);
return updated_user;
} catch (error) {
console.error(error);
return null;
@ -647,7 +622,11 @@ class Services {
return null;
}
try {
connection.sendMessage('faucet'+spaddress);
const flag: AnkFlag = "Faucet";
const faucetMsg: FaucetMessage = {
'sp_address': spaddress
}
connection.sendMessage(flag, JSON.stringify(faucetMsg));
} catch (error) {
console.error("Failed to obtain tokens with relay ", connection.getUrl());
return null;

View File

@ -1,5 +1,5 @@
import Services from "./services";
// import * as mempool from "./mempool";
import { AnkFlag, AnkNetworkMsg, parseNetworkMsgReturn } from "../dist/pkg/sdk_client";
class WebSocketClient {
private ws: WebSocket;
@ -25,28 +25,18 @@ class WebSocketClient {
console.log(msgData);
(async () => {
if (msgData instanceof Blob) {
// bitcoin network msg is just bytes
let res = await services.parseBitcoinMessage(msgData);
if (res) {
let ours = await services.checkTransaction(res);
if (ours) {
console.log("Found our utxo in "+res);
} else {
console.log("No utxo found in tx "+res);
}
} else {
console.error("Faile to parse a bitcoin network msg");
}
} else if (typeof(msgData) === 'string') {
// json strings are 4nk message
if (typeof(msgData) === 'string') {
console.log("Received text message: "+msgData);
let res = await services.parse4nkMessage(msgData);
let res = await services.parseNetworkMessage(msgData);
if (res) {
console.debug(res);
if (res.topic === 'new_tx') {
// we received a tx
window.alert(`New tx\n${res.message}`);
await services.updateOwnedOutputsForUser(res.message);
}
}
} else {
console.error("Received an unknown message");
console.error("Received an invalid message");
}
})();
});
@ -63,9 +53,14 @@ class WebSocketClient {
}
// Method to send messages
public sendMessage(message: string): void {
public sendMessage(flag: AnkFlag, message: string): void {
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(message);
const networkMessage: AnkNetworkMsg = {
'flag': flag,
'content': message
}
// console.debug("Sending message:", JSON.stringify(networkMessage));
this.ws.send(JSON.stringify(networkMessage));
} else {
console.error('WebSocket is not open. ReadyState:', this.ws.readyState);
this.messageQueue.push(message);