cml_chain/builders/
output_builder.rs1use cml_core::ArithmeticError;
2
3use crate::{
4 address::Address,
5 assets::{Coin, MultiAsset, Value},
6 crypto::hash::hash_plutus_data,
7 min_ada::min_ada_required,
8 plutus::PlutusData,
9 transaction::{DatumOption, ScriptRef, TransactionOutput},
10};
11
12#[derive(Debug, thiserror::Error)]
13pub enum OutputBuilderError {
14 #[error("Address missing")]
15 AddressMissing,
16 #[error("Value missing")]
17 AmountMissing,
18 #[error("Min ADA error: {0:?}")]
19 MinAdaError(#[from] ArithmeticError),
20}
21
22#[derive(Clone, Debug, Default)]
29pub struct TransactionOutputBuilder {
30 pub address: Option<Address>,
31 pub datum: Option<DatumOption>,
32 pub communication_datum: Option<PlutusData>,
33 pub script_ref: Option<ScriptRef>,
34}
35
36impl TransactionOutputBuilder {
37 pub fn new() -> Self {
38 Self::default()
40 }
41
42 pub fn with_address(mut self, address: Address) -> Self {
43 self.address = Some(address);
44 self
45 }
46
47 pub fn with_communication_data(mut self, datum: PlutusData) -> Self {
50 self.datum = Some(DatumOption::new_hash(hash_plutus_data(&datum)));
51 self.communication_datum = Some(datum);
52 self
53 }
54 pub fn with_data(mut self, datum: DatumOption) -> Self {
55 self.datum = Some(datum);
56 self.communication_datum = None;
57 self
58 }
59
60 pub fn with_reference_script(mut self, script_ref: ScriptRef) -> Self {
61 self.script_ref = Some(script_ref);
62 self
63 }
64
65 pub fn next(self) -> Result<TransactionOutputAmountBuilder, OutputBuilderError> {
66 Ok(TransactionOutputAmountBuilder {
67 address: self.address.ok_or(OutputBuilderError::AddressMissing)?,
68 amount: None,
69 datum: self.datum,
70 script_ref: self.script_ref,
71 communication_datum: self.communication_datum,
72 })
73 }
74}
75
76#[derive(Clone, Debug)]
77pub struct TransactionOutputAmountBuilder {
78 address: Address,
79 amount: Option<Value>,
80 datum: Option<DatumOption>,
81 script_ref: Option<ScriptRef>,
82 communication_datum: Option<PlutusData>,
83}
84
85impl TransactionOutputAmountBuilder {
86 pub fn with_value<T: Into<Value>>(mut self, amount: T) -> Self {
87 self.amount = Some(amount.into());
88 self
89 }
90
91 pub fn with_asset_and_min_required_coin(
92 self,
93 multiasset: MultiAsset,
94 coins_per_utxo_byte: Coin,
95 ) -> Result<Self, OutputBuilderError> {
96 let mut min_output = TransactionOutput::new(
97 self.address.clone(),
98 self.amount.clone().unwrap_or_else(|| Value::from(0)),
99 self.datum.clone(),
100 self.script_ref.clone(),
101 );
102 let min_possible_coin = min_ada_required(&min_output, coins_per_utxo_byte)?;
103
104 let check_output = &mut min_output;
105 check_output.set_amount(Value::new(min_possible_coin, multiasset.clone()));
106
107 let required_coin = min_ada_required(check_output, coins_per_utxo_byte)?;
108
109 Ok(self.with_value(Value::new(required_coin, multiasset)))
110 }
111
112 pub fn build(self) -> Result<SingleOutputBuilderResult, OutputBuilderError> {
113 let output = TransactionOutput::new(
114 self.address,
115 self.amount.ok_or(OutputBuilderError::AmountMissing)?,
116 self.datum,
117 self.script_ref,
118 );
119 Ok(SingleOutputBuilderResult {
120 output,
121 communication_datum: self.communication_datum,
122 })
123 }
124}
125
126#[derive(Clone, Debug)]
127pub struct SingleOutputBuilderResult {
128 pub output: TransactionOutput,
129 pub communication_datum: Option<PlutusData>,
130}
131
132impl SingleOutputBuilderResult {
133 pub fn new(output: TransactionOutput) -> SingleOutputBuilderResult {
134 Self {
135 output,
136 communication_datum: None,
137 }
138 }
139}