@@ -8,6 +8,7 @@ use std::{collections::HashMap, sync::Arc};
88
99use color_eyre:: eyre:: { self , Context , eyre} ;
1010use num_bigint:: BigUint ;
11+ use num_traits:: Zero ;
1112use tracing:: { debug, error, instrument, trace, warn} ;
1213use tycho_common:: models:: token:: Token ;
1314use tycho_simulation:: {
@@ -345,45 +346,64 @@ impl CrossChainSingleHop {
345346 fast_height : u64 ,
346347 fast_inventory : & BigUint ,
347348 ) -> Option < signals:: CrossChainSingleHop > {
349+ if slow_sims. is_empty ( ) {
350+ trace ! ( "no slow sims provided for binary search; cannot find optimal signal" ) ;
351+ return None ;
352+ }
348353 let ( mut left, mut right) = ( 0 , slow_sims. len ( ) - 1 ) ;
349354
350- let mut best_signal: Option < signals:: CrossChainSingleHop > = None ;
351-
352355 while left < right {
353- let mid = ( right + left) / 2 ;
354-
355- // make sims for mid
356- let mid_signal = match self . try_signal_from_precompute (
357- slow_sims[ mid] . clone ( ) ,
358- slow_protocol_component. clone ( ) ,
359- slow_pool_id,
360- slow_height,
361- slow_prices_a_b,
362- slow_prices_a_usdc,
363- slow_prices_b_usdc,
364- fast_state,
365- fast_protocol_component. clone ( ) ,
366- fast_pool_id,
367- fast_height,
368- fast_inventory,
369- ) {
370- Ok ( signal) => signal,
371- Err ( err) => {
372- trace ! ( index = mid, err = %err, "failed to make mid signal, searching over smaller values" ) ;
373- right = mid - 1 ;
374- continue ;
375- }
376- } ;
356+ let mid = left + ( right - left) / 2 ;
357+ let mid_profit_usdc = self
358+ . get_profit_and_signal (
359+ mid,
360+ slow_sims,
361+ slow_protocol_component. clone ( ) ,
362+ slow_pool_id,
363+ slow_height,
364+ slow_prices_a_b,
365+ slow_prices_a_usdc,
366+ slow_prices_b_usdc,
367+ fast_state,
368+ fast_protocol_component. clone ( ) ,
369+ fast_pool_id,
370+ fast_height,
371+ fast_inventory,
372+ )
373+ . map ( |( _, p) | p)
374+ . unwrap_or_default ( ) ;
375+ let next_profit_usdc = self
376+ . get_profit_and_signal (
377+ mid + 1 ,
378+ slow_sims,
379+ slow_protocol_component. clone ( ) ,
380+ slow_pool_id,
381+ slow_height,
382+ slow_prices_a_b,
383+ slow_prices_a_usdc,
384+ slow_prices_b_usdc,
385+ fast_state,
386+ fast_protocol_component. clone ( ) ,
387+ fast_pool_id,
388+ fast_height,
389+ fast_inventory,
390+ )
391+ . map ( |( _, p) | p)
392+ . unwrap_or_default ( ) ;
377393
378- trace ! (
379- index = mid,
380- expected_profit = %mid_signal. expected_profit,
381- "Generated mid candidate signal"
382- ) ;
394+ if mid_profit_usdc < next_profit_usdc {
395+ // next is higher -> check to the right (try a higher amount_in)
396+ trace ! ( index = mid, left = %left, right = %right, mid_profit_usdc = %mid_profit_usdc, next_profit_usdc = %next_profit_usdc, "mid+1 signal has higher expected profit, continuing search" ) ;
397+ left = mid + 1 ;
398+ } else {
399+ right = mid;
400+ }
401+ }
383402
384- // make sims for mid+1
385- let next_signal = match self . try_signal_from_precompute (
386- slow_sims[ mid + 1 ] . clone ( ) ,
403+ let ( best_signal, profit) = self
404+ . get_profit_and_signal (
405+ left,
406+ slow_sims,
387407 slow_protocol_component. clone ( ) ,
388408 slow_pool_id,
389409 slow_height,
@@ -395,51 +415,16 @@ impl CrossChainSingleHop {
395415 fast_pool_id,
396416 fast_height,
397417 fast_inventory,
398- ) {
399- Ok ( signal) => signal,
400- Err ( err) => {
401- trace ! ( index = mid+1 , err = %err, "failed to make mid+1 signal, searching over smaller values" ) ;
402- right = mid;
403- continue ;
404- }
405- } ;
406- trace ! (
407- index = mid+1 ,
408- expected_profit = %next_signal. expected_profit,
409- "Generated mid+1 candidate signal"
410- ) ;
418+ )
419+ . map ( |( sig, p) | ( sig, p) ) ?;
411420
412- // compare the expected profits
413- let mid_profit_usdc = match mid_signal. expected_profit . total_profit_usdc ( ) {
414- Ok ( profit) => profit,
415- Err ( err) => {
416- error ! ( index = mid+1 , err = %err, profit = %mid_signal. expected_profit, "failed to calculate mid+1 signal profit" ) ;
417- continue ;
418- }
419- } ;
420- let next_profit_usdc = match next_signal. expected_profit . total_profit_usdc ( ) {
421- Ok ( profit) => profit,
422- Err ( err) => {
423- error ! ( index = mid+1 , err = %err, profit = %next_signal. expected_profit, "failed to calculate next signal profit" ) ;
424- continue ;
425- }
426- } ;
421+ trace ! ( index = %left, found_signal = %best_signal, "search complete" ) ;
427422
428- if mid_profit_usdc < next_profit_usdc {
429- // next is higher -> check to the right (try a higher amount_in)
430- trace ! ( index = mid, left = %left, right = %right, "mid+1 signal has higher expected profit, continuing search" ) ;
431- best_signal = Some ( next_signal) ;
432- left = mid + 1 ;
433- } else {
434- // next is lower -> check to the left (try a lower amount_in)
435- trace ! ( index = mid, left = %left, right = %right, "mid+1 signal has lower expected profit, continuing search" ) ;
436- right = mid;
437- }
423+ if profit. is_zero ( ) {
424+ trace ! ( "best signal has zero profit, returning None" ) ;
425+ return None ;
438426 }
439-
440- trace ! ( index = %left, found_signal = %best_signal. is_some( ) , "search complete" ) ;
441-
442- best_signal
427+ Some ( best_signal)
443428 }
444429
445430 /// This creates the fast leg of the arbitrage out of the precompute slow leg.
@@ -525,6 +510,43 @@ impl CrossChainSingleHop {
525510 } )
526511 }
527512
513+ // Helper to keep the main loop clean
514+ fn get_profit_and_signal (
515+ & self ,
516+ index : usize ,
517+ slow_sims : & [ Swap ] ,
518+ slow_protocol_component : Arc < ProtocolComponent > ,
519+ slow_pool_id : & PoolId ,
520+ slow_height : u64 ,
521+ slow_prices_a_b : & SpotPrices ,
522+ slow_prices_a_usdc : & Option < SpotPrices > ,
523+ slow_prices_b_usdc : & Option < SpotPrices > ,
524+ fast_state : & dyn ProtocolSim ,
525+ fast_protocol_component : Arc < ProtocolComponent > ,
526+ fast_pool_id : & PoolId ,
527+ fast_height : u64 ,
528+ fast_inventory : & BigUint ,
529+ ) -> Option < ( signals:: CrossChainSingleHop , BigUint ) > {
530+ let sig = self
531+ . try_signal_from_precompute (
532+ slow_sims[ index] . clone ( ) ,
533+ slow_protocol_component,
534+ slow_pool_id,
535+ slow_height,
536+ slow_prices_a_b,
537+ slow_prices_a_usdc,
538+ slow_prices_b_usdc,
539+ fast_state,
540+ fast_protocol_component,
541+ fast_pool_id,
542+ fast_height,
543+ fast_inventory,
544+ )
545+ . ok ( ) ?;
546+ let profit = sig. expected_profit . total_profit_usdc ( ) . ok ( ) ?;
547+ Some ( ( sig, profit) )
548+ }
549+
528550 pub fn token_a_symbol ( & self ) -> & str {
529551 & self . slow_pair . token_a ( ) . symbol
530552 }
0 commit comments