use core::fmt;
use core::str::FromStr;
use arkworks_setups::common::Leaf;
use js_sys::{JsString, Uint8Array};
use rand::rngs::OsRng;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsValue;
use crate::types::{
Backend, Curve, HashFunction, NoteProtocol, NoteVersion, OpStatusCode, OperationError, Protocol, Version,
WasmCurve, BE, HF,
};
use crate::utxo::JsUtxo;
pub mod mixer;
pub mod vanchor;
pub mod versioning;
#[allow(unused_macros)]
macro_rules! console_log {
($($t:tt)*) => (crate::types::log(&format_args!($($t)*).to_string()))
}
pub enum JsLeafInner {
Mixer(Leaf),
VAnchor(JsUtxo),
}
impl Clone for JsLeafInner {
fn clone(&self) -> Self {
match self {
JsLeafInner::Mixer(leaf) => JsLeafInner::Mixer(Leaf {
chain_id_bytes: leaf.chain_id_bytes.clone(),
secret_bytes: leaf.secret_bytes.clone(),
nullifier_bytes: leaf.nullifier_bytes.clone(),
leaf_bytes: leaf.leaf_bytes.clone(),
nullifier_hash_bytes: leaf.nullifier_hash_bytes.clone(),
}),
JsLeafInner::VAnchor(utxo) => JsLeafInner::VAnchor(utxo.clone()),
}
}
}
#[wasm_bindgen]
pub struct JsLeaf {
#[wasm_bindgen(skip)]
pub inner: JsLeafInner,
}
impl JsLeaf {
pub fn mixer_leaf(&self) -> Result<Leaf, OperationError> {
match self.inner.clone() {
JsLeafInner::Mixer(leaf) => Ok(leaf),
_ => Err(OpStatusCode::InvalidNoteProtocol.into()),
}
}
pub fn vanchor_leaf(&self) -> Result<JsUtxo, OperationError> {
match self.inner.clone() {
JsLeafInner::VAnchor(leaf) => Ok(leaf),
_ => Err(OpStatusCode::InvalidNoteProtocol.into()),
}
}
}
#[wasm_bindgen]
impl JsLeaf {
#[wasm_bindgen(getter)]
pub fn protocol(&self) -> Protocol {
let protocol = match self.inner {
JsLeafInner::Mixer(_) => "mixer",
JsLeafInner::VAnchor(_) => "vanchor",
};
JsValue::from(protocol).into()
}
#[wasm_bindgen(getter)]
pub fn commitment(&self) -> Uint8Array {
match &self.inner {
JsLeafInner::Mixer(leaf) => Uint8Array::from(leaf.leaf_bytes.as_slice()),
JsLeafInner::VAnchor(vanchor_leaf) => vanchor_leaf.commitment(),
}
}
}
impl JsNote {
pub fn deserialize(note: &str) -> Result<Self, OperationError> {
note.parse().map_err(Into::into)
}
pub fn mutate_index(&mut self, index: u64) -> Result<(), OperationError> {
match self.protocol {
NoteProtocol::VAnchor => {}
_ => {
let message = "Index secret can be set only for VAnchor".to_string();
let oe = OperationError::new_with_message(OpStatusCode::InvalidNoteProtocol, message);
return Err(oe);
}
}
self.index = Some(index);
Ok(())
}
pub fn get_leaf_and_nullifier(&self) -> Result<JsLeaf, OperationError> {
match self.protocol {
NoteProtocol::Mixer => {
let raw = match self.version {
NoteVersion::V1 => {
let mut raw = Vec::new();
raw.extend_from_slice(&self.secrets[0][..]);
raw.extend_from_slice(&self.secrets[1][..]);
raw
}
};
let mixer_leaf = mixer::get_leaf_with_private_raw(
self.curve.unwrap_or(Curve::Bn254),
self.width.unwrap_or(5),
self.exponentiation.unwrap_or(5),
&raw,
)?;
Ok(JsLeaf {
inner: JsLeafInner::Mixer(mixer_leaf),
})
}
NoteProtocol::VAnchor => match self.version {
NoteVersion::V1 => {
if self.secrets.len() == 4 {
let chain_id = self.secrets[0].clone();
let amount = self.secrets[1].clone();
let blinding = self.secrets[2].clone();
let secret_key = self.secrets[3].clone();
let index = self.index;
let mut amount_slice = [0u8; 16];
amount_slice.copy_from_slice(amount[..16].to_vec().as_slice());
let amount = u128::from_le_bytes(amount_slice);
let mut chain_id_slice = [0u8; 8];
chain_id_slice.copy_from_slice(chain_id[chain_id.len() - 8..].to_vec().as_slice());
let chain_id = u64::from_be_bytes(chain_id_slice);
let curve = self.curve.unwrap_or(Curve::Bn254);
let width = self.width.unwrap_or(2);
let exponentiation = self.exponentiation.unwrap_or(5);
let utxo = vanchor::get_leaf_with_private_raw(
curve,
width,
exponentiation,
Some(secret_key),
Some(blinding),
chain_id,
amount,
index,
)?;
Ok(JsLeaf {
inner: JsLeafInner::VAnchor(utxo),
})
} else {
let message = format!("Invalid secret format for protocol {}", self.protocol);
Err(OperationError::new_with_message(
OpStatusCode::InvalidNoteSecrets,
message,
))
}
}
},
}
}
pub fn get_js_utxo(&self) -> Result<JsUtxo, OperationError> {
let leaf = self.get_leaf_and_nullifier()?;
match leaf.inner {
JsLeafInner::VAnchor(utxo) => Ok(utxo),
_ => Err(OpStatusCode::InvalidNoteProtocol.into()),
}
}
}
impl fmt::Display for JsNote {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let scheme = "webb://";
let authority = vec![self.version.to_string(), self.protocol.to_string()].join(":");
let chain_ids = vec![self.source_chain_id.to_string(), self.target_chain_id.to_string()].join(":");
let chain_identifying_data = vec![
self.source_identifying_data.to_string(),
self.target_identifying_data.to_string(),
]
.join(":");
let secrets = &self.secrets.iter().map(hex::encode).collect::<Vec<String>>().join(":");
#[allow(clippy::map_clone)]
let misc_values = vec![
if self.curve.is_some() {
format!("curve={}", self.curve.unwrap())
} else {
"".to_string()
},
if self.width.is_some() {
format!("width={}", self.width.unwrap())
} else {
"".to_string()
},
if self.exponentiation.is_some() {
format!("exp={}", self.exponentiation.unwrap())
} else {
"".to_string()
},
if self.hash_function.is_some() {
format!("hf={}", self.hash_function.unwrap())
} else {
"".to_string()
},
if self.backend.is_some() {
format!("backend={}", self.backend.unwrap())
} else {
"".to_string()
},
if self.token_symbol.is_some() {
format!("token={}", self.token_symbol.clone().unwrap())
} else {
"".to_string()
},
if self.denomination.is_some() {
format!("denom={}", self.denomination.unwrap())
} else {
"".to_string()
},
if self.amount.is_some() {
format!("amount={}", self.amount.clone().unwrap())
} else {
"".to_string()
},
if self.index.is_some() {
format!("index={}", self.index.unwrap())
} else {
"".to_string()
},
]
.iter()
.filter(|v| !v.is_empty())
.map(|v| v.clone())
.collect::<Vec<String>>()
.join("&");
let misc = vec!["?".to_string(), misc_values].join("");
let parts: Vec<String> = vec![authority, chain_ids, chain_identifying_data, secrets.to_string(), misc];
let note = vec![scheme.to_string(), parts.join("/")].join("");
write!(f, "{}", note)
}
}
impl FromStr for JsNote {
type Err = OperationError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
versioning::v1::note_from_str(s)
}
}
#[wasm_bindgen]
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct JsNote {
#[wasm_bindgen(skip)]
pub scheme: String,
#[wasm_bindgen(skip)]
pub protocol: NoteProtocol,
#[wasm_bindgen(skip)]
pub version: NoteVersion,
#[wasm_bindgen(skip)]
pub source_chain_id: String,
#[wasm_bindgen(skip)]
pub target_chain_id: String,
#[wasm_bindgen(skip)]
pub source_identifying_data: String,
#[wasm_bindgen(skip)]
pub target_identifying_data: String,
#[wasm_bindgen(skip)]
pub secrets: Vec<Vec<u8>>,
#[wasm_bindgen(skip)]
pub curve: Option<Curve>,
#[wasm_bindgen(skip)]
pub exponentiation: Option<i8>,
#[wasm_bindgen(skip)]
pub width: Option<usize>,
#[wasm_bindgen(skip)]
pub token_symbol: Option<String>,
#[wasm_bindgen(skip)]
pub amount: Option<String>,
#[wasm_bindgen(skip)]
pub denomination: Option<u8>,
#[wasm_bindgen(skip)]
pub backend: Option<Backend>,
#[wasm_bindgen(skip)]
pub hash_function: Option<HashFunction>,
#[wasm_bindgen(skip)]
pub index: Option<u64>,
}
#[wasm_bindgen]
#[derive(Default)]
pub struct JsNoteBuilder {
#[wasm_bindgen(skip)]
pub protocol: Option<NoteProtocol>,
#[wasm_bindgen(skip)]
pub version: Option<NoteVersion>,
#[wasm_bindgen(skip)]
pub source_chain_id: Option<String>,
#[wasm_bindgen(skip)]
pub target_chain_id: Option<String>,
#[wasm_bindgen(skip)]
pub source_identifying_data: Option<String>,
#[wasm_bindgen(skip)]
pub target_identifying_data: Option<String>,
#[wasm_bindgen(skip)]
pub amount: Option<String>,
#[wasm_bindgen(skip)]
pub denomination: Option<u8>,
#[wasm_bindgen(skip)]
pub secrets: Option<Vec<Vec<u8>>>,
#[wasm_bindgen(skip)]
pub backend: Option<Backend>,
#[wasm_bindgen(skip)]
pub hash_function: Option<HashFunction>,
#[wasm_bindgen(skip)]
pub curve: Option<Curve>,
#[wasm_bindgen(skip)]
pub token_symbol: Option<String>,
#[wasm_bindgen(skip)]
pub exponentiation: Option<i8>,
#[wasm_bindgen(skip)]
pub width: Option<usize>,
#[wasm_bindgen(skip)]
pub index: Option<u64>,
#[wasm_bindgen(skip)]
pub private_key: Option<Vec<u8>>,
#[wasm_bindgen(skip)]
pub blinding: Option<Vec<u8>>,
}
#[allow(clippy::unused_unit)]
#[wasm_bindgen]
impl JsNoteBuilder {
#[wasm_bindgen(constructor)]
pub fn new() -> Self {
Self::default()
}
pub fn protocol(&mut self, protocol: Protocol) -> Result<(), JsValue> {
let protocol: String = JsValue::from(&protocol)
.as_string()
.ok_or(OpStatusCode::InvalidNoteProtocol)?;
let note_protocol: NoteProtocol = protocol
.as_str()
.parse()
.map_err(|_| OpStatusCode::InvalidNoteProtocol)?;
self.protocol = Some(note_protocol);
Ok(())
}
pub fn version(&mut self, version: Version) -> Result<(), JsValue> {
let version: String = JsValue::from(&version)
.as_string()
.ok_or(OpStatusCode::InvalidNoteVersion)?;
let note_version: NoteVersion = version.as_str().parse().map_err(|_| OpStatusCode::InvalidNoteVersion)?;
self.version = Some(note_version);
Ok(())
}
#[wasm_bindgen(js_name = sourceChainId)]
pub fn source_chain_id(&mut self, source_chain_id: JsString) {
self.source_chain_id = Some(source_chain_id.into());
}
#[wasm_bindgen(js_name = targetChainId)]
pub fn target_chain_id(&mut self, target_chain_id: JsString) {
self.target_chain_id = Some(target_chain_id.into());
}
#[wasm_bindgen(js_name = sourceIdentifyingData)]
pub fn source_identifying_data(&mut self, source_identifying_data: JsString) {
self.source_identifying_data = Some(source_identifying_data.into());
}
#[wasm_bindgen(js_name = targetIdentifyingData)]
pub fn target_identifying_data(&mut self, target_identifying_data: JsString) {
self.target_identifying_data = Some(target_identifying_data.into());
}
pub fn backend(&mut self, backend: BE) {
let c: String = JsValue::from(&backend).as_string().unwrap();
let backend: Backend = c.parse().unwrap();
self.backend = Some(backend);
}
#[wasm_bindgen(js_name = hashFunction)]
pub fn hash_function(&mut self, hash_function: HF) -> Result<(), JsValue> {
let hash_function: String = JsValue::from(&hash_function)
.as_string()
.ok_or(OpStatusCode::InvalidHasFunction)?;
let hash_function: HashFunction = hash_function.parse().map_err(|_| OpStatusCode::InvalidHasFunction)?;
self.hash_function = Some(hash_function);
Ok(())
}
pub fn curve(&mut self, curve: WasmCurve) -> Result<(), JsValue> {
let curve: String = JsValue::from(&curve).as_string().ok_or(OpStatusCode::InvalidCurve)?;
let curve: Curve = curve.parse().map_err(|_| OpStatusCode::InvalidCurve)?;
self.curve = Some(curve);
Ok(())
}
#[wasm_bindgen(js_name = tokenSymbol)]
pub fn token_symbol(&mut self, token_symbol: JsString) {
self.token_symbol = Some(token_symbol.into());
}
pub fn amount(&mut self, amount: JsString) {
self.amount = Some(amount.into());
}
pub fn denomination(&mut self, denomination: JsString) -> Result<(), JsValue> {
let den: String = denomination.into();
let denomination = den.parse().map_err(|_| OpStatusCode::InvalidDenomination)?;
self.denomination = Some(denomination);
Ok(())
}
pub fn index(&mut self, index: JsString) -> Result<(), JsValue> {
let index: String = index.into();
let index: u64 = index.parse().map_err(|_| OpStatusCode::InvalidUTXOIndex)?;
self.index = Some(index);
Ok(())
}
pub fn exponentiation(&mut self, exponentiation: JsString) -> Result<(), JsValue> {
let exp: String = exponentiation.into();
let exponentiation = exp.parse().map_err(|_| OpStatusCode::InvalidExponentiation)?;
self.exponentiation = Some(exponentiation);
Ok(())
}
pub fn width(&mut self, width: JsString) -> Result<(), JsValue> {
let width: String = width.into();
let width = width.parse().map_err(|_| OpStatusCode::InvalidWidth)?;
self.width = Some(width);
Ok(())
}
#[wasm_bindgen(js_name = setSecrets)]
pub fn set_secrets(&mut self, secrets: JsString) -> Result<(), JsValue> {
let secrets_string: String = secrets.into();
let secrets_parts: Vec<String> = secrets_string.split(':').map(String::from).collect();
let secs = secrets_parts
.iter()
.map(|v| hex::decode(v.replace("0x", "")).unwrap_or_default())
.collect();
self.secrets = Some(secs);
Ok(())
}
#[wasm_bindgen(js_name = setPrivateKey)]
pub fn set_private_key(&mut self, private_key: Uint8Array) -> Result<(), JsValue> {
self.private_key = Some(private_key.to_vec());
Ok(())
}
#[wasm_bindgen(js_name = setBlinding)]
pub fn set_blinding(&mut self, blinding: Uint8Array) -> Result<(), JsValue> {
self.blinding = Some(blinding.to_vec());
Ok(())
}
pub fn build(self) -> Result<JsNote, JsValue> {
let version = self.version.ok_or(OpStatusCode::InvalidNoteVersion)?;
let protocol = self.protocol.ok_or(OpStatusCode::InvalidNoteProtocol)?;
let source_chain_id = self.source_chain_id.ok_or(OpStatusCode::InvalidSourceChain)?;
let _: u64 = source_chain_id.parse().map_err(|_| OpStatusCode::InvalidSourceChain)?;
let target_chain_id = self.target_chain_id.ok_or(OpStatusCode::InvalidTargetChain)?;
let chain_id: u64 = target_chain_id.parse().map_err(|_| OpStatusCode::InvalidTargetChain)?;
let source_identifying_data = self.source_identifying_data.ok_or_else(|| "".to_string())?;
let target_identifying_data = self.target_identifying_data.ok_or_else(|| "".to_string())?;
let exponentiation = self.exponentiation;
let width = self.width;
let curve = self.curve;
let amount = self.amount.clone();
let index = self.index;
let backend = self.backend.unwrap_or(Backend::Arkworks);
if backend == Backend::Circom && self.secrets.is_none() {
let message = "Circom backend is supported when the secret value is supplied".to_string();
let operation_error = OperationError::new_with_message(OpStatusCode::UnsupportedBackend, message);
return Err(operation_error.into());
}
let secrets = match self.secrets {
None => match protocol {
NoteProtocol::Mixer => {
let secrets = mixer::generate_secrets(
exponentiation.unwrap_or(5),
width.unwrap_or(5),
curve.unwrap_or(Curve::Bn254),
&mut OsRng,
)?;
secrets.to_vec()
}
NoteProtocol::VAnchor => {
let blinding = self.blinding;
let private_key = self.private_key;
let utxo = vanchor::get_leaf_with_private_raw(
curve.unwrap_or(Curve::Bn254),
width.unwrap_or(5),
exponentiation.unwrap_or(5),
private_key,
blinding,
chain_id,
amount.unwrap_or_else(|| "0".to_string()).parse().unwrap(),
index,
)?;
let chain_id = utxo.get_chain_id_bytes();
let amount = utxo.get_amount();
let blinding = utxo.get_blinding();
let secret_key = utxo.get_secret_key();
vec![chain_id, amount, blinding, secret_key]
}
},
Some(secrets) => {
match protocol {
NoteProtocol::Mixer => {
if secrets.len() != 1 {
let message = "Mixer secrets length should be 1 in length".to_string();
let operation_error =
OperationError::new_with_message(OpStatusCode::InvalidNoteSecrets, message);
return Err(operation_error.into());
}
}
NoteProtocol::VAnchor => {
if secrets.len() != 4 {
let message = "VAnchor secrets length should be 4 in length".to_string();
let operation_error =
OperationError::new_with_message(OpStatusCode::InvalidNoteSecrets, message);
return Err(operation_error.into());
}
}
};
secrets
}
};
let backend = self.backend;
let hash_function = self.hash_function;
let token_symbol = self.token_symbol;
let amount = self.amount.clone();
let denomination = self.denomination;
let scheme = "webb://".to_string();
let note = JsNote {
scheme,
protocol,
version,
source_chain_id,
target_chain_id,
source_identifying_data,
target_identifying_data,
backend,
hash_function,
curve,
token_symbol,
amount,
denomination,
exponentiation,
width,
secrets,
index,
};
Ok(note)
}
}
#[allow(clippy::unused_unit)]
#[wasm_bindgen]
impl JsNote {
#[wasm_bindgen(constructor)]
pub fn new(builder: JsNoteBuilder) -> Result<JsNote, JsValue> {
builder.build()
}
#[wasm_bindgen(js_name = deserialize)]
pub fn js_deserialize(note: JsString) -> Result<JsNote, JsValue> {
let n: String = note.into();
let n = JsNote::deserialize(&n)?;
Ok(n)
}
#[wasm_bindgen(js_name = getLeafCommitment)]
pub fn get_leaf_commitment(&self) -> Result<Uint8Array, JsValue> {
let leaf = self.get_leaf_and_nullifier()?;
Ok(leaf.commitment())
}
pub fn serialize(&self) -> JsString {
JsString::from(self.to_string())
}
#[wasm_bindgen(getter)]
pub fn protocol(&self) -> Protocol {
self.protocol.into()
}
#[wasm_bindgen(getter)]
pub fn version(&self) -> Version {
self.version.into()
}
#[wasm_bindgen(js_name = targetChainId)]
#[wasm_bindgen(getter)]
pub fn target_chain_id(&self) -> JsString {
self.target_chain_id.clone().into()
}
#[wasm_bindgen(js_name = sourceChainId)]
#[wasm_bindgen(getter)]
pub fn source_chain_id(&self) -> JsString {
self.source_chain_id.clone().into()
}
#[wasm_bindgen(js_name = targetIdentifyingData)]
#[wasm_bindgen(getter)]
pub fn target_identifying_data(&self) -> JsString {
self.target_identifying_data.clone().into()
}
#[wasm_bindgen(js_name = sourceIdentifyingData)]
#[wasm_bindgen(getter)]
pub fn source_identifying_data(&self) -> JsString {
self.source_identifying_data.clone().into()
}
#[wasm_bindgen(getter)]
pub fn backend(&self) -> BE {
self.backend.unwrap_or(Backend::Circom).into()
}
#[wasm_bindgen(getter)]
#[wasm_bindgen(js_name = hashFunction)]
pub fn hash_function(&self) -> JsString {
self.hash_function.unwrap_or(HashFunction::Poseidon).into()
}
#[wasm_bindgen(getter)]
pub fn curve(&self) -> WasmCurve {
self.curve.unwrap_or(Curve::Bn254).into()
}
#[wasm_bindgen(getter)]
pub fn secrets(&self) -> JsString {
let secrets = self.secrets.iter().map(hex::encode).collect::<Vec<String>>().join(":");
secrets.into()
}
#[wasm_bindgen(getter)]
#[wasm_bindgen(js_name = tokenSymbol)]
pub fn token_symbol(&self) -> JsString {
self.token_symbol.clone().unwrap_or_default().into()
}
#[wasm_bindgen(getter)]
pub fn amount(&self) -> JsString {
self.amount.clone().unwrap_or_default().into()
}
#[wasm_bindgen(getter)]
pub fn denomination(&self) -> JsString {
let denomination = self.denomination.unwrap_or_default().to_string();
denomination.into()
}
#[wasm_bindgen(getter)]
pub fn width(&self) -> JsString {
let width = self.width.unwrap_or_default().to_string();
width.into()
}
#[wasm_bindgen(getter)]
pub fn exponentiation(&self) -> JsString {
let exp = self.exponentiation.unwrap_or_default().to_string();
exp.into()
}
#[wasm_bindgen(js_name = mutateIndex)]
pub fn js_mutate_index(&mut self, index: JsString) -> Result<(), JsValue> {
let index: String = index.into();
let index: u64 = index.parse().map_err(|_| OpStatusCode::InvalidNoteVersion)?;
self.mutate_index(index).map_err(|e| e.into())
}
#[wasm_bindgen(js_name = defaultUtxoNote)]
pub fn default_utxo_note(note: &JsNote) -> Result<JsNote, OperationError> {
let mut new_note = JsNote {
scheme: note.scheme.clone(),
protocol: note.protocol,
version: note.version,
source_chain_id: note.source_chain_id.clone(),
target_chain_id: note.target_chain_id.clone(),
source_identifying_data: note.source_identifying_data.clone(),
target_identifying_data: note.target_identifying_data.clone(),
secrets: note.secrets.clone(),
curve: note.curve,
exponentiation: note.exponentiation,
width: note.width,
token_symbol: note.token_symbol.clone(),
amount: Some("0".to_string()),
denomination: note.denomination,
backend: note.backend,
hash_function: note.hash_function,
index: Some(0),
};
let chain_id: u64 = new_note
.target_chain_id
.parse()
.map_err(|_| OpStatusCode::InvalidTargetChain)?;
let utxo = vanchor::generate_secrets(
0,
new_note.exponentiation.unwrap_or(5),
new_note.width.unwrap_or(5),
new_note.curve.unwrap_or(Curve::Bn254),
chain_id,
Some(0),
&mut OsRng,
)?;
new_note.update_vanchor_utxo(utxo)?;
Ok(new_note)
}
#[wasm_bindgen(js_name = getUtxo)]
pub fn get_utxo(&self) -> Result<JsUtxo, OperationError> {
match self.protocol {
NoteProtocol::VAnchor => {
let leaf = self.get_leaf_and_nullifier()?;
leaf.vanchor_leaf()
}
_ => Err(OpStatusCode::InvalidNoteProtocol.into()),
}
}
pub fn update_vanchor_utxo(&mut self, utxo: JsUtxo) -> Result<(), OperationError> {
let chain_id = utxo.get_chain_id_bytes();
let amount = utxo.get_amount();
let blinding = utxo.get_blinding();
let secret_key = utxo.get_secret_key();
self.amount = Some(utxo.get_amount_raw().to_string());
self.secrets = vec![chain_id, amount, blinding, secret_key];
Ok(())
}
#[wasm_bindgen(getter)]
pub fn index(&self) -> JsString {
match self.index {
None => JsString::from(""),
Some(index) => JsString::from(index.to_string().as_str()),
}
}
}
#[cfg(test)]
mod test {
use ark_bn254;
use wasm_bindgen_test::*;
use crate::utils::to_rust_string;
use super::*;
type Bn254Fr = ark_bn254::Fr;
#[wasm_bindgen_test]
fn generate_mixer_note() {
let mut note_builder = JsNoteBuilder::new();
let protocol: Protocol = JsValue::from(NoteProtocol::Mixer.to_string()).into();
let version: Version = JsValue::from(NoteVersion::V1.to_string()).into();
let backend: BE = JsValue::from(Backend::Arkworks.to_string()).into();
let hash_function: HF = JsValue::from(HashFunction::Poseidon.to_string()).into();
let curve: WasmCurve = JsValue::from(Curve::Bn254.to_string()).into();
note_builder.protocol(protocol).unwrap();
note_builder.version(version).unwrap();
note_builder.source_chain_id(JsString::from("2"));
note_builder.target_chain_id(JsString::from("2"));
note_builder.source_identifying_data(JsString::from("2"));
note_builder.target_identifying_data(JsString::from("2"));
note_builder.width(JsString::from("3")).unwrap();
note_builder.exponentiation(JsString::from("5")).unwrap();
note_builder.denomination(JsString::from("18")).unwrap();
note_builder.amount(JsString::from("10"));
note_builder.token_symbol(JsString::from("EDG"));
note_builder.curve(curve).unwrap();
note_builder.hash_function(hash_function).unwrap();
note_builder.backend(backend);
note_builder.index(JsString::from("10")).unwrap();
let mixer_note = note_builder.build().unwrap();
let note_string = mixer_note.to_string();
let leaf = mixer_note.get_leaf_commitment().unwrap();
let leaf_vec = leaf.to_vec();
let js_note_2 = JsNote::deserialize(¬e_string).unwrap();
let js_note_2_string = js_note_2.to_string();
let leaf_2 = js_note_2.get_leaf_commitment().unwrap();
let leaf_2_vec = leaf_2.to_vec();
assert_eq!(note_string, js_note_2_string);
assert_eq!(mixer_note.secrets.len(), 2);
assert_eq!(hex::encode(leaf_vec), hex::encode(leaf_2_vec));
}
#[wasm_bindgen_test]
fn should_deserialize_mixer_note() {
let mixer_note = "webb://v1:mixer/2:2/2:2/fd717cfe463b3ffec71ee6b7606bbd0179170510abf41c9f16c1d20ca9923f0e:18b6b080e6a43262f00f6fb3da0d2409c4871b8f26d89d5c8836358e1af5a41c/?curve=Bn254&width=3&exp=5&hf=Poseidon&backend=Arkworks&token=EDG&denom=18&amount=10&index=10";
let note = JsNote::deserialize(mixer_note).unwrap();
note.get_leaf_commitment().unwrap();
assert_eq!(note.serialize(), mixer_note);
}
#[wasm_bindgen_test]
fn generate_vanchor_note() {
let mut note_builder = JsNoteBuilder::new();
let protocol: Protocol = JsValue::from(NoteProtocol::VAnchor.to_string()).into();
let version: Version = JsValue::from(NoteVersion::V1.to_string()).into();
let backend: BE = JsValue::from(Backend::Arkworks.to_string()).into();
let hash_function: HF = JsValue::from(HashFunction::Poseidon.to_string()).into();
let curve: WasmCurve = JsValue::from(Curve::Bn254.to_string()).into();
note_builder.protocol(protocol).unwrap();
note_builder.version(version).unwrap();
note_builder.source_chain_id(JsString::from("2"));
note_builder.target_chain_id(JsString::from("3"));
note_builder.source_identifying_data(JsString::from("2"));
note_builder.target_identifying_data(JsString::from("3"));
note_builder.width(JsString::from("5")).unwrap();
note_builder.exponentiation(JsString::from("5")).unwrap();
note_builder.denomination(JsString::from("18")).unwrap();
note_builder.amount(JsString::from("10"));
note_builder.token_symbol(JsString::from("EDG"));
note_builder.curve(curve).unwrap();
note_builder.hash_function(hash_function).unwrap();
note_builder.backend(backend);
note_builder.index(JsString::from("10")).unwrap();
let vanchor_note = note_builder.build().unwrap();
let note_string = vanchor_note.to_string();
let leaf = vanchor_note.get_leaf_commitment().unwrap();
let leaf_vec = leaf.to_vec();
let js_note_2 = JsNote::deserialize(¬e_string).unwrap();
let js_note_2_string = js_note_2.to_string();
let leaf_2 = js_note_2.get_leaf_commitment().unwrap();
let leaf_2_vec = leaf_2.to_vec();
assert_eq!(note_string, js_note_2_string);
assert_eq!(vanchor_note.secrets.len(), 4);
assert_eq!(hex::encode(leaf_vec), hex::encode(leaf_2_vec));
}
#[wasm_bindgen_test]
fn should_deserialize_vanchor_note() {
let vanchor_note_str = "webb://v1:vanchor/2:3/2:3/0300000000000000000000000000000000000000000000000000000000000000:0a00000000000000000000000000000000000000000000000000000000000000:7798d054444ec463be7d41ad834147b5b2c468182c7cd6a601aec29a273fca05:bf5d780608f5b8a8db1dc87356a225a0324a1db61903540daaedd54ab10a4124/?curve=Bn254&width=5&exp=5&hf=Poseidon&backend=Arkworks&token=EDG&denom=18&amount=10&index=10";
let note = JsNote::deserialize(vanchor_note_str).unwrap();
note.get_leaf_commitment().unwrap();
assert_eq!(note.serialize(), vanchor_note_str);
}
}