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