cardano_serialization_lib/builders/
output_builder.rs

1use crate::*;
2
3/// We introduce a builder-pattern format for creating transaction outputs
4/// This is because:
5/// 1. Some fields (i.e. data hash) are optional, and we can't easily expose Option<> in WASM
6/// 2. Some fields like amounts have many ways it could be set (some depending on other field values being known)
7/// 3. Easier to adapt as the output format gets more complicated in future Cardano releases
8
9#[wasm_bindgen]
10#[derive(Clone, Debug)]
11pub struct TransactionOutputBuilder {
12    address: Option<Address>,
13    data: Option<DataOption>,
14    script_ref: Option<ScriptRef>,
15}
16
17#[wasm_bindgen]
18impl TransactionOutputBuilder {
19    pub fn new() -> Self {
20        Self {
21            address: None,
22            data: None,
23            script_ref: None,
24        }
25    }
26
27    pub fn with_address(&self, address: &Address) -> Self {
28        let mut cfg = self.clone();
29        cfg.address = Some(address.clone());
30        cfg
31    }
32
33    pub fn with_data_hash(&self, data_hash: &DataHash) -> Self {
34        let mut cfg = self.clone();
35        cfg.data = Some(DataOption::DataHash(data_hash.clone()));
36        cfg
37    }
38
39    pub fn with_plutus_data(&self, data: &PlutusData) -> Self {
40        let mut cfg = self.clone();
41        cfg.data = Some(DataOption::Data(data.clone()));
42        cfg
43    }
44
45    pub fn with_script_ref(&self, script_ref: &ScriptRef) -> Self {
46        let mut cfg = self.clone();
47        cfg.script_ref = Some(script_ref.clone());
48        cfg
49    }
50
51    pub fn next(&self) -> Result<TransactionOutputAmountBuilder, JsError> {
52        Ok(TransactionOutputAmountBuilder {
53            address: self.address.clone().ok_or(JsError::from_str(
54                "TransactionOutputBaseBuilder: Address missing",
55            ))?,
56            amount: None,
57            data: self.data.clone(),
58            script_ref: self.script_ref.clone(),
59        })
60    }
61}
62
63#[wasm_bindgen]
64#[derive(Clone, Debug)]
65pub struct TransactionOutputAmountBuilder {
66    address: Address,
67    amount: Option<Value>,
68    data: Option<DataOption>,
69    script_ref: Option<ScriptRef>,
70}
71
72#[wasm_bindgen]
73impl TransactionOutputAmountBuilder {
74    pub fn with_value(&self, amount: &Value) -> Self {
75        let mut cfg = self.clone();
76        cfg.amount = Some(amount.clone());
77        cfg
78    }
79
80    pub fn with_coin(&self, coin: &Coin) -> Self {
81        let mut cfg = self.clone();
82
83        cfg.amount = Some(Value::new(coin));
84        cfg
85    }
86
87    pub fn with_coin_and_asset(&self, coin: &Coin, multiasset: &MultiAsset) -> Self {
88        let mut cfg = self.clone();
89
90        let mut val = Value::new(coin);
91        val.set_multiasset(multiasset);
92        cfg.amount = Some(val.clone());
93        cfg
94    }
95
96pub fn with_asset_and_min_required_coin_by_utxo_cost(
97    &self,
98    multiasset: &MultiAsset,
99    data_cost: &DataCost,
100) -> Result<TransactionOutputAmountBuilder, JsError> {
101    let mut calc = MinOutputAdaCalculator::new_empty(data_cost)?;
102
103    calc.set_address(&self.address);
104
105    if let Some(data) = &self.data {
106        match data {
107            DataOption::DataHash(data_hash) => calc.set_data_hash(data_hash),
108            DataOption::Data(datum) => calc.set_plutus_data(datum),
109        };
110    }
111
112    if let Some(script_ref) = &self.script_ref {
113        calc.set_script_ref(script_ref);
114    }
115
116    let mut value = Value::new(&Coin::zero());
117    value.set_multiasset(multiasset);
118
119    calc.set_amount(&value);
120
121    let required_coin = calc.calculate_ada()?;
122
123    Ok(self.with_coin_and_asset(&required_coin, &multiasset))
124}
125
126    pub fn build(&self) -> Result<TransactionOutput, JsError> {
127        Ok(TransactionOutput {
128            address: self.address.clone(),
129            amount: self.amount.clone().ok_or(JsError::from_str(
130                "TransactionOutputAmountBuilder: amount missing",
131            ))?,
132            plutus_data: self.data.clone(),
133            script_ref: self.script_ref.clone(),
134            serialization_format: None,
135        })
136    }
137}