iota_client/api/
consolidation.rs1use crate::{
5 api::message_builder::ClientMessageBuilder,
6 node::{OutputType, OutputsOptions},
7 Client, Result,
8};
9use bee_message::constants::INPUT_OUTPUT_COUNT_MAX;
10use crypto::keys::slip10::Seed;
11use std::ops::Range;
12
13pub async fn consolidate_funds(
16 client: &Client,
17 seed: &Seed,
18 account_index: usize,
19 address_range: Range<usize>,
20) -> Result<String> {
21 let addresses = client
22 .get_addresses(seed)
23 .with_account_index(account_index)
24 .with_range(address_range.clone())
25 .finish()
26 .await?;
27 let consolidation_address = addresses[0].clone();
28
29 let mut last_transfer_index = address_range.start;
30 let offset = address_range.start;
31 'consolidation: loop {
32 let mut message_ids = Vec::new();
33 for (index, address) in addresses.iter().enumerate().rev() {
35 let index = index + offset;
37 let signature_locked_outputs = client
41 .get_address()
42 .outputs(
43 address,
44 OutputsOptions {
45 include_spent: false,
46 output_type: Some(OutputType::SignatureLockedSingle),
47 },
48 )
49 .await?;
50 let dust_allowance_outputs = client
51 .get_address()
52 .outputs(
53 address,
54 OutputsOptions {
55 include_spent: false,
56 output_type: Some(OutputType::SignatureLockedDustAllowance),
57 },
58 )
59 .await?;
60
61 let mut output_with_metadata = Vec::new();
62
63 for out in signature_locked_outputs.iter().chain(dust_allowance_outputs.iter()) {
64 let output_metadata = client.get_output(out).await?;
65 let (amount, _output_address, _check_treshold) =
66 ClientMessageBuilder::get_output_amount_and_address(&output_metadata.output)?;
67 output_with_metadata.push((out.clone(), amount));
68 }
69
70 if !output_with_metadata.is_empty() {
71 if last_transfer_index == index {
73 if output_with_metadata.len() < 2 {
74 break 'consolidation;
75 }
76 } else {
77 last_transfer_index = index;
78 }
79 }
80
81 let outputs_chunks = output_with_metadata.chunks(INPUT_OUTPUT_COUNT_MAX);
82
83 for chunk in outputs_chunks {
84 let mut message_builder = client.message().with_seed(seed);
85 let mut total_amount = 0;
86 for (input, amount) in chunk {
87 message_builder = message_builder.with_input(input.clone());
88 total_amount += amount;
89 }
90
91 let message = message_builder
92 .with_input_range(index..index + 1)
93 .with_output(&consolidation_address, total_amount)?
94 .with_initial_address_index(0)
95 .finish()
96 .await?;
97 message_ids.push(message.id().0);
98 }
99 }
100
101 if message_ids.is_empty() {
102 break 'consolidation;
103 }
104 for message_id in message_ids {
106 let _ = client.retry_until_included(&message_id, None, None).await?;
107 }
108 }
109 Ok(consolidation_address)
110}