cardano_serialization_lib/builders/
tx_batch_builder.rs

1use crate::*;
2use batch_tools::asset_categorizer::AssetCategorizer;
3use batch_tools::proposals::TxProposal;
4
5#[wasm_bindgen]
6pub struct TransactionBatchList(Vec<TransactionBatch>);
7
8#[wasm_bindgen]
9impl TransactionBatchList {
10    pub fn len(&self) -> usize {
11        self.0.len()
12    }
13
14    pub fn get(&self, index: usize) -> TransactionBatch {
15        self.0[index].clone()
16    }
17}
18
19impl<'a> IntoIterator for &'a TransactionBatchList {
20    type Item = &'a TransactionBatch;
21    type IntoIter = std::slice::Iter<'a, TransactionBatch>;
22
23    fn into_iter(self) -> std::slice::Iter<'a, TransactionBatch> {
24        self.0.iter()
25    }
26}
27
28#[wasm_bindgen]
29#[derive(Clone)]
30pub struct TransactionBatch {
31    transactions: Vec<Transaction>,
32}
33
34#[wasm_bindgen]
35impl TransactionBatch {
36    pub fn len(&self) -> usize {
37        self.transactions.len()
38    }
39
40    pub fn get(&self, index: usize) -> Transaction {
41        self.transactions[index].clone()
42    }
43}
44
45impl<'a> IntoIterator for &'a TransactionBatch {
46    type Item = &'a Transaction;
47    type IntoIter = std::slice::Iter<'a, Transaction>;
48
49    fn into_iter(self) -> std::slice::Iter<'a, Transaction> {
50        self.transactions.iter()
51    }
52}
53
54impl TransactionBatch {
55    pub fn new() -> Self {
56        Self {
57            transactions: Vec::new(),
58        }
59    }
60
61    pub fn add_transaction(&mut self, transaction: Transaction) {
62        self.transactions.push(transaction);
63    }
64}
65
66struct TxBatchBuilder {
67    asset_groups: AssetCategorizer,
68    tx_proposals: Vec<TxProposal>,
69}
70
71impl TxBatchBuilder {
72    pub fn new(
73        utxos: &TransactionUnspentOutputs,
74        address: &Address,
75        config: &TransactionBuilderConfig,
76    ) -> Result<Self, JsError> {
77        let asset_groups = AssetCategorizer::new(config, utxos, address)?;
78        Ok(Self {
79            asset_groups,
80            tx_proposals: Vec::new(),
81        })
82    }
83
84    pub fn build(
85        &mut self,
86        utxos: &TransactionUnspentOutputs,
87    ) -> Result<TransactionBatch, JsError> {
88        while self.asset_groups.has_assets() || self.asset_groups.has_ada() {
89            let mut current_tx_proposal = TxProposal::new();
90            while let Some(tx_proposal) = self
91                .asset_groups
92                .try_append_next_utxos(&current_tx_proposal)?
93            {
94                current_tx_proposal = tx_proposal;
95            }
96
97            if current_tx_proposal.is_empty()
98                && (self.asset_groups.has_assets() || self.asset_groups.has_ada())
99            {
100                return Err(JsError::from_str("Unable to build transaction batch"));
101            }
102
103            current_tx_proposal.add_last_ada_to_last_output()?;
104            self.asset_groups
105                .set_min_ada_for_tx(&mut current_tx_proposal)?;
106            self.tx_proposals.push(current_tx_proposal);
107        }
108
109        let mut batch = TransactionBatch::new();
110        for tx_proposal in self.tx_proposals.iter_mut() {
111            batch.add_transaction(tx_proposal.create_tx(&self.asset_groups, utxos)?);
112        }
113
114        Ok(batch)
115    }
116}
117
118#[wasm_bindgen]
119pub fn create_send_all(
120    address: &Address,
121    utxos: &TransactionUnspentOutputs,
122    config: &TransactionBuilderConfig,
123) -> Result<TransactionBatchList, JsError> {
124    let mut tx_batch_builder = TxBatchBuilder::new(utxos, address, config)?;
125    let batch = tx_batch_builder.build(utxos)?;
126    Ok(TransactionBatchList(vec![batch]))
127}