ergo_lib_c_core/
box_selector.rs

1//! Simple box selection algorithms
2use ergo_lib::wallet::{self, box_selector::BoxSelector};
3
4use crate::{
5    collections::{Collection, CollectionPtr, ConstCollectionPtr},
6    ergo_box::{ConstBoxValuePtr, ErgoBox, ErgoBoxAssetsData},
7    token::Token,
8    util::{const_ptr_as_ref, mut_ptr_as_mut},
9    Error,
10};
11
12/// Selected boxes with change boxes (by [`BoxSelector`])
13#[derive(PartialEq, Eq, Debug, Clone)]
14pub struct BoxSelection(
15    pub(crate) wallet::box_selector::BoxSelection<ergo_lib::ergotree_ir::chain::ergo_box::ErgoBox>,
16);
17pub type BoxSelectionPtr = *mut BoxSelection;
18pub type ConstBoxSelectionPtr = *const BoxSelection;
19
20/// Create a selection to easily inject custom selection algorithms
21pub unsafe fn box_selection_new(
22    ergo_boxes_ptr: ConstCollectionPtr<ErgoBox>,
23    change_ergo_boxes_ptr: ConstCollectionPtr<ErgoBoxAssetsData>,
24    box_selection_out: *mut BoxSelectionPtr,
25) -> Result<(), Error> {
26    let ergo_boxes = const_ptr_as_ref(ergo_boxes_ptr, "ergo_boxes_ptr")?;
27    let change_ergo_boxes = const_ptr_as_ref(change_ergo_boxes_ptr, "change_ergo_boxes_ptr")?;
28    let box_selection_out = mut_ptr_as_mut(box_selection_out, "box_selection_out")?;
29    let boxes = wallet::box_selector::SelectedBoxes::from_vec(
30        ergo_boxes.0.clone().into_iter().map(|b| b.0).collect(),
31    )?;
32    *box_selection_out = Box::into_raw(Box::new(BoxSelection(
33        wallet::box_selector::BoxSelection::<ergo_lib::ergotree_ir::chain::ergo_box::ErgoBox> {
34            boxes,
35            change_boxes: change_ergo_boxes
36                .0
37                .clone()
38                .into_iter()
39                .map(|b| b.0)
40                .collect(),
41        },
42    )));
43    Ok(())
44}
45
46/// Selected boxes to spend as transaction inputs
47pub unsafe fn box_selection_boxes(
48    box_selection_ptr: ConstBoxSelectionPtr,
49    ergo_boxes_out: *mut CollectionPtr<ErgoBox>,
50) -> Result<(), Error> {
51    let box_selection = const_ptr_as_ref(box_selection_ptr, "box_selection_ptr")?;
52    let ergo_boxes_out = mut_ptr_as_mut(ergo_boxes_out, "ergo_boxes_out")?;
53    *ergo_boxes_out = Box::into_raw(Box::new(Collection(
54        box_selection
55            .0
56            .boxes
57            .clone()
58            .into_iter()
59            .map(ErgoBox)
60            .collect(),
61    )));
62    Ok(())
63}
64
65/// Selected boxes to use as change
66pub unsafe fn box_selection_change(
67    box_selection_ptr: ConstBoxSelectionPtr,
68    change_ergo_boxes_out: *mut CollectionPtr<ErgoBoxAssetsData>,
69) -> Result<(), Error> {
70    let box_selection = const_ptr_as_ref(box_selection_ptr, "box_selection_ptr")?;
71    let change_ergo_boxes_out = mut_ptr_as_mut(change_ergo_boxes_out, "change_ergo_boxes_out")?;
72    *change_ergo_boxes_out = Box::into_raw(Box::new(Collection(
73        box_selection
74            .0
75            .change_boxes
76            .clone()
77            .into_iter()
78            .map(ErgoBoxAssetsData)
79            .collect(),
80    )));
81    Ok(())
82}
83
84/// Naive box selector, collects inputs until target balance is reached
85pub struct SimpleBoxSelector(wallet::box_selector::SimpleBoxSelector);
86pub type SimpleBoxSelectorPtr = *mut SimpleBoxSelector;
87pub type ConstSimpleBoxSelectorPtr = *const SimpleBoxSelector;
88
89pub unsafe fn simple_box_selector_new(
90    simple_box_selector_out: *mut SimpleBoxSelectorPtr,
91) -> Result<(), Error> {
92    let simple_box_selector_out =
93        mut_ptr_as_mut(simple_box_selector_out, "simple_box_selector_out")?;
94    *simple_box_selector_out = Box::into_raw(Box::new(SimpleBoxSelector(
95        wallet::box_selector::SimpleBoxSelector::new(),
96    )));
97    Ok(())
98}
99
100/// Selects inputs to satisfy target balance and tokens.
101/// `inputs` - available inputs (returns an error, if empty),
102/// `target_balance` - coins (in nanoERGs) needed,
103/// `target_tokens` - amount of tokens needed.
104/// Returns selected inputs and box assets(value+tokens) with change.
105pub unsafe fn simple_box_selector_select(
106    simple_box_selector_ptr: ConstSimpleBoxSelectorPtr,
107    inputs_ptr: ConstCollectionPtr<ErgoBox>,
108    target_balance_ptr: ConstBoxValuePtr,
109    target_tokens_ptr: ConstCollectionPtr<Token>,
110    box_selection_out: *mut BoxSelectionPtr,
111) -> Result<(), Error> {
112    let inputs = const_ptr_as_ref(inputs_ptr, "inputs_ptr")?;
113    let target_balance = const_ptr_as_ref(target_balance_ptr, "target_balance_ptr")?;
114    let target_tokens = const_ptr_as_ref(target_tokens_ptr, "target_tokens_ptr")?;
115    let simple_box_selector = const_ptr_as_ref(simple_box_selector_ptr, "simple_box_selector_ptr")?;
116    let box_selection_out = mut_ptr_as_mut(box_selection_out, "box_selection_out")?;
117    let box_selection = simple_box_selector.0.select(
118        inputs.0.clone().into_iter().map(|b| b.0).collect(),
119        target_balance.0,
120        target_tokens
121            .0
122            .clone()
123            .into_iter()
124            .map(|b| b.0)
125            .collect::<Vec<ergo_lib::ergotree_ir::chain::token::Token>>()
126            .as_slice(),
127    )?;
128    *box_selection_out = Box::into_raw(Box::new(BoxSelection(box_selection)));
129    Ok(())
130}