kabu_types_entities/
swap_step.rs

1use std::fmt::{Display, Formatter};
2use std::sync::Arc;
3
4use alloy_primitives::{I256, U256};
5use eyre::{eyre, Result};
6use tracing::error;
7
8use crate::{PoolWrapper, SwapAmountType, SwapLine, Token};
9use alloy_primitives::Address;
10use kabu_evm_db::KabuDBError;
11use revm::DatabaseRef;
12
13#[derive(Clone, Debug)]
14pub struct SwapStep {
15    swap_line_vec: Vec<SwapLine>,
16    swap_from: Option<Address>,
17    swap_to: Address,
18}
19
20impl Display for SwapStep {
21    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
22        let paths = self.swap_line_vec.iter().map(|path| format!("{path}")).collect::<Vec<String>>().join(" / ");
23        write!(f, "{paths}")
24    }
25}
26
27impl SwapStep {
28    pub fn new(swap_to: Address) -> Self {
29        Self { swap_line_vec: Vec::new(), swap_to, swap_from: None }
30    }
31
32    pub fn get_mut_swap_line_by_index(&mut self, idx: usize) -> &mut SwapLine {
33        &mut self.swap_line_vec[idx]
34    }
35
36    pub fn swap_line_vec(&self) -> &Vec<SwapLine> {
37        &self.swap_line_vec
38    }
39
40    pub fn len(&self) -> usize {
41        self.swap_line_vec.len()
42    }
43
44    pub fn is_empty(&self) -> bool {
45        self.swap_line_vec.is_empty()
46    }
47
48    fn first_swap_line(&self) -> Option<&SwapLine> {
49        self.swap_line_vec.first()
50    }
51
52    pub fn first_token(&self) -> Option<&Arc<Token>> {
53        match self.first_swap_line() {
54            Some(s) => s.get_first_token(),
55            None => None,
56        }
57    }
58
59    pub fn last_token(&self) -> Option<&Arc<Token>> {
60        match self.first_swap_line() {
61            Some(s) => s.get_last_token(),
62            None => None,
63        }
64    }
65
66    pub fn add(&mut self, swap_path: SwapLine) -> &mut Self {
67        if self.is_empty()
68            || ((self.first_token().unwrap() == swap_path.get_first_token().unwrap())
69                && (self.last_token().unwrap() == swap_path.get_last_token().unwrap()))
70        {
71            self.swap_line_vec.push(swap_path);
72        } else {
73            error!(
74                "cannot add SwapPath {} != {} {} !=  {}",
75                self.first_token().unwrap().get_address(),
76                swap_path.get_first_token().unwrap().get_address(),
77                self.last_token().unwrap().get_address(),
78                swap_path.get_last_token().unwrap().get_address()
79            )
80        }
81        self
82    }
83
84    pub fn can_flash_swap(&self) -> bool {
85        for swap_line in self.swap_line_vec.iter() {
86            for pool in swap_line.pools().iter() {
87                if !pool.can_flash_swap() {
88                    return false;
89                }
90            }
91        }
92        true
93    }
94
95    pub fn can_calculate_in_amount(&self) -> bool {
96        for swap_line in self.swap_line_vec.iter() {
97            for pool in swap_line.pools().iter() {
98                if !pool.can_calculate_in_amount() {
99                    return false;
100                }
101            }
102        }
103        true
104    }
105
106    pub fn get_pools(&self) -> Vec<PoolWrapper> {
107        self.swap_line_vec.iter().flat_map(|sp| sp.pools().clone()).collect()
108    }
109
110    fn common_pools(swap_path_0: &SwapLine, swap_path_1: &SwapLine) -> usize {
111        let mut ret = 0;
112        for pool in swap_path_0.pools().iter() {
113            if swap_path_1.pools().contains(pool) {
114                ret += 1;
115            }
116        }
117        ret
118    }
119
120    pub fn merge_swap_paths(swap_path_0: SwapLine, swap_path_1: SwapLine, multicaller: Address) -> Result<(SwapStep, SwapStep)> {
121        let mut split_index_start = 0;
122        let mut split_index_end = 0;
123
124        if swap_path_0.get_first_token().unwrap() != swap_path_1.get_first_token().unwrap()
125            || swap_path_0.get_last_token().unwrap() != swap_path_1.get_last_token().unwrap()
126        {
127            return Err(eyre!("CANNOT_MERGE_DIFFERENT_TOKENS"));
128        }
129
130        for i in 0..swap_path_0.pools().len() {
131            if i >= swap_path_1.pools().len() {
132                break;
133            }
134            let pool_0 = &swap_path_0.pools()[i];
135            let pool_1 = &swap_path_1.pools()[i];
136
137            let token_0 = &swap_path_0.tokens()[i + 1];
138            let token_1 = &swap_path_1.tokens()[i + 1];
139
140            if pool_0 == pool_1 && token_0 == token_1 {
141                split_index_start += 1;
142            } else {
143                break;
144            }
145        }
146
147        for i in 0..swap_path_0.pools().len() {
148            if i >= swap_path_1.pools().len() {
149                break;
150            }
151            let pool_0 = &swap_path_0.pools()[swap_path_0.pools().len() - 1 - i];
152            let pool_1 = &swap_path_1.pools()[swap_path_1.pools().len() - 1 - i];
153
154            let token_0 = &swap_path_0.tokens()[swap_path_0.tokens().len() - 2 - i];
155            let token_1 = &swap_path_1.tokens()[swap_path_1.tokens().len() - 2 - i];
156
157            if pool_0 == pool_1 && token_0 == token_1 {
158                split_index_end += 1;
159            } else {
160                break;
161            }
162        }
163
164        if split_index_start > 0 && split_index_end > 0 {
165            return Err(eyre!("CANNOT_MERGE_BOTH_SIDES"));
166        }
167
168        let common_pools_count = Self::common_pools(&swap_path_0, &swap_path_1);
169        if (split_index_start > 0 && split_index_start != common_pools_count)
170            || (split_index_end > 0 && split_index_end != common_pools_count)
171        {
172            return Err(eyre!("MORE_COMMON_POOLS"));
173        }
174
175        if split_index_start > 0 {
176            let (mut split_0_0, mut split_0_1) = swap_path_0.split(split_index_start)?;
177            let (split_1_0, mut split_1_1) = swap_path_1.split(split_index_start)?;
178
179            let mut swap_step_0 = SwapStep::new(multicaller);
180            let mut swap_step_1 = SwapStep::new(multicaller);
181
182            if let SwapAmountType::Set(a0) = swap_path_0.amount_in {
183                if let SwapAmountType::Set(a1) = swap_path_1.amount_in {
184                    split_0_0.amount_in = SwapAmountType::Set(a0.max(a1) >> 1);
185                }
186            }
187
188            if let SwapAmountType::Set(a0) = swap_path_0.amount_out {
189                if let SwapAmountType::Set(a1) = swap_path_1.amount_out {
190                    split_0_1.amount_out = SwapAmountType::Set((a0.max(a1) * a0 / (a0 + a1)) >> 1);
191                    split_1_1.amount_out = SwapAmountType::Set((a0.max(a1) * a1 / (a0 + a1)) >> 1);
192                }
193            }
194
195            swap_step_0.add(split_0_0);
196
197            swap_step_1.add(split_0_1);
198            swap_step_1.add(split_1_1);
199
200            return Ok((swap_step_0, swap_step_1));
201        }
202
203        if split_index_end > 0 {
204            let (mut split_0_0, mut split_0_1) = swap_path_0.split(swap_path_0.pools().len() - split_index_end)?;
205            let (mut split_1_0, split_1_1) = swap_path_1.split(swap_path_1.pools().len() - split_index_end)?;
206
207            let mut swap_step_0 = SwapStep::new(multicaller);
208            let mut swap_step_1 = SwapStep::new(multicaller);
209
210            if let SwapAmountType::Set(a0) = swap_path_0.amount_out {
211                if let SwapAmountType::Set(a1) = swap_path_1.amount_out {
212                    split_0_1.amount_out = SwapAmountType::Set(a0.max(a1) >> 1);
213                }
214            }
215
216            /*
217            if let SwapAmountType::Set(a0) = swap_path_0.amount_in {
218                if let SwapAmountType::Set(a1) = swap_path_1.amount_in {
219                    split_0_1.amount_in = SwapAmountType::Set(a0.max(a1))
220                }
221            }
222
223             */
224
225            if let SwapAmountType::Set(a0) = swap_path_0.amount_in {
226                if let SwapAmountType::Set(a1) = swap_path_1.amount_in {
227                    split_0_0.amount_in = SwapAmountType::Set((a0.max(a1) * a0 / (a0 + a1)) >> 1);
228                    split_1_0.amount_in = SwapAmountType::Set((a0.max(a1) * a1 / (a0 + a1)) >> 1);
229                }
230            }
231
232            /*
233            if let SwapAmountType::Set(a0) = swap_path_0.amount_out {
234                if let SwapAmountType::Set(a1) = swap_path_1.amount_out {
235                    split_0_0.amount_out = SwapAmountType::Set(a0 );
236                    split_1_0.amount_out = SwapAmountType::Set(a1 );
237                }
238            }
239
240             */
241
242            swap_step_0.add(split_0_0);
243            swap_step_0.add(split_1_0);
244
245            swap_step_1.add(split_0_1);
246
247            return Ok((swap_step_0, swap_step_1));
248        }
249
250        Err(eyre!("CANNOT_MERGE"))
251    }
252
253    pub fn get_first_token_address(&self) -> Option<Address> {
254        let mut ret: Option<Address> = None;
255        for sp in self.swap_line_vec.iter() {
256            match sp.get_first_token() {
257                Some(token) => match ret {
258                    Some(a) => {
259                        if a != token.get_address() {
260                            return None;
261                        }
262                    }
263                    None => {
264                        ret = Some(token.get_address());
265                    }
266                },
267                _ => {
268                    return None;
269                }
270            }
271        }
272        ret
273    }
274
275    pub fn get_first_pool(&self) -> Option<&PoolWrapper> {
276        if self.swap_line_vec.len() == 1 {
277            self.swap_line_vec.first().and_then(|x| x.path.pools.first())
278        } else {
279            None
280        }
281    }
282
283    pub fn get_last_pool(&self) -> Option<&PoolWrapper> {
284        if self.swap_line_vec.len() == 1 {
285            self.swap_line_vec.first().and_then(|x| x.path.pools.last())
286        } else {
287            None
288        }
289    }
290
291    pub fn get_first_token(&self) -> Option<&Arc<Token>> {
292        let mut ret: Option<&Arc<Token>> = None;
293        for sp in self.swap_line_vec.iter() {
294            match sp.get_first_token() {
295                Some(token) => match &ret {
296                    Some(a) => {
297                        if a.get_address() != token.get_address() {
298                            return None;
299                        }
300                    }
301                    None => {
302                        ret = Some(token);
303                    }
304                },
305                _ => {
306                    return None;
307                }
308            }
309        }
310        ret
311    }
312
313    pub fn get_in_amount(&self) -> Result<U256> {
314        let mut in_amount = U256::ZERO;
315        for swap_path in self.swap_line_vec.iter() {
316            match swap_path.amount_in {
317                SwapAmountType::Set(amount) => in_amount += amount,
318                _ => return Err(eyre!("IN_AMOUNT_NOT_SET")),
319            }
320        }
321        Ok(in_amount)
322    }
323
324    pub fn get_out_amount(&self) -> Result<U256> {
325        let mut out_amount = U256::ZERO;
326        for swap_path in self.swap_line_vec.iter() {
327            match swap_path.amount_out {
328                SwapAmountType::Set(amount) => out_amount += amount,
329                _ => return Err(eyre!("IN_AMOUNT_NOT_SET")),
330            }
331        }
332        Ok(out_amount)
333    }
334
335    pub fn calculate_with_in_amount<DB: DatabaseRef<Error = KabuDBError>>(
336        &mut self,
337        db: &DB,
338        in_ammount: Option<U256>,
339    ) -> Result<(U256, u64)> {
340        let mut out_amount = U256::ZERO;
341        let mut gas_used = 0;
342
343        for swap_path in self.swap_line_vec.iter_mut() {
344            let cur_in_amount = match in_ammount {
345                Some(amount) => amount,
346                None => match swap_path.amount_in {
347                    SwapAmountType::Set(amount) => amount,
348                    _ => {
349                        return Err(eyre!("IN_AMOUNT_NOT_SET"));
350                    }
351                },
352            };
353            swap_path.amount_in = SwapAmountType::Set(cur_in_amount);
354
355            match swap_path.calculate_with_in_amount(db, cur_in_amount) {
356                Ok((amount, gas, calculation_results)) => {
357                    out_amount += amount;
358                    swap_path.amount_out = SwapAmountType::Set(amount);
359                    gas_used += gas;
360                }
361                _ => {
362                    return Err(eyre!("ERROR_CALCULATING_OUT_AMOUNT"));
363                }
364            }
365        }
366        Ok((out_amount, gas_used))
367    }
368
369    pub fn calculate_with_out_amount<DB: DatabaseRef<Error = KabuDBError>>(
370        &mut self,
371        db: &DB,
372        out_amount: Option<U256>,
373    ) -> Result<(U256, u64)> {
374        let mut in_amount = U256::ZERO;
375        let mut gas_used = 0;
376
377        for swap_path in self.swap_line_vec.iter_mut() {
378            let cur_out_amount = match out_amount {
379                Some(amount) => amount,
380                None => match swap_path.amount_out {
381                    SwapAmountType::Set(amount) => amount,
382                    _ => {
383                        return Err(eyre!("IN_AMOUNT_NOT_SET"));
384                    }
385                },
386            };
387
388            swap_path.amount_out = SwapAmountType::Set(cur_out_amount);
389
390            match swap_path.calculate_with_out_amount(db, cur_out_amount) {
391                Ok((amount, gas, calculation_results)) => {
392                    in_amount += amount;
393                    gas_used += gas;
394                    swap_path.amount_in = SwapAmountType::Set(amount);
395                }
396                _ => {
397                    return Err(eyre!("ERROR_CALCULATING_OUT_AMOUNT"));
398                }
399            }
400        }
401        Ok((in_amount, gas_used))
402    }
403
404    /*
405
406    fn optimize_swap_step_in_amount_provided(&mut self, state: &dyn DatabaseRef<Error=Infallible>, env: Env, step : I256, ) -> Result<Self> {
407        let best_idx = Option<usize>;
408        let best_out_amount = Option<usize>;
409        let cu_out_amount = self.get_out_amount().unwrap_or(U256::zero());
410
411        for (idx, swap_path) in self.swap_path_vec.iter_mut().enumerate() {
412            match swap_path.amount_in {
413                InAmountType::Set(amount) {
414                    swap_path.calculate_swap_path_in_amount_provided(state, env.clone(), )
415                }
416                _=>{ return Err(eyre!("IN_AMOUNT_NOT_SET"))}
417
418            }
419        }
420
421
422    }*/
423
424    pub fn arb_result(swap_step_0: &SwapStep, swap_step_1: &SwapStep) -> I256 {
425        let in_amount: I256 = I256::try_from(swap_step_0.get_in_amount().unwrap_or(U256::MAX)).unwrap_or(I256::MAX);
426        let out_amount: I256 = I256::try_from(swap_step_1.get_out_amount().unwrap_or(U256::ZERO)).unwrap_or(I256::ZERO);
427        if in_amount.is_negative() {
428            I256::MIN
429        } else {
430            out_amount - in_amount
431        }
432    }
433
434    pub fn arb_profit(swap_step_0: &SwapStep, swap_step_1: &SwapStep) -> U256 {
435        let in_amount: U256 = swap_step_0.get_in_amount().unwrap_or(U256::MAX);
436        let out_amount: U256 = swap_step_1.get_out_amount().unwrap_or(U256::ZERO);
437        if in_amount >= out_amount {
438            U256::ZERO
439        } else {
440            out_amount - in_amount
441        }
442    }
443
444    pub fn arb_profit_eth(swap_step_0: &SwapStep, swap_step_1: &SwapStep) -> U256 {
445        match swap_step_0.get_first_token() {
446            Some(t) => {
447                let profit = Self::arb_profit(swap_step_0, swap_step_1);
448                t.calc_eth_value(profit).unwrap_or_default()
449            }
450            _ => U256::ZERO,
451        }
452    }
453
454    pub fn optimize_swap_steps<DB: DatabaseRef<Error = KabuDBError>>(
455        db: &DB,
456        swap_step_0: &SwapStep,
457        swap_step_1: &SwapStep,
458        middle_amount: Option<U256>,
459    ) -> Result<(SwapStep, SwapStep)> {
460        if swap_step_0.can_calculate_in_amount() {
461            SwapStep::optimize_with_middle_amount(db, swap_step_0, swap_step_1, middle_amount)
462        } else {
463            SwapStep::optimize_with_in_amount(db, swap_step_0, swap_step_1, middle_amount)
464        }
465    }
466
467    pub fn optimize_with_middle_amount<DB: DatabaseRef<Error = KabuDBError>>(
468        db: &DB,
469        swap_step_0: &SwapStep,
470        swap_step_1: &SwapStep,
471        middle_amount: Option<U256>,
472    ) -> Result<(SwapStep, SwapStep)> {
473        let mut step_0 = swap_step_0.clone();
474        let mut step_1 = swap_step_1.clone();
475        let mut best_profit: Option<I256> = None;
476
477        let (middle_amount, _) = match middle_amount {
478            Some(amount) => step_0.calculate_with_in_amount(db, Some(amount))?,
479            _ => step_0.calculate_with_in_amount(db, None)?,
480        };
481
482        let step_0_out_amount = step_0.get_out_amount()?;
483        let step_1_out_amount = step_1.get_out_amount()?;
484
485        for swap_path_1 in step_1.swap_line_vec.iter_mut() {
486            let in_amount = step_0_out_amount * swap_path_1.amount_out.unwrap() / step_1_out_amount;
487            swap_path_1.amount_in = SwapAmountType::Set(in_amount);
488        }
489
490        step_1.calculate_with_in_amount(db, None);
491
492        let cur_profit = Self::arb_result(&step_0, &step_1);
493        if cur_profit.is_positive() {
494            best_profit = Some(cur_profit);
495        }
496
497        //if step_0.get_in_amount()? > step_1.get_out_amount()? {
498        //    return Ok((step_0, step_1))
499        //}
500
501        //let step_0_in_amount = step_0.get_in_amount().unwrap_or(U256::max_value());
502        //let step_1_out_amount = step_1.get_out_amount().unwrap_or(U256::zero());
503
504        let denominator = U256::from(10000);
505        let step_multiplier = U256::from(500);
506
507        let mut step_0_calc = step_0.clone();
508        let mut step_1_calc = step_1.clone();
509
510        let mut counter = 0;
511
512        let step = middle_amount * step_multiplier / denominator;
513
514        loop {
515            counter += 1;
516            if counter > 30 {
517                return if Self::arb_result(&step_0, &step_1).is_positive() { Ok((step_0, step_1)) } else { Err(eyre!("TOO_MANY_STEPS")) };
518            }
519
520            let step0in = step_0.get_in_amount()?;
521            let step0out = step_0.get_out_amount()?;
522            let step1in = step_1.get_in_amount()?;
523            let step1out = step_1.get_out_amount()?;
524            let profit = Self::arb_result(&step_0, &step_1);
525
526            //debug!("middle_amount Steps :  {} in {} out {} in {} out {} profit {}", counter, step0in, step0out, step1in, step1out, profit);
527
528            for (i, swap_path_0_calc) in step_0_calc.swap_line_vec.iter_mut().enumerate() {
529                let amount_out = step_0.swap_line_vec[i].amount_out.unwrap();
530
531                if amount_out <= step {
532                    return Ok((step_0, step_1));
533                }
534
535                let new_out_amount = amount_out.checked_add(step);
536                match new_out_amount {
537                    Some(new_out_amount) => {
538                        if swap_path_0_calc.amount_out.unwrap() != new_out_amount {
539                            let new_amount_out = amount_out + step;
540                            let (in_amount, gas, calculation_results) =
541                                swap_path_0_calc.calculate_with_out_amount(db, new_amount_out).unwrap_or((U256::MAX, 0, vec![]));
542                            swap_path_0_calc.amount_in = SwapAmountType::Set(in_amount);
543                            swap_path_0_calc.amount_out = SwapAmountType::Set(new_amount_out);
544                            swap_path_0_calc.gas_used = Some(gas);
545                            swap_path_0_calc.calculation_results = calculation_results;
546                        }
547                    }
548                    None => {
549                        swap_path_0_calc.amount_in = SwapAmountType::Set(U256::MAX);
550                    }
551                }
552            }
553
554            for (i, swap_path_1_calc) in step_1_calc.swap_line_vec.iter_mut().enumerate() {
555                let amount_in = step_1.swap_line_vec[i].amount_in.unwrap();
556
557                if amount_in <= step || amount_in == U256::MAX {
558                    return Ok((step_0, step_1));
559                }
560
561                let new_amount_in = amount_in.checked_add(step);
562
563                match new_amount_in {
564                    Some(new_amount_in) => {
565                        if swap_path_1_calc.amount_in.unwrap() != new_amount_in {
566                            let (out_amount, gas, calculation_results) =
567                                swap_path_1_calc.calculate_with_in_amount(db, new_amount_in).unwrap_or((U256::ZERO, 0, vec![]));
568                            swap_path_1_calc.amount_out = SwapAmountType::Set(out_amount);
569                            swap_path_1_calc.amount_in = SwapAmountType::Set(new_amount_in);
570                            swap_path_1_calc.gas_used = Some(gas);
571                        }
572                    }
573                    None => {
574                        swap_path_1_calc.amount_out = SwapAmountType::Set(U256::ZERO);
575                    }
576                }
577            }
578
579            let mut best_merged_step_0: Option<SwapStep> = None;
580
581            for i in 0..step_0.swap_line_vec.len() {
582                let mut merged_step_0 = SwapStep::new(step_0.swap_to);
583                for ci in 0..step_0.swap_line_vec.len() {
584                    merged_step_0.add(if ci == i { step_0_calc.swap_line_vec[ci].clone() } else { step_0.swap_line_vec[ci].clone() });
585                }
586                if best_merged_step_0.is_none() || best_merged_step_0.clone().unwrap().get_in_amount()? > merged_step_0.get_in_amount()? {
587                    best_merged_step_0 = Some(merged_step_0);
588                }
589            }
590
591            let mut best_merged_step_1: Option<SwapStep> = None;
592
593            for i in 0..step_1.swap_line_vec.len() {
594                let mut merged_step_1 = SwapStep::new(step_1.swap_to);
595                for ci in 0..step_1.swap_line_vec.len() {
596                    merged_step_1.add(if ci == i { step_1_calc.swap_line_vec[ci].clone() } else { step_1.swap_line_vec[ci].clone() });
597                }
598                if best_merged_step_1.is_none() || best_merged_step_1.clone().unwrap().get_out_amount()? < merged_step_1.get_out_amount()? {
599                    best_merged_step_1 = Some(merged_step_1);
600                }
601            }
602
603            //let new_middle_amount = middle_amount - step;
604
605            if best_merged_step_0.is_none() || best_merged_step_1.is_none() {
606                //debug!("optimize_swap_steps_middle_amount {} {}", counter, Self::profit(&step_0, &step_1)  );
607                return if Self::arb_result(&step_0, &step_1).is_positive() {
608                    Ok((step_0, step_1))
609                } else {
610                    Err(eyre!("CANNOT_OPTIMIZE_SWAP_STEP"))
611                };
612            }
613
614            let best_merged_step_0 = best_merged_step_0.unwrap();
615            let best_merged_step_1 = best_merged_step_1.unwrap();
616
617            let cur_profit = Self::arb_result(&best_merged_step_0, &best_merged_step_1);
618
619            if best_profit.is_none() || best_profit.unwrap() < cur_profit {
620                step_0 = best_merged_step_0;
621                step_1 = best_merged_step_1;
622                best_profit = Some(cur_profit);
623            } else {
624                //debug!("optimize_swap_steps_middle_amount {} {} {}", counter, Self::profit(&step_0, &step_1), Self::profit(&best_merged_step_0, &best_merged_step_1)  );
625                return if Self::arb_result(&step_0, &step_1).is_positive() {
626                    Ok((step_0, step_1))
627                } else {
628                    Err(eyre!("CANNOT_OPTIMIZE_SWAP_STEP"))
629                };
630            }
631        }
632    }
633
634    pub fn optimize_with_in_amount<DB: DatabaseRef<Error = KabuDBError>>(
635        db: &DB,
636        swap_step_0: &SwapStep,
637        swap_step_1: &SwapStep,
638        in_amount: Option<U256>,
639    ) -> Result<(SwapStep, SwapStep)> {
640        let mut step_0 = swap_step_0.clone();
641        let mut step_1 = swap_step_1.clone();
642        let mut best_profit: Option<I256> = None;
643
644        match in_amount {
645            Some(amount) => step_0.calculate_with_in_amount(db, Some(amount))?,
646            _ => step_0.calculate_with_in_amount(db, None)?,
647        };
648        let in_amount = step_0.get_in_amount()?;
649
650        let step_0_out_amount = step_0.get_out_amount()?;
651        let step_1_out_amount = step_1.get_out_amount()?;
652
653        for swap_path_1 in step_1.swap_line_vec.iter_mut() {
654            let in_amount = step_0_out_amount * swap_path_1.amount_out.unwrap() / step_1_out_amount;
655            swap_path_1.amount_in = SwapAmountType::Set(in_amount);
656        }
657        let _ = step_1.calculate_with_in_amount(db, None)?;
658
659        //debug!("AfterCalc SwapStep0 {:?}", step_0);
660        //debug!("AfterCalc SwapStep1 {:?}", step_1);
661
662        let cur_profit = Self::arb_result(&step_0, &step_1);
663        if cur_profit.is_positive() {
664            best_profit = Some(cur_profit);
665        }
666
667        /*if step_0.get_in_amount()? > step_1.get_out_amount()? {
668            return Ok((step_0, step_1))
669        }
670         */
671
672        let step_0_in_amount = step_0.get_in_amount().unwrap_or(U256::MAX);
673        let step_1_out_amount = step_1.get_out_amount().unwrap_or(U256::ZERO);
674
675        let denominator = U256::from(10000);
676        let step_multiplier = U256::from(500);
677
678        let mut step_0_calc = step_0.clone();
679        let mut step_1_calc = step_1.clone();
680
681        let mut counter = 0;
682
683        let step = in_amount * step_multiplier / denominator;
684
685        loop {
686            counter += 1;
687            if counter > 30 {
688                return if Self::arb_result(&step_0, &step_1).is_positive() { Ok((step_0, step_1)) } else { Err(eyre!("TOO_MANY_STEPS")) };
689            }
690
691            let step0in = step_0.get_in_amount()?;
692            let step0out = step_0.get_out_amount()?;
693            let step1in = step_1.get_in_amount()?;
694            let step1out = step_1.get_out_amount()?;
695            let profit = Self::arb_result(&step_0, &step_1);
696
697            //debug!("in_amount Steps :  {} in {} out {} in {} out {} profit {}", counter, step0in, step0out, step1in, step1out, profit);
698
699            for (i, swap_path_0_calc) in step_0_calc.swap_line_vec.iter_mut().enumerate() {
700                if step_0.swap_line_vec[i].amount_in.unwrap() > step
701                    && swap_path_0_calc.amount_in.unwrap() != step_0.swap_line_vec[i].amount_in.unwrap() - step
702                {
703                    let new_amount_in = step_0.swap_line_vec[i].amount_in.unwrap() + step;
704                    let (amount_out, gas, calculation_results) =
705                        swap_path_0_calc.calculate_with_in_amount(db, new_amount_in).unwrap_or((U256::ZERO, 0, vec![]));
706                    swap_path_0_calc.amount_in = SwapAmountType::Set(new_amount_in);
707                    swap_path_0_calc.amount_out = SwapAmountType::Set(amount_out);
708                    swap_path_0_calc.gas_used = Some(gas);
709                    swap_path_0_calc.calculation_results = calculation_results;
710                }
711            }
712
713            let mut best_merged_step_0: Option<SwapStep> = None;
714
715            for i in 0..step_0.swap_line_vec.len() {
716                let mut merged_step_0 = SwapStep::new(step_0.swap_to);
717                for ci in 0..step_0.swap_line_vec.len() {
718                    merged_step_0.add(if ci == i { step_0_calc.swap_line_vec[ci].clone() } else { step_0.swap_line_vec[ci].clone() });
719                }
720                if step_0.get_in_amount()? < step || merged_step_0.get_in_amount()? != step_0.get_in_amount()? + step {
721                    //error!("{:?} {} {:?}", step_0.get_in_amount(), step , merged_step_0.get_in_amount() );
722                    continue;
723                }
724
725                if best_merged_step_0.is_none() || best_merged_step_0.clone().unwrap().get_out_amount()? < merged_step_0.get_out_amount()? {
726                    best_merged_step_0 = Some(merged_step_0);
727                }
728            }
729
730            if best_merged_step_0.is_none() {
731                //error!("optimize_swap_steps_in_amount best merged step is None {}", counter );
732                break;
733            };
734
735            let middle_amount_step = best_merged_step_0.clone().unwrap().get_out_amount()? - step_1.get_in_amount()?;
736
737            for (i, swap_path_1_calc) in step_1_calc.swap_line_vec.iter_mut().enumerate() {
738                if step_1.swap_line_vec[i].amount_in.unwrap() > middle_amount_step
739                    && swap_path_1_calc.amount_in.unwrap() != step_1.swap_line_vec[i].amount_in.unwrap() - middle_amount_step
740                {
741                    let new_amount_in = step_1.swap_line_vec[i].amount_in.unwrap() + middle_amount_step;
742                    let (out_amount, gas, calculation_results) =
743                        swap_path_1_calc.calculate_with_in_amount(db, new_amount_in).unwrap_or_default();
744                    swap_path_1_calc.amount_out = SwapAmountType::Set(out_amount);
745                    swap_path_1_calc.amount_in = SwapAmountType::Set(new_amount_in);
746                    swap_path_1_calc.gas_used = Some(gas);
747                    swap_path_1_calc.calculation_results = calculation_results;
748                }
749            }
750
751            let mut best_merged_step_1: Option<SwapStep> = None;
752
753            for i in 0..step_1.swap_line_vec.len() {
754                let mut merged_step_1 = SwapStep::new(step_1.swap_to);
755                for ci in 0..step_1.swap_line_vec.len() {
756                    merged_step_1.add(if ci == i { step_1_calc.swap_line_vec[ci].clone() } else { step_1.swap_line_vec[ci].clone() });
757                }
758                if merged_step_1.get_in_amount()? != best_merged_step_0.clone().unwrap().get_out_amount()? {
759                    continue;
760                }
761
762                if best_merged_step_1.is_none() || best_merged_step_1.clone().unwrap().get_out_amount()? < merged_step_1.get_out_amount()? {
763                    best_merged_step_1 = Some(merged_step_1);
764                }
765            }
766
767            //let new_in_amount = middle_amount - step;
768
769            if best_merged_step_0.is_none() || best_merged_step_1.is_none() {
770                //debug!("optimize_swap_steps_in_amount {} {}", counter, Self::profit(&step_0, &step_1)  );
771
772                return if Self::arb_result(&step_0, &step_1).is_positive() {
773                    Ok((step_0, step_1))
774                } else {
775                    //continue
776                    Err(eyre!("CANNOT_OPTIMIZE_SWAP_STEP"))
777                };
778            }
779            let best_merged_step_0 = best_merged_step_0.unwrap();
780            let best_merged_step_1 = best_merged_step_1.unwrap();
781
782            let cur_profit = Self::arb_result(&best_merged_step_0, &best_merged_step_1);
783
784            if best_profit.is_none() || best_profit.unwrap() < cur_profit {
785                step_0 = best_merged_step_0;
786                step_1 = best_merged_step_1;
787                best_profit = Some(cur_profit);
788            } else {
789                //debug!("optimize_swap_steps_in_amount {} {} {}", counter, Self::profit(&step_0, &step_1), Self::profit(&best_merged_step_0, &best_merged_step_1)  );
790
791                return if Self::arb_result(&step_0, &step_1).is_positive() {
792                    Ok((step_0, step_1))
793                } else {
794                    Err(eyre!("CANNOT_OPTIMIZE_SWAP_STEP"))
795                };
796            }
797        }
798
799        if Self::arb_result(&step_0, &step_1).is_positive() {
800            Ok((step_0, step_1))
801        } else {
802            Err(eyre!("OPTIMIZATION_FAILED"))
803        }
804    }
805}