Update faucet
This commit is contained in:
parent
0d42c289cb
commit
8fb517c107
@ -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]
|
||||
|
@ -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"));
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user