Skip to content

Commit

Permalink
WASM code for builders (all)
Browse files Browse the repository at this point in the history
Includes direct 1:1 wrappers for misc builders (#197) and tx_builder
(#210)
  • Loading branch information
rooooooooob committed May 31, 2023
1 parent 99ffb1c commit 6c4d8bd
Show file tree
Hide file tree
Showing 11 changed files with 1,049 additions and 4 deletions.
2 changes: 1 addition & 1 deletion chain/rust/src/builders/redeemer_builder.rs
Expand Up @@ -41,7 +41,7 @@ pub struct UntaggedRedeemer {
}

impl UntaggedRedeemer {
fn new(data: PlutusData, ex_units: ExUnits) -> Self {
pub fn new(data: PlutusData, ex_units: ExUnits) -> Self {
Self {
data,
ex_units
Expand Down
14 changes: 11 additions & 3 deletions chain/rust/src/builders/tx_builder.rs
Expand Up @@ -42,6 +42,9 @@ use cml_crypto::{Ed25519KeyHash, ScriptHash, Serialize, ScriptDataHash};
use rand::Rng;
use crate::builders::output_builder::TransactionOutputBuilder;

// for enums:
use wasm_bindgen::prelude::wasm_bindgen;

#[derive(Clone, Debug)]
pub struct TransactionUnspentOutput {
pub input: TransactionInput,
Expand Down Expand Up @@ -174,6 +177,7 @@ fn min_fee_with_exunits(tx_builder: &TransactionBuilder) -> Result<Coin, TxBuild
.map_err(Into::into)
}

#[wasm_bindgen]
pub enum CoinSelectionStrategyCIP2 {
/// Performs CIP2's Largest First ada-only selection. Will error if outputs contain non-ADA assets.
LargestFirst,
Expand Down Expand Up @@ -694,8 +698,8 @@ impl TransactionBuilder {
self.ttl = Some(ttl)
}

pub fn set_validity_start_interval(&mut self, validity_start_interval: &Slot) {
self.validity_start_interval = Some(*validity_start_interval)
pub fn set_validity_start_interval(&mut self, validity_start_interval: Slot) {
self.validity_start_interval = Some(validity_start_interval)
}

pub fn add_cert(&mut self, result: CertificateBuilderResult) {
Expand Down Expand Up @@ -1140,6 +1144,7 @@ impl TransactionBuilder {
}
}

#[derive(Debug, Clone)]
pub struct TxRedeemerBuilder {
draft_body: TransactionBody,
witness_builders: WitnessBuilders,
Expand Down Expand Up @@ -1183,6 +1188,7 @@ impl TxRedeemerBuilder {
}
}

#[derive(Debug, Clone)]
pub struct SignedTxBuilder {
body: TransactionBody,
witness_set: TransactionWitnessSetBuilder,
Expand Down Expand Up @@ -1272,13 +1278,15 @@ impl SignedTxBuilder {
}
}


#[wasm_bindgen]
pub enum ChangeSelectionAlgo {
Default,
}

pub fn choose_change_selection_algo(algo: ChangeSelectionAlgo) -> fn(&mut TransactionBuilder, &Address, include_exunits: bool) -> Result<bool, TxBuilderError> {
match algo {
Default => {
ChangeSelectionAlgo::Default => {
add_change_if_needed
}
}
Expand Down
58 changes: 58 additions & 0 deletions chain/wasm/src/builders/certificate_builder.rs
@@ -0,0 +1,58 @@
use crate::*;
use crate::builders::witness_builder::{PartialPlutusWitness};
use wasm_bindgen::prelude::{wasm_bindgen, JsError};
use cml_core_wasm::impl_wasm_conversions;

use super::witness_builder::{NativeScriptWitnessInfo};

use crate::{
certs::{Certificate},
transaction::RequiredSigners,
};

#[wasm_bindgen]
#[derive(Clone)]
pub struct CertificateBuilderResult(cml_chain::builders::certificate_builder::CertificateBuilderResult);

impl_wasm_conversions!(cml_chain::builders::certificate_builder::CertificateBuilderResult, CertificateBuilderResult);

#[wasm_bindgen]
#[derive(Clone)]
pub struct SingleCertificateBuilder(cml_chain::builders::certificate_builder::SingleCertificateBuilder);

impl_wasm_conversions!(cml_chain::builders::certificate_builder::SingleCertificateBuilder, SingleCertificateBuilder);

#[wasm_bindgen]
impl SingleCertificateBuilder {
pub fn new(cert: &Certificate) -> Self {
cml_chain::builders::certificate_builder::SingleCertificateBuilder::new(cert.clone().into()).into()
}

/// note: particularly useful for StakeRegistration which doesn't require witnessing
pub fn skip_witness(&self) -> CertificateBuilderResult {
self.0.clone().skip_witness().into()
}

pub fn payment_key(&self) -> Result<CertificateBuilderResult, JsError> {
self.0.clone().payment_key().map(Into::into).map_err(Into::into)
}

/** Signer keys don't have to be set. You can leave it empty and then add the required witnesses later */
pub fn native_script(&self, native_script: &NativeScript, witness_info: &NativeScriptWitnessInfo) -> Result<CertificateBuilderResult, JsError> {
self.0.clone().native_script(
native_script.clone().into(),
witness_info.clone().into()
)
.map(Into::into)
.map_err(Into::into)
}

pub fn plutus_script(self, partial_witness: &PartialPlutusWitness, required_signers: &RequiredSigners) -> Result<CertificateBuilderResult, JsError> {
self.0.clone().plutus_script(
partial_witness.clone().into(),
required_signers.clone().into()
)
.map(Into::into)
.map_err(Into::into)
}
}
51 changes: 51 additions & 0 deletions chain/wasm/src/builders/input_builder.rs
@@ -0,0 +1,51 @@
use crate::builders::witness_builder::{
PartialPlutusWitness, NativeScriptWitnessInfo
};
use wasm_bindgen::prelude::{wasm_bindgen, JsError};
use cml_core_wasm::impl_wasm_conversions;
use crate::{
NativeScript,
transaction::{TransactionInput, TransactionOutput, RequiredSigners},
plutus::PlutusData,
};

#[wasm_bindgen]
#[derive(Clone, Debug)]
pub struct InputBuilderResult(cml_chain::builders::input_builder::InputBuilderResult);

impl_wasm_conversions!(cml_chain::builders::input_builder::InputBuilderResult, InputBuilderResult);

#[wasm_bindgen]
#[derive(Clone)]
pub struct SingleInputBuilder(cml_chain::builders::input_builder::SingleInputBuilder);

impl_wasm_conversions!(cml_chain::builders::input_builder::SingleInputBuilder, SingleInputBuilder);

#[wasm_bindgen]
impl SingleInputBuilder {
pub fn new(input: &TransactionInput, utxo_info: &TransactionOutput) -> Self {
cml_chain::builders::input_builder::SingleInputBuilder::new(
input.clone().into(),
utxo_info.clone().into(),
).into()
}

pub fn payment_key(&self) -> Result<InputBuilderResult, JsError> {
self.0.clone().payment_key().map(Into::into).map_err(Into::into)
}

pub fn native_script(&self, native_script: &NativeScript, witness_info: &NativeScriptWitnessInfo) -> Result<InputBuilderResult, JsError> {
self.0.clone().native_script(
native_script.clone().into(),
witness_info.clone().into(),
).map(Into::into).map_err(Into::into)
}

pub fn plutus_script(&self, partial_witness: &PartialPlutusWitness, required_signers: &RequiredSigners, datum: &PlutusData) -> Result<InputBuilderResult, JsError> {
self.0.clone().plutus_script(
partial_witness.clone().into(),
required_signers.clone().into(),
datum.clone().into(),
).map(Into::into).map_err(Into::into)
}
}
50 changes: 50 additions & 0 deletions chain/wasm/src/builders/mint_builder.rs
@@ -0,0 +1,50 @@
use crate::builders::witness_builder::{
PartialPlutusWitness, NativeScriptWitnessInfo
};

use wasm_bindgen::prelude::{wasm_bindgen};
use cml_core_wasm::impl_wasm_conversions;

use crate::{
AssetName,
MapAssetNameToI64,
NativeScript,
transaction::RequiredSigners,
};

#[wasm_bindgen]
#[derive(Clone)]
pub struct MintBuilderResult(cml_chain::builders::mint_builder::MintBuilderResult);

impl_wasm_conversions!(cml_chain::builders::mint_builder::MintBuilderResult, MintBuilderResult);

#[wasm_bindgen]
#[derive(Clone)]
pub struct SingleMintBuilder(cml_chain::builders::mint_builder::SingleMintBuilder);

impl_wasm_conversions!(cml_chain::builders::mint_builder::SingleMintBuilder, SingleMintBuilder);

#[wasm_bindgen]
impl SingleMintBuilder {
pub fn new(assets: &MapAssetNameToI64) -> Self {
cml_chain::builders::mint_builder::SingleMintBuilder::new(assets.clone().into()).into()
}

pub fn new_single_asset(asset: &AssetName, amount: i64) -> Self {
cml_chain::builders::mint_builder::SingleMintBuilder::new_single_asset(asset.clone().into(), amount).into()
}

pub fn native_script(self, native_script: &NativeScript, witness_info: &NativeScriptWitnessInfo) -> MintBuilderResult {
self.0.clone().native_script(
native_script.clone().into(),
witness_info.clone().into(),
).into()
}

pub fn plutus_script(self, partial_witness: &PartialPlutusWitness, required_signers: &RequiredSigners) -> MintBuilderResult {
self.0.clone().plutus_script(
partial_witness.clone().into(),
required_signers.clone().into(),
).into()
}
}
8 changes: 8 additions & 0 deletions chain/wasm/src/builders/mod.rs
@@ -0,0 +1,8 @@
pub mod certificate_builder;
pub mod input_builder;
pub mod mint_builder;
pub mod output_builder;
pub mod redeemer_builder;
pub mod tx_builder;
pub mod withdrawal_builder;
pub mod witness_builder;
93 changes: 93 additions & 0 deletions chain/wasm/src/builders/output_builder.rs
@@ -0,0 +1,93 @@
use wasm_bindgen::{prelude::wasm_bindgen, JsError};

use cml_core_wasm::impl_wasm_conversions;

use crate::{
address::Address,
transaction::{DatumOption, ScriptRef, TransactionOutput},
plutus::PlutusData,
assets::{MultiAsset, Value, Coin},
};

/// We introduce a builder-pattern format for creating transaction outputs
/// This is because:
/// 1. Some fields (i.e. data hash) are optional, and we can't easily expose Option<> in WASM
/// 2. Some fields like amounts have many ways it could be set (some depending on other field values being known)
/// 3. Easier to adapt as the output format gets more complicated in future Cardano releases
#[derive(Clone, Debug, Default)]
#[wasm_bindgen]
pub struct TransactionOutputBuilder(cml_chain::builders::output_builder::TransactionOutputBuilder);

#[wasm_bindgen]
impl TransactionOutputBuilder {
pub fn new() -> Self {
cml_chain::builders::output_builder::TransactionOutputBuilder::new().into()
}

pub fn with_address(&self, address: &Address) -> Self {
self.0.clone().with_address(address.clone().into()).into()
}

/// A communication datum is one where the data hash is used in the tx output
/// Yet the full datum is included in the witness of the same transaction
pub fn with_communication_data(&self, datum: &PlutusData) -> Self {
self.0.clone().with_communication_data(datum.clone().into()).into()
}
pub fn with_data(&self, datum: &DatumOption) -> Self {
self.0.clone().with_data(datum.clone().into()).into()
}

pub fn with_reference_script(&self, script_ref: &ScriptRef) -> Self {
self.0.clone().with_reference_script(script_ref.clone().into()).into()
}

pub fn next(&self) -> Result<TransactionOutputAmountBuilder, JsError> {
self.0.clone().next().map(Into::into).map_err(Into::into)
}
}

impl_wasm_conversions!(cml_chain::builders::output_builder::TransactionOutputBuilder, TransactionOutputBuilder);

#[wasm_bindgen]
#[derive(Clone, Debug)]
pub struct TransactionOutputAmountBuilder(cml_chain::builders::output_builder::TransactionOutputAmountBuilder);

#[wasm_bindgen]
impl TransactionOutputAmountBuilder {
pub fn with_value(&self, amount: &Value) -> Self {
self.0.clone().with_value::<cml_chain::Value>(amount.clone().into()).into()
}

pub fn with_asset_and_min_required_coin(&self, multiasset: &MultiAsset, coins_per_utxo_byte: Coin) -> Result<TransactionOutputAmountBuilder, JsError> {
self.0.clone().with_asset_and_min_required_coin(multiasset.clone().into(), coins_per_utxo_byte)
.map(Into::into)
.map_err(Into::into)
}

pub fn build(&self) -> Result<SingleOutputBuilderResult, JsError> {
self.0.clone().build().map(Into::into).map_err(Into::into)
}
}

impl_wasm_conversions!(cml_chain::builders::output_builder::TransactionOutputAmountBuilder, TransactionOutputAmountBuilder);

#[wasm_bindgen]
#[derive(Clone, Debug)]
pub struct SingleOutputBuilderResult(cml_chain::builders::output_builder::SingleOutputBuilderResult);

#[wasm_bindgen]
impl SingleOutputBuilderResult {
pub fn new(output: &TransactionOutput) -> SingleOutputBuilderResult {
cml_chain::builders::output_builder::SingleOutputBuilderResult::new(output.clone().into()).into()
}

pub fn output(&self) -> TransactionOutput {
self.0.output.clone().into()
}

pub fn communication_datum(&self) -> Option<PlutusData> {
self.0.communication_datum.clone().map(Into::into)
}
}

impl_wasm_conversions!(cml_chain::builders::output_builder::SingleOutputBuilderResult, SingleOutputBuilderResult);

0 comments on commit 6c4d8bd

Please sign in to comment.