diff --git a/packages/Cargo.lock b/packages/Cargo.lock index 87739b3..d9c5e83 100644 --- a/packages/Cargo.lock +++ b/packages/Cargo.lock @@ -1833,7 +1833,7 @@ dependencies = [ [[package]] name = "sidan-csl-rs" -version = "0.5.0-alpha.3" +version = "0.5.0-alpha.4" dependencies = [ "cardano-serialization-lib", "cryptoxide", @@ -1845,7 +1845,9 @@ dependencies = [ "pallas-primitives 0.22.0", "pallas-traverse 0.22.0", "rand_os", + "schemars", "serde", + "serde-wasm-bindgen 0.4.5", "serde-wasm-bindgen 0.6.5", "serde_json", "uplc 0.0.29", @@ -2385,7 +2387,7 @@ dependencies = [ [[package]] name = "whisky" -version = "0.5.0-alpha.3" +version = "0.5.0-alpha.4" dependencies = [ "async-trait", "cardano-serialization-lib", diff --git a/packages/sidan-csl-rs/Cargo.toml b/packages/sidan-csl-rs/Cargo.toml index 55f16f7..de52d38 100644 --- a/packages/sidan-csl-rs/Cargo.toml +++ b/packages/sidan-csl-rs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sidan-csl-rs" -version = "0.5.0-alpha.3" +version = "0.5.0-alpha.4" edition = "2021" license = "Apache-2.0" description = "Wrapper around the cardano-serialization-lib for easier transaction building, heavily inspired by cardano-cli APIs" @@ -16,6 +16,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" cryptoxide = "0.4.4" serde-wasm-bindgen = "0.6.5" +schemars = "0.8.8" # non-wasm [target.'cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))'.dependencies] @@ -31,6 +32,7 @@ pallas-traverse = "0.22.0" # wasm [target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies] +serde-wasm-bindgen = "0.4.5" # uplc = { version = "=1.0.26-alpha", default-features = false, features = ["native-secp256k1"] } uplc = "0.0.29" wasm-bindgen = { version = "=0.2.90", features = ["serde-serialize"] } diff --git a/packages/sidan-csl-rs/src/builder/core.rs b/packages/sidan-csl-rs/src/builder/core.rs index 7e0da0f..2747b86 100644 --- a/packages/sidan-csl-rs/src/builder/core.rs +++ b/packages/sidan-csl-rs/src/builder/core.rs @@ -2,9 +2,144 @@ use crate::{ core::builder::{IMeshCSL, MeshCSL}, csl, model::*, + *, }; -use super::interface::{IMeshTxBuilderCore, MeshTxBuilderCore}; +use super::{interface::MeshTxBuilderCore, IMeshTxBuilderCore}; + +#[wasm_bindgen] +pub fn js_serialize_tx_body(mesh_tx_builder_body_json: &str) -> String { + let mesh_tx_builder_body: MeshTxBuilderBody = serde_json::from_str(mesh_tx_builder_body_json) + .expect("Error deserializing transaction body"); + + serialize_tx_body(mesh_tx_builder_body) +} + +/// ## Transaction building method +/// +/// Serialize the transaction body +/// +/// ### Arguments +/// +/// * `mesh_tx_builder_body` - The transaction builder body information +/// +/// ### Returns +/// +/// * `String` - the built transaction hex +pub fn serialize_tx_body(mut mesh_tx_builder_body: MeshTxBuilderBody) -> String { + let mut mesh_csl = MeshCSL::new(); + + mesh_tx_builder_body + .mints + .sort_by(|a, b| a.policy_id.cmp(&b.policy_id)); + + mesh_tx_builder_body.inputs.sort_by(|a, b| { + let tx_in_data_a: &TxInParameter = match a { + TxIn::PubKeyTxIn(pub_key_tx_in) => &pub_key_tx_in.tx_in, + TxIn::ScriptTxIn(script_tx_in) => &script_tx_in.tx_in, + }; + + let tx_in_data_b: &TxInParameter = match b { + TxIn::PubKeyTxIn(pub_key_tx_in) => &pub_key_tx_in.tx_in, + TxIn::ScriptTxIn(script_tx_in) => &script_tx_in.tx_in, + }; + + tx_in_data_a + .tx_hash + .cmp(&tx_in_data_b.tx_hash) + .then_with(|| tx_in_data_a.tx_index.cmp(&tx_in_data_b.tx_index)) + }); + + MeshTxBuilderCore::add_all_inputs(&mut mesh_csl, mesh_tx_builder_body.inputs.clone()); + MeshTxBuilderCore::add_all_outputs(&mut mesh_csl, mesh_tx_builder_body.outputs.clone()); + MeshTxBuilderCore::add_all_collaterals(&mut mesh_csl, mesh_tx_builder_body.collaterals.clone()); + MeshTxBuilderCore::add_all_reference_inputs( + &mut mesh_csl, + mesh_tx_builder_body.reference_inputs.clone(), + ); + MeshTxBuilderCore::add_all_mints(&mut mesh_csl, mesh_tx_builder_body.mints.clone()); + MeshTxBuilderCore::add_validity_range( + &mut mesh_csl, + mesh_tx_builder_body.validity_range.clone(), + ); + MeshTxBuilderCore::add_all_required_signature( + &mut mesh_csl, + mesh_tx_builder_body.required_signatures.clone(), + ); + MeshTxBuilderCore::add_all_metadata(&mut mesh_csl, mesh_tx_builder_body.metadata.clone()); + + mesh_csl.add_script_hash(); + // if self.mesh_tx_builder_body.change_address != "" { + // let collateral_inputs = self.mesh_tx_builder_body.collaterals.clone(); + // let collateral_vec: Vec = collateral_inputs + // .into_iter() + // .map(|pub_key_tx_in| { + // let assets = pub_key_tx_in.tx_in.amount.unwrap(); + // let lovelace = assets + // .into_iter() + // .find(|asset| asset.unit == "lovelace") + // .unwrap(); + // lovelace.quantity.parse::().unwrap() + // }) + // .collect(); + // let total_collateral: u64 = collateral_vec.into_iter().sum(); + + // let collateral_estimate: u64 = (150 + // * self + // .tx_builder + // .min_fee() + // .unwrap() + // .checked_add(&to_bignum(10000)) + // .unwrap() + // .to_string() + // .parse::() + // .unwrap()) + // / 100; + + // let mut collateral_return_needed = false; + // if (total_collateral - collateral_estimate) > 0 { + // let collateral_estimate_output = csl::TransactionOutput::new( + // &csl::address::Address::from_bech32(&self.mesh_tx_builder_body.change_address) + // .unwrap(), + // &csl::utils::Value::new(&to_bignum(collateral_estimate)), + // ); + + // let min_ada = csl::utils::min_ada_for_output( + // &collateral_estimate_output, + // &csl::DataCost::new_coins_per_byte(&to_bignum(4310)), + // ) + // .unwrap() + // .to_string() + // .parse::() + // .unwrap(); + + // if total_collateral - collateral_estimate > min_ada { + // self.tx_builder + // .set_collateral_return(&csl::TransactionOutput::new( + // &csl::address::Address::from_bech32( + // &self.mesh_tx_builder_body.change_address, + // ) + // .unwrap(), + // &csl::utils::Value::new(&to_bignum(total_collateral)), + // )); + + // self.tx_builder + // .set_total_collateral(&to_bignum(total_collateral)); + + // collateral_return_needed = true; + // } + // } + // self.add_change(self.mesh_tx_builder_body.change_address.clone()); + // if collateral_return_needed { + // self.add_collateral_return(self.mesh_tx_builder_body.change_address.clone()); + // } + // } + mesh_csl.add_change( + mesh_tx_builder_body.change_address.clone(), + mesh_tx_builder_body.change_datum.clone(), + ); + mesh_csl.build_tx() +} impl IMeshTxBuilderCore for MeshTxBuilderCore { fn new_core() -> Self { @@ -36,184 +171,72 @@ impl IMeshTxBuilderCore for MeshTxBuilderCore { self.mesh_csl.tx_hex.to_string() } - fn serialize_tx_body(&mut self) -> &mut Self { - self.mesh_tx_builder_body - .mints - .sort_by(|a, b| a.policy_id.cmp(&b.policy_id)); - - self.mesh_tx_builder_body.inputs.sort_by(|a, b| { - let tx_in_data_a: &TxInParameter = match a { - TxIn::PubKeyTxIn(pub_key_tx_in) => &pub_key_tx_in.tx_in, - TxIn::ScriptTxIn(script_tx_in) => &script_tx_in.tx_in, - }; - - let tx_in_data_b: &TxInParameter = match b { - TxIn::PubKeyTxIn(pub_key_tx_in) => &pub_key_tx_in.tx_in, - TxIn::ScriptTxIn(script_tx_in) => &script_tx_in.tx_in, - }; - - tx_in_data_a - .tx_hash - .cmp(&tx_in_data_b.tx_hash) - .then_with(|| tx_in_data_a.tx_index.cmp(&tx_in_data_b.tx_index)) - }); - - self.add_all_inputs(self.mesh_tx_builder_body.inputs.clone()); - self.add_all_outputs(self.mesh_tx_builder_body.outputs.clone()); - self.add_all_collaterals(self.mesh_tx_builder_body.collaterals.clone()); - self.add_all_reference_inputs(self.mesh_tx_builder_body.reference_inputs.clone()); - self.add_all_mints(self.mesh_tx_builder_body.mints.clone()); - self.add_validity_range(self.mesh_tx_builder_body.validity_range.clone()); - self.add_all_required_signature(self.mesh_tx_builder_body.required_signatures.clone()); - self.add_all_metadata(self.mesh_tx_builder_body.metadata.clone()); - - self.mesh_csl.add_script_hash(); - // if self.mesh_tx_builder_body.change_address != "" { - // let collateral_inputs = self.mesh_tx_builder_body.collaterals.clone(); - // let collateral_vec: Vec = collateral_inputs - // .into_iter() - // .map(|pub_key_tx_in| { - // let assets = pub_key_tx_in.tx_in.amount.unwrap(); - // let lovelace = assets - // .into_iter() - // .find(|asset| asset.unit == "lovelace") - // .unwrap(); - // lovelace.quantity.parse::().unwrap() - // }) - // .collect(); - // let total_collateral: u64 = collateral_vec.into_iter().sum(); - - // let collateral_estimate: u64 = (150 - // * self - // .tx_builder - // .min_fee() - // .unwrap() - // .checked_add(&to_bignum(10000)) - // .unwrap() - // .to_string() - // .parse::() - // .unwrap()) - // / 100; - - // let mut collateral_return_needed = false; - // if (total_collateral - collateral_estimate) > 0 { - // let collateral_estimate_output = csl::TransactionOutput::new( - // &csl::address::Address::from_bech32(&self.mesh_tx_builder_body.change_address) - // .unwrap(), - // &csl::utils::Value::new(&to_bignum(collateral_estimate)), - // ); - - // let min_ada = csl::utils::min_ada_for_output( - // &collateral_estimate_output, - // &csl::DataCost::new_coins_per_byte(&to_bignum(4310)), - // ) - // .unwrap() - // .to_string() - // .parse::() - // .unwrap(); - - // if total_collateral - collateral_estimate > min_ada { - // self.tx_builder - // .set_collateral_return(&csl::TransactionOutput::new( - // &csl::address::Address::from_bech32( - // &self.mesh_tx_builder_body.change_address, - // ) - // .unwrap(), - // &csl::utils::Value::new(&to_bignum(total_collateral)), - // )); - - // self.tx_builder - // .set_total_collateral(&to_bignum(total_collateral)); - - // collateral_return_needed = true; - // } - // } - // self.add_change(self.mesh_tx_builder_body.change_address.clone()); - // if collateral_return_needed { - // self.add_collateral_return(self.mesh_tx_builder_body.change_address.clone()); - // } - // } - self.mesh_csl.add_change( - self.mesh_tx_builder_body.change_address.clone(), - self.mesh_tx_builder_body.change_datum.clone(), - ); - self.mesh_csl.build_tx(); - self - } - fn add_all_signing_keys(&mut self, signing_keys: JsVecString) { if !signing_keys.is_empty() { self.mesh_csl.add_signing_keys(signing_keys); } } - fn add_all_inputs(&mut self, inputs: Vec) { + fn add_all_inputs(mesh_csl: &mut MeshCSL, inputs: Vec) { for input in inputs { match input { - TxIn::PubKeyTxIn(pub_key_tx_in) => self.mesh_csl.add_tx_in(pub_key_tx_in), - TxIn::ScriptTxIn(script_tx_in) => self.mesh_csl.add_script_tx_in(script_tx_in), + TxIn::PubKeyTxIn(pub_key_tx_in) => mesh_csl.add_tx_in(pub_key_tx_in), + TxIn::ScriptTxIn(script_tx_in) => mesh_csl.add_script_tx_in(script_tx_in), }; } - self.mesh_csl - .tx_builder - .set_inputs(&self.mesh_csl.tx_inputs_builder); + mesh_csl.tx_builder.set_inputs(&mesh_csl.tx_inputs_builder); } - fn add_all_outputs(&mut self, outputs: Vec) { + fn add_all_outputs(mesh_csl: &mut MeshCSL, outputs: Vec) { for output in outputs { - self.mesh_csl.add_output(output); + mesh_csl.add_output(output); } } - fn add_all_collaterals(&mut self, collaterals: Vec) { + fn add_all_collaterals(mesh_csl: &mut MeshCSL, collaterals: Vec) { let mut collateral_builder = csl::TxInputsBuilder::new(); for collateral in collaterals { - self.mesh_csl - .add_collateral(&mut collateral_builder, collateral) + mesh_csl.add_collateral(&mut collateral_builder, collateral) } - self.mesh_csl.tx_builder.set_collateral(&collateral_builder) + mesh_csl.tx_builder.set_collateral(&collateral_builder) } - fn add_all_reference_inputs(&mut self, ref_inputs: Vec) { + fn add_all_reference_inputs(mesh_csl: &mut MeshCSL, ref_inputs: Vec) { for ref_input in ref_inputs { - self.mesh_csl.add_reference_input(ref_input); + mesh_csl.add_reference_input(ref_input); } } - fn add_all_mints(&mut self, mints: Vec) { + fn add_all_mints(mesh_csl: &mut MeshCSL, mints: Vec) { let mut mint_builder = csl::MintBuilder::new(); for (index, mint) in mints.into_iter().enumerate() { match mint.type_.as_str() { - "Plutus" => self - .mesh_csl - .add_plutus_mint(&mut mint_builder, mint, index as u64), - "Native" => self.mesh_csl.add_native_mint(&mut mint_builder, mint), + "Plutus" => mesh_csl.add_plutus_mint(&mut mint_builder, mint, index as u64), + "Native" => mesh_csl.add_native_mint(&mut mint_builder, mint), _ => {} }; } - self.mesh_csl.tx_builder.set_mint_builder(&mint_builder) + mesh_csl.tx_builder.set_mint_builder(&mint_builder) } - fn add_validity_range(&mut self, validity_range: ValidityRange) { + fn add_validity_range(mesh_csl: &mut MeshCSL, validity_range: ValidityRange) { if validity_range.invalid_before.is_some() { - self.mesh_csl - .add_invalid_before(validity_range.invalid_before.unwrap()) + mesh_csl.add_invalid_before(validity_range.invalid_before.unwrap()) } if validity_range.invalid_hereafter.is_some() { - self.mesh_csl - .add_invalid_hereafter(validity_range.invalid_hereafter.unwrap()) + mesh_csl.add_invalid_hereafter(validity_range.invalid_hereafter.unwrap()) } } - fn add_all_required_signature(&mut self, required_signatures: JsVecString) { + fn add_all_required_signature(mesh_csl: &mut MeshCSL, required_signatures: JsVecString) { for pub_key_hash in required_signatures { - self.mesh_csl.add_required_signature(pub_key_hash); + mesh_csl.add_required_signature(pub_key_hash); } } - fn add_all_metadata(&mut self, all_metadata: Vec) { + fn add_all_metadata(mesh_csl: &mut MeshCSL, all_metadata: Vec) { for metadata in all_metadata { - self.mesh_csl.add_metadata(metadata); + mesh_csl.add_metadata(metadata); } } diff --git a/packages/sidan-csl-rs/src/builder/interface.rs b/packages/sidan-csl-rs/src/builder/interface.rs index 5aea3b1..e679a6c 100644 --- a/packages/sidan-csl-rs/src/builder/interface.rs +++ b/packages/sidan-csl-rs/src/builder/interface.rs @@ -14,6 +14,7 @@ pub trait IMeshTxBuilderCore { /// ### Returns /// /// * `Self` - A new MeshTxBuilder instance + /// fn new_core() -> Self; /// ## Transaction building method @@ -23,16 +24,8 @@ pub trait IMeshTxBuilderCore { /// ### Returns /// /// * `String` - The signed transaction in hex - fn complete_signing(&mut self) -> String; - /// ## Transaction building method - /// - /// Serialize the transaction body - /// - /// ### Returns - /// - /// * `Self` - The MeshTxBuilder instance - fn serialize_tx_body(&mut self) -> &mut Self; + fn complete_signing(&mut self) -> String; /// ## Internal method /// @@ -49,8 +42,9 @@ pub trait IMeshTxBuilderCore { /// /// ### Arguments /// + /// * `mesh_csl` - The MeshCSL instance /// * `inputs` - A vector of inputs - fn add_all_inputs(&mut self, inputs: Vec); + fn add_all_inputs(mesh_csl: &mut MeshCSL, inputs: Vec); /// ## Internal method /// @@ -58,8 +52,9 @@ pub trait IMeshTxBuilderCore { /// /// ### Arguments /// + /// * `mesh_csl` - The MeshCSL instance /// * `outputs` - A vector of outputs - fn add_all_outputs(&mut self, outputs: Vec); + fn add_all_outputs(mesh_csl: &mut MeshCSL, outputs: Vec); /// ## Internal method /// @@ -67,8 +62,9 @@ pub trait IMeshTxBuilderCore { /// /// ## Arguments /// + /// * `mesh_csl` - The MeshCSL instance /// * `collaterals` - A vector of collaterals - fn add_all_collaterals(&mut self, collaterals: Vec); + fn add_all_collaterals(mesh_csl: &mut MeshCSL, collaterals: Vec); /// ## Internal method /// @@ -76,8 +72,9 @@ pub trait IMeshTxBuilderCore { /// /// ## Arguments /// + /// * `mesh_csl` - The MeshCSL instance /// * `ref_inputs` - A vector of reference inputs - fn add_all_reference_inputs(&mut self, ref_inputs: Vec); + fn add_all_reference_inputs(mesh_csl: &mut MeshCSL, ref_inputs: Vec); /// ## Internal method /// @@ -85,8 +82,9 @@ pub trait IMeshTxBuilderCore { /// /// ### Arguments /// + /// * `mesh_csl` - The MeshCSL instance /// * `mints` - A vector of mints - fn add_all_mints(&mut self, mints: Vec); + fn add_all_mints(mesh_csl: &mut MeshCSL, mints: Vec); /// ## Internal method /// @@ -94,8 +92,9 @@ pub trait IMeshTxBuilderCore { /// /// ### Arguments /// + /// * `mesh_csl` - The MeshCSL instance /// * `validity_range` - The validity range - fn add_validity_range(&mut self, validity_range: ValidityRange); + fn add_validity_range(mesh_csl: &mut MeshCSL, validity_range: ValidityRange); /// ## Internal method /// @@ -103,8 +102,9 @@ pub trait IMeshTxBuilderCore { /// /// ### Arguments /// + /// * `mesh_csl` - The MeshCSL instance /// * `required_signatures` - A vector of required signatures - fn add_all_required_signature(&mut self, required_signatures: JsVecString); + fn add_all_required_signature(mesh_csl: &mut MeshCSL, required_signatures: JsVecString); /// ## Internal method /// @@ -112,6 +112,7 @@ pub trait IMeshTxBuilderCore { /// /// ### Arguments /// + /// * `mesh_csl` - The MeshCSL instance /// * `all_metadata` - A vector of metadata - fn add_all_metadata(&mut self, all_metadata: Vec); + fn add_all_metadata(mesh_csl: &mut MeshCSL, all_metadata: Vec); } diff --git a/packages/sidan-csl-rs/src/core/algo/utxo_selection.rs b/packages/sidan-csl-rs/src/core/algo/utxo_selection.rs index c5cd52d..4177984 100644 --- a/packages/sidan-csl-rs/src/core/algo/utxo_selection.rs +++ b/packages/sidan-csl-rs/src/core/algo/utxo_selection.rs @@ -28,7 +28,7 @@ pub fn select_utxos( let mut use_utxo = |index: usize, total_required_assets: &mut Value| { let utxo = inputs[index].clone(); for asset in utxo.output.amount { - total_required_assets.negate_asset(Asset::new(asset.unit, asset.quantity)); + total_required_assets.negate_asset(Asset::new(asset.unit(), asset.quantity())); used_utxos.insert(index); } }; @@ -41,7 +41,7 @@ pub fn select_utxos( } let utxo = inputs[index].clone(); for asset in utxo.output.amount { - if asset.unit == unit { + if asset.unit() == unit { use_utxo(index, total_required_assets); break; } @@ -105,10 +105,7 @@ fn test_basic_selection() { }, output: UtxoOutput { address: "test".to_string(), - amount: vec![Asset { - unit: "lovelace".to_string(), - quantity: "10000000".to_string(), - }], + amount: vec![Asset::new_from_str("lovelace", "10000000")], data_hash: None, plutus_data: None, script_ref: None, diff --git a/packages/sidan-csl-rs/src/core/builder.rs b/packages/sidan-csl-rs/src/core/builder.rs index d6bea01..42aed5b 100644 --- a/packages/sidan-csl-rs/src/core/builder.rs +++ b/packages/sidan-csl-rs/src/core/builder.rs @@ -22,7 +22,7 @@ pub trait IMeshCSL { fn add_required_signature(&mut self, pub_key_hash: String); fn add_metadata(&mut self, metadata: Metadata); fn add_script_hash(&mut self); - fn build_tx(&mut self); + fn build_tx(&mut self) -> String; } pub struct MeshCSL { @@ -280,9 +280,9 @@ impl IMeshCSL for MeshCSL { &csl::AssetName::new(hex::decode(mint.asset_name).unwrap()).unwrap(), &csl::Int::new_i32(mint.amount.try_into().unwrap()), ), - ScriptSource::InlineScriptSource(_) => { - Err(csl::JsError::from_str("Native scripts cannot be referenced")) - } + ScriptSource::InlineScriptSource(_) => Err(csl::JsError::from_str( + "Native scripts cannot be referenced", + )), }; } @@ -340,9 +340,10 @@ impl IMeshCSL for MeshCSL { .unwrap(); } - fn build_tx(&mut self) { + fn build_tx(&mut self) -> String { let tx = self.tx_builder.build_tx().unwrap(); self.tx_hex = tx.to_hex(); + self.tx_hex.to_string() } } diff --git a/packages/sidan-csl-rs/src/core/tx_parser/mod.rs b/packages/sidan-csl-rs/src/core/tx_parser/mod.rs index d45eea9..ea001de 100644 --- a/packages/sidan-csl-rs/src/core/tx_parser/mod.rs +++ b/packages/sidan-csl-rs/src/core/tx_parser/mod.rs @@ -138,10 +138,10 @@ impl IMeshTxParser for MeshTxParser { fn csl_output_to_mesh_output(output: csl::TransactionOutput) -> Output { let mut value: Vec = vec![]; - value.push(Asset { - unit: "lovelace".to_string(), - quantity: output.amount().coin().to_str(), - }); + value.push(Asset::new_from_str( + "lovelace", + &output.amount().coin().to_str(), + )); let multi_asset = output.amount().multiasset(); match multi_asset { @@ -155,10 +155,10 @@ fn csl_output_to_mesh_output(output: csl::TransactionOutput) -> Output { let asset_quantity = assets.get(&asset_name).unwrap(); let concated_name = policy_id.to_hex() + &asset_name.to_string(); - value.push(Asset { - unit: concated_name, - quantity: asset_quantity.to_str(), - }) + value.push(Asset::new_from_str( + &concated_name, + &asset_quantity.to_str(), + )) } } } diff --git a/packages/sidan-csl-rs/src/core/utils/ungroup.rs b/packages/sidan-csl-rs/src/core/utils/ungroup.rs index 4d46708..1eb8c8f 100644 --- a/packages/sidan-csl-rs/src/core/utils/ungroup.rs +++ b/packages/sidan-csl-rs/src/core/utils/ungroup.rs @@ -27,29 +27,29 @@ pub fn build_tx_builder() -> csl::TransactionBuilder { } pub fn to_value(assets: &Vec) -> csl::Value { - let lovelace = assets.iter().find(|asset| asset.unit == "lovelace"); + let lovelace = assets.iter().find(|asset| asset.unit() == "lovelace"); let mut multi_asset = csl::MultiAsset::new(); for asset in assets { - if asset.unit == "lovelace" { + if asset.unit() == "lovelace" { continue; } let mut policy_assets = csl::Assets::new(); let name_bytes = - Vec::::from_hex(&asset.unit[56..]).expect("Failed to parse hex asset name"); + Vec::::from_hex(&asset.unit()[56..]).expect("Failed to parse hex asset name"); policy_assets.insert( &csl::AssetName::new(name_bytes).unwrap(), - &csl::BigNum::from_str(&asset.quantity.to_string()).unwrap(), + &csl::BigNum::from_str(&asset.quantity().to_string()).unwrap(), ); multi_asset.insert( - &csl::ScriptHash::from_hex(&asset.unit[0..56]).unwrap(), + &csl::ScriptHash::from_hex(&asset.unit()[0..56]).unwrap(), &policy_assets, ); } let lovelace_asset = match lovelace { - Some(asset) => csl::BigNum::from_str(&asset.quantity).unwrap(), + Some(asset) => csl::BigNum::from_str(&asset.quantity()).unwrap(), None => csl::BigNum::from_str("0").unwrap(), }; diff --git a/packages/sidan-csl-rs/src/model/asset.rs b/packages/sidan-csl-rs/src/model/asset.rs index d9403d8..a9bd4ec 100644 --- a/packages/sidan-csl-rs/src/model/asset.rs +++ b/packages/sidan-csl-rs/src/model/asset.rs @@ -1,7 +1,12 @@ -#[derive(Clone, Debug, PartialEq)] +use crate::*; +use schemars::JsonSchema; +use serde; + +#[wasm_bindgen] +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, JsonSchema)] pub struct Asset { - pub unit: String, - pub quantity: String, + unit: String, + quantity: String, } impl Asset { @@ -14,4 +19,10 @@ impl Asset { quantity: quantity.to_string(), } } + pub fn unit(&self) -> String { + self.unit.clone() + } + pub fn quantity(&self) -> String { + self.quantity.clone() + } } diff --git a/packages/sidan-csl-rs/src/model/js_vec.rs b/packages/sidan-csl-rs/src/model/js_vec.rs index 0d51913..bbb2916 100644 --- a/packages/sidan-csl-rs/src/model/js_vec.rs +++ b/packages/sidan-csl-rs/src/model/js_vec.rs @@ -1,7 +1,8 @@ use crate::*; +use serde::{Deserialize, Serialize}; #[wasm_bindgen] -#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Default)] +#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Default, Serialize, Deserialize)] pub struct JsVecString(Vec); #[wasm_bindgen] diff --git a/packages/sidan-csl-rs/src/model/mod.rs b/packages/sidan-csl-rs/src/model/mod.rs index ad272a1..218a402 100644 --- a/packages/sidan-csl-rs/src/model/mod.rs +++ b/packages/sidan-csl-rs/src/model/mod.rs @@ -8,10 +8,11 @@ pub use action::*; pub use asset::*; pub use data::*; pub use js_vec::*; +use serde::{Deserialize, Serialize}; pub use serialized_address::*; pub use value::*; -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct MeshTxBuilderBody { pub inputs: Vec, pub outputs: Vec, @@ -26,46 +27,45 @@ pub struct MeshTxBuilderBody { pub signing_key: JsVecString, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Output { pub address: String, pub amount: Vec, pub datum: Option, pub reference_script: Option, } - -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct ValidityRange { pub invalid_before: Option, pub invalid_hereafter: Option, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum TxIn { PubKeyTxIn(PubKeyTxIn), ScriptTxIn(ScriptTxIn), } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct RefTxIn { pub tx_hash: String, pub tx_index: u32, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct PubKeyTxIn { pub type_: String, pub tx_in: TxInParameter, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct ScriptTxIn { pub type_: String, pub tx_in: TxInParameter, pub script_tx_in: ScriptTxInParameter, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct TxInParameter { pub tx_hash: String, pub tx_index: u32, @@ -73,26 +73,26 @@ pub struct TxInParameter { pub address: Option, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct ScriptTxInParameter { pub script_source: Option, pub datum_source: Option, pub redeemer: Option, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum ScriptSource { ProvidedScriptSource(ProvidedScriptSource), InlineScriptSource(InlineScriptSource), } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct ProvidedScriptSource { pub script_cbor: String, pub language_version: LanguageVersion, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct InlineScriptSource { pub tx_hash: String, pub tx_index: u32, @@ -101,38 +101,38 @@ pub struct InlineScriptSource { pub script_size: usize, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum LanguageVersion { V1, V2, V3, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum DatumSource { ProvidedDatumSource(ProvidedDatumSource), InlineDatumSource(InlineDatumSource), } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct ProvidedDatumSource { pub data: String, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct InlineDatumSource { pub tx_hash: String, pub tx_index: u32, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct ScriptSourceInfo { pub tx_hash: String, pub tx_index: u32, pub spending_script_hash: Option, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct MintItem { pub type_: String, pub policy_id: String, @@ -142,37 +142,37 @@ pub struct MintItem { pub script_source: Option, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Redeemer { pub data: String, pub ex_units: Budget, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Budget { pub mem: u64, pub steps: u64, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Metadata { pub tag: String, pub metadata: String, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Datum { pub type_: String, // Currently it is either "Hash" or "Inline" pub data: String, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct UtxoInput { pub output_index: u32, pub tx_hash: String, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct UtxoOutput { pub address: String, pub amount: Vec, @@ -182,7 +182,7 @@ pub struct UtxoOutput { pub script_hash: Option, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct UTxO { pub input: UtxoInput, pub output: UtxoOutput, diff --git a/packages/sidan-csl-rs/src/model/value.rs b/packages/sidan-csl-rs/src/model/value.rs index 7b309c6..62d531d 100644 --- a/packages/sidan-csl-rs/src/model/value.rs +++ b/packages/sidan-csl-rs/src/model/value.rs @@ -14,8 +14,8 @@ impl Value { pub fn from_asset(asset: Asset) -> Self { let mut asset_map = HashMap::new(); asset_map.insert( - asset.unit.to_string(), - asset.quantity.parse::().unwrap(), + asset.unit().to_string(), + asset.quantity().parse::().unwrap(), ); Value(asset_map) } @@ -23,15 +23,15 @@ impl Value { pub fn from_asset_vec(assets: Vec) -> Self { let mut asset_map = HashMap::new(); for asset in assets { - let current_value = asset_map.entry(asset.unit.to_string()).or_insert(0); - *current_value += asset.quantity.parse::().unwrap(); + let current_value = asset_map.entry(asset.unit().to_string()).or_insert(0); + *current_value += asset.quantity().parse::().unwrap(); } Value(asset_map) } pub fn add_asset(&mut self, asset: Asset) -> &mut Self { - let current_value = self.0.entry(asset.unit.to_string()).or_insert(0); - *current_value += asset.quantity.parse::().unwrap(); + let current_value = self.0.entry(asset.unit().to_string()).or_insert(0); + *current_value += asset.quantity().parse::().unwrap(); self } @@ -44,10 +44,10 @@ impl Value { } pub fn negate_asset(&mut self, other: Asset) -> &mut Self { - let current_value = self.0.entry(other.unit.to_string()).or_insert(0); - let negate_quantity = other.quantity.parse::().unwrap(); + let current_value = self.0.entry(other.unit().to_string()).or_insert(0); + let negate_quantity = other.quantity().parse::().unwrap(); if *current_value <= negate_quantity { - self.0.remove(&other.unit); + self.0.remove(&other.unit()); } else { *current_value -= negate_quantity; }; @@ -69,10 +69,7 @@ impl Value { pub fn to_asset_vec(&self) -> Vec { let mut assets = vec![]; for (unit, quantity) in &self.0 { - assets.push(Asset { - unit: unit.to_string(), - quantity: quantity.to_string(), - }); + assets.push(Asset::new(unit.to_string(), quantity.to_string())); } assets } @@ -151,10 +148,7 @@ mod tests { fn test_negate_asset() { let mut assets = Value::new(); assets.0.insert("lovelace".to_string(), 100); - assets.negate_asset(Asset { - unit: "lovelace".to_string(), - quantity: "65".to_string(), - }); + assets.negate_asset(Asset::new_from_str("lovelace", "65")); assert_eq!(assets.0.get("lovelace").unwrap(), &35); } @@ -162,10 +156,7 @@ mod tests { fn test_negate_asset_to_zero() { let mut assets = Value::new(); assets.0.insert("lovelace".to_string(), 100); - assets.negate_asset(Asset { - unit: "lovelace".to_string(), - quantity: "101".to_string(), - }); + assets.negate_asset(Asset::new_from_str("lovelace", "101")); assert_eq!(assets.0.get("lovelace"), None); } diff --git a/packages/whisky/Cargo.toml b/packages/whisky/Cargo.toml index 124b357..397cc35 100644 --- a/packages/whisky/Cargo.toml +++ b/packages/whisky/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "whisky" -version = "0.5.0-alpha.3" +version = "0.5.0-alpha.4" edition = "2021" license = "Apache-2.0" description = "The Cardano Rust SDK, inspired by MeshJS" @@ -24,7 +24,7 @@ noop_proc_macro = "0.3.0" pallas-codec = "0.22.0" pallas-primitives = "0.22.0" pallas-traverse = "0.22.0" -sidan-csl-rs = { version = "=0.5.0-alpha.3", path = "../sidan-csl-rs" } +sidan-csl-rs = { version = "=0.5.0-alpha.4", path = "../sidan-csl-rs" } [profile.release] # Tell `rustc` to optimize for small code size. diff --git a/packages/whisky/src/builder/core.rs b/packages/whisky/src/builder/core.rs index b558b15..915ff95 100644 --- a/packages/whisky/src/builder/core.rs +++ b/packages/whisky/src/builder/core.rs @@ -68,7 +68,7 @@ impl IMeshTxBuilder for MeshTxBuilder { self.add_utxos_from(self.extra_inputs.clone(), self.selection_threshold); } } - self.core.serialize_tx_body(); + // self.core.serialize_tx_body(); self.core.mesh_csl.tx_builder = build_tx_builder(); self.core.mesh_csl.tx_inputs_builder = csl::TxInputsBuilder::new(); self @@ -569,10 +569,10 @@ impl IMeshTxBuilder for MeshTxBuilder { } for mint in &self.core.mesh_tx_builder_body.mints { - let mint_amount = Asset { - unit: mint.policy_id.clone() + &mint.asset_name, - quantity: mint.amount.to_string(), - }; + let mint_amount = Asset::new( + mint.policy_id.clone() + &mint.asset_name, + mint.amount.to_string(), + ); required_assets.negate_asset(mint_amount); } diff --git a/packages/whisky/src/builder/tx_eval.rs b/packages/whisky/src/builder/tx_eval.rs index 13d6343..8d3d24c 100644 --- a/packages/whisky/src/builder/tx_eval.rs +++ b/packages/whisky/src/builder/tx_eval.rs @@ -182,8 +182,8 @@ fn to_pallas_datum(utxo_output: &UtxoOutput) -> Result, JsEr fn to_pallas_value(assets: &Vec) -> Result { if assets.len() == 1 { - match assets[0].unit.as_str() { - "lovelace" => Ok(Value::Coin(assets[0].quantity.parse::().unwrap())), + match assets[0].unit().as_str() { + "lovelace" => Ok(Value::Coin(assets[0].quantity().parse::().unwrap())), _ => Err(JsError::from_str("Invalid value")), } } else { @@ -195,14 +195,15 @@ fn to_pallas_multi_asset_value(assets: &Vec) -> Result { let mut coins: Coin = 0; let mut asset_mapping: HashMap> = HashMap::new(); for asset in assets { - if asset.unit == "lovelace" || asset.unit.is_empty() { - coins = asset.quantity.parse::().unwrap(); + if asset.unit() == "lovelace" || asset.unit().is_empty() { + coins = asset.quantity().parse::().unwrap(); } else { - let (policy_id, asset_name) = asset.unit.split_at(56); + let asset_unit = asset.unit(); + let (policy_id, asset_name) = asset_unit.split_at(56); asset_mapping .entry(policy_id.to_string()) .or_default() - .push((asset_name.to_string(), asset.quantity.clone())) + .push((asset_name.to_string(), asset.quantity().clone())) } } @@ -396,10 +397,7 @@ mod test { }, output: UtxoOutput { address: "addr_test1wzlwsgq97vchypqzk8u8lz30w932tvx7akcj7csm02scl7qlghd97".to_string(), - amount: vec![Asset { - unit: "lovelace".to_string(), - quantity: "986990".to_string(), - }], + amount: vec![Asset::new_from_str("lovelace", "986990")], data_hash: None, plutus_data: Some(serde_json::json!({ "constructor": 0, @@ -416,10 +414,7 @@ mod test { }, output: UtxoOutput { address: "addr_test1vq0atw43vuecjuwe9dxc7z7l2lvgnyp7d6f5ul4r3376mug8v67h5".to_string(), - amount: vec![Asset { - unit: "lovelace".to_string(), - quantity: "9974857893".to_string(), - }], + amount: vec![Asset::new_from_str("lovelace", "9974857893")], data_hash: None, plutus_data: None, script_hash: None, @@ -433,10 +428,7 @@ mod test { }, output: UtxoOutput { address: "addr_test1wzlwsgq97vchypqzk8u8lz30w932tvx7akcj7csm02scl7qlghd97".to_string(), - amount: vec![Asset { - unit: "lovelace".to_string(), - quantity: "986990".to_string(), - }], + amount: vec![Asset::new_from_str("lovelace", "986990")], data_hash: None, plutus_data: None, script_hash: None, diff --git a/packages/whisky/tests/integration_tests.rs b/packages/whisky/tests/integration_tests.rs index b5cb1ff..314b30e 100644 --- a/packages/whisky/tests/integration_tests.rs +++ b/packages/whisky/tests/integration_tests.rs @@ -54,10 +54,7 @@ mod int_tests { mesh.tx_in( "fc1c806abc9981f4bee2ce259f61578c3341012f3d04f22e82e7e40c7e7e3c3c", 3, - vec![Asset { - unit: "lovelace".to_string(), - quantity: "9692479606".to_string(), - }], + vec![Asset::new_from_str("lovelace", "9692479606")], "addr_test1vpw22xesfv0hnkfw4k5vtrz386tfgkxu6f7wfadug7prl7s6gt89x", ) .read_only_tx_in_reference( @@ -88,10 +85,10 @@ mod int_tests { .tx_in( record_tx_hash, record_tx_id, - vec![Asset { - unit: record_token_policy_id.to_string() + record_token_name_hex, - quantity: "1".to_string(), - }], + vec![Asset::new( + record_token_policy_id.to_string() + record_token_name_hex, + "1".to_string(), + )], "addr_test1wz97vqzhce0m4ek4cpnnlzvlaf5gdzck46axlur094lnzcgj0pq2u", ) .spending_reference_tx_in_inline_datum_present() @@ -116,34 +113,22 @@ mod int_tests { .tx_out( wallet_address, vec![ - Asset { - unit: "lovelace".to_string(), - quantity: "2000000".to_string(), - }, - Asset { - unit: cns_policy_id.to_string() + domain_with_ext, - quantity: "1".to_string(), - }, + Asset::new_from_str("lovelace", "2000000"), + Asset::new(cns_policy_id.to_string() + domain_with_ext, "1".to_string()), ], ) .tx_out( cns_owner_addr, - vec![Asset { - unit: "lovelace".to_string(), - quantity: "30000000".to_string(), - }], + vec![Asset::new_from_str("lovelace", "30000000")], ) .tx_out( record_validator_addr, vec![ - Asset { - unit: "lovelace".to_string(), - quantity: "20000000".to_string(), - }, - Asset { - unit: record_token_policy_id.to_string() + record_token_name_hex, - quantity: "1".to_string(), - }, + Asset::new_from_str("lovelace", "20000000"), + Asset::new( + record_token_policy_id.to_string() + record_token_name_hex, + "1".to_string(), + ), ], ) .tx_out_inline_datum_value( @@ -159,19 +144,13 @@ mod int_tests { .tx_in_collateral( "3fbdf2b0b4213855dd9b87f7c94a50cf352ba6edfdded85ecb22cf9ceb75f814", 6, - vec![Asset { - unit: "lovelace".to_string(), - quantity: "10000000".to_string(), - }], + vec![Asset::new_from_str("lovelace", "10000000")], "addr_test1vpw22xesfv0hnkfw4k5vtrz386tfgkxu6f7wfadug7prl7s6gt89x", ) .tx_in_collateral( "3fbdf2b0b4213855dd9b87f7c94a50cf352ba6edfdded85ecb22cf9ceb75f814", 7, - vec![Asset { - unit: "lovelace".to_string(), - quantity: "10000000".to_string(), - }], + vec![Asset::new_from_str("lovelace", "10000000")], "addr_test1vpw22xesfv0hnkfw4k5vtrz386tfgkxu6f7wfadug7prl7s6gt89x", ) .change_address(wallet_address) @@ -192,10 +171,7 @@ mod int_tests { .tx_in( "2cb57168ee66b68bd04a0d595060b546edf30c04ae1031b883c9ac797967dd85", 3, - vec![Asset { - unit: "lovelace".to_string(), - quantity: "9891607895".to_string(), - }], + vec![Asset::new_from_str("lovelace", "9891607895")], "addr_test1vru4e2un2tq50q4rv6qzk7t8w34gjdtw3y2uzuqxzj0ldrqqactxh", ) .change_address("addr_test1vru4e2un2tq50q4rv6qzk7t8w34gjdtw3y2uzuqxzj0ldrqqactxh") diff --git a/packages/whisky/tests/mesh_tx_builder.rs b/packages/whisky/tests/mesh_tx_builder.rs index 2aa7d42..0f0c714 100644 --- a/packages/whisky/tests/mesh_tx_builder.rs +++ b/packages/whisky/tests/mesh_tx_builder.rs @@ -20,10 +20,7 @@ mod mesh_tx_builder_core_tests { fetcher: None, submitter: None, }); - let asset = Asset { - unit: "lovelace".to_string(), - quantity: "30000000".to_string(), - }; + let asset = Asset::new_from_str("lovelace", "30000000"); mesh.tx_in( "93fec6deaafabcc394a15552b57b1beca120d9ee90480d1e5cb42ff20118d40a", 1, @@ -39,10 +36,7 @@ mod mesh_tx_builder_core_tests { fetcher: None, submitter: None, }); - let asset = Asset { - unit: "lovelace".to_string(), - quantity: "30000000".to_string(), - }; + let asset = Asset::new_from_str("lovelace", "30000000"); let data = to_string(&json!({ "constructor": 0, @@ -74,10 +68,7 @@ mod mesh_tx_builder_core_tests { fetcher: None, submitter: None, }); - let asset = Asset { - unit: "lovelace".to_string(), - quantity: "30000000".to_string(), - }; + let asset = Asset::new_from_str("lovelace", "30000000"); let data = to_string(&json!({ "constructor": 0, @@ -109,10 +100,7 @@ mod mesh_tx_builder_core_tests { fetcher: None, submitter: None, }); - let asset = Asset { - unit: "lovelace".to_string(), - quantity: "30000000".to_string(), - }; + let asset = Asset::new_from_str("lovelace", "30000000"); let data = to_string(&json!({ "constructor": 0, @@ -151,10 +139,7 @@ mod mesh_tx_builder_core_tests { fetcher: None, submitter: None, }); - let asset = Asset { - unit: "lovelace".to_string(), - quantity: "30000000".to_string(), - }; + let asset = Asset::new_from_str("lovelace", "30000000"); let data = to_string(&json!({ "constructor": 0, @@ -189,10 +174,7 @@ mod mesh_tx_builder_core_tests { submitter: None, }); - let asset = Asset { - unit: "lovelace".to_string(), - quantity: "30000000".to_string(), - }; + let asset = Asset::new_from_str("lovelace", "30000000"); let data = to_string(&json!({ "constructor": 0, @@ -239,10 +221,7 @@ mod mesh_tx_builder_core_tests { mesh.tx_in( "fc1c806abc9981f4bee2ce259f61578c3341012f3d04f22e82e7e40c7e7e3c3c", 3, - vec![Asset { - unit: "lovelace".to_string(), - quantity: "9692479606".to_string(), - }], + vec![Asset::new_from_str("lovelace", "9692479606")], "addr_test1vpw22xesfv0hnkfw4k5vtrz386tfgkxu6f7wfadug7prl7s6gt89x", ) .mint_plutus_script_v2()