@@ -347,6 +347,8 @@ impl TransferGraph {
347347 self . render_node_with_prefix ( output, addr, depth, visited, is_origin, String :: new ( ) ) ;
348348 }
349349
350+ /// Build a convergence-aware visualization
351+ /// Shows all paths with proper merging when multiple paths lead to same wallet
350352 fn render_node_with_prefix (
351353 & self ,
352354 output : & mut String ,
@@ -356,37 +358,53 @@ impl TransferGraph {
356358 is_origin : bool ,
357359 parent_prefix : String ,
358360 ) {
361+ // Check if this wallet has already been rendered (convergence point)
359362 if visited. contains ( addr) {
363+ // This is a convergence - show a reference instead of duplicating
364+ output. push_str ( & format ! ( "{} ↗ CONVERGES TO: {} (shown above)\n " , parent_prefix, addr) ) ;
360365 return ;
361366 }
362367 visited. insert ( addr. to_string ( ) ) ;
363368
364369 let node = self . nodes . get ( addr) ;
365370 let cfg = & self . render_config ;
366371
367- // Node header - NO TRUNCATION, show full address + label if available
372+ // Check how many incoming transfers this wallet has (convergence indicator)
373+ let incoming_count = self . nodes . values ( )
374+ . flat_map ( |n| & n. outgoing )
375+ . filter ( |t| t. to == addr)
376+ . count ( ) ;
377+
378+ let convergence_marker = if incoming_count > 1 {
379+ format ! ( " [×{} PATHS CONVERGE HERE]" , incoming_count)
380+ } else {
381+ String :: new ( )
382+ } ;
383+
384+ // Node header - NO TRUNCATION, show full address + label
368385 let label_text = node. and_then ( |n| n. label . as_ref ( ) ) . map ( |l| format ! ( " [{}]" , l) ) . unwrap_or_default ( ) ;
369386
370387 if is_origin {
371- output. push_str ( & format ! ( "{}{}\n {} \n " ,
388+ output. push_str ( & format ! ( "{}{}\n " ,
372389 cfg. origin_icon,
373- label_text,
374- addr // FULL ADDRESS
390+ label_text
375391 ) ) ;
392+ output. push_str ( & format ! ( " {}{}\n " , addr, convergence_marker) ) ;
376393 } else if Some ( addr) == self . target . as_deref ( ) {
377- output. push_str ( & format ! ( "{}{}{}\n {} {}\n " ,
394+ output. push_str ( & format ! ( "{}{}{}{}\n " ,
378395 parent_prefix,
379396 cfg. target_icon,
380397 label_text,
381- parent_prefix,
382- addr // FULL ADDRESS
398+ convergence_marker
383399 ) ) ;
400+ output. push_str ( & format ! ( "{} {}\n " , parent_prefix, addr) ) ;
384401 } else {
385- output. push_str ( & format ! ( "{}{}{} {}\n " ,
402+ output. push_str ( & format ! ( "{}{}{} {}{} \n " ,
386403 parent_prefix,
387404 cfg. node_icon,
388405 label_text,
389- addr // FULL ADDRESS
406+ addr,
407+ convergence_marker
390408 ) ) ;
391409 }
392410
@@ -398,35 +416,35 @@ impl TransferGraph {
398416
399417 // Build the prefix that will be passed to ALL children of this branch
400418 let child_prefix = if is_last {
401- // Last branch - use spaces (no more siblings)
402- format ! ( "{} " , parent_prefix)
419+ format ! ( "{} " , parent_prefix)
403420 } else {
404- // Not last - keep the pipe going for siblings below
405- format ! ( "{}│ " , parent_prefix)
421+ format ! ( "{}│ " , parent_prefix)
406422 } ;
407423
408- // Transfer line
424+ // Show connector line before transfer
425+ output. push_str ( & format ! ( "{}│\n " , parent_prefix) ) ;
426+
427+ // Transfer line with amount and metadata
409428 let branch_char = if is_last { "└─" } else { "├─" } ;
429+ let note_text = transfer. note . as_deref ( ) . unwrap_or ( "transfer" ) ;
430+
410431 output. push_str ( & format ! (
411- "{}{}→ {} {} [{:? }]\n " ,
432+ "{}{}→ [ {} {}] ──→ {} [{ }]\n " ,
412433 parent_prefix,
413434 branch_char,
414435 self . format_amount( transfer. amount) ,
415436 transfer. token_symbol,
416- transfer. note. as_deref( ) . unwrap_or( "SimpleTransfer" )
417- ) ) ;
418-
419- // Show full destination address with proper prefix
420- output. push_str ( & format ! (
421- "{} ↓ TO: {}\n " ,
422- if is_last { format!( "{} " , parent_prefix) } else { format!( "{}│ " , parent_prefix) } ,
423- transfer. to // FULL ADDRESS
437+ transfer. to,
438+ note_text
424439 ) ) ;
425440
426441 // Recurse to child with the continuous prefix
427442 if !visited. contains ( & transfer. to ) {
428- output. push_str ( & format ! ( "{} │\n " , if is_last { format! ( "{} " , parent_prefix) } else { format!( "{}│ " , parent_prefix) } ) ) ;
443+ output. push_str ( & format ! ( "{} │\n " , if is_last { parent_prefix. clone ( ) } else { format!( "{}│" , parent_prefix) } ) ) ;
429444 self . render_node_with_prefix ( output, & transfer. to , depth + 1 , visited, false , child_prefix) ;
445+ } else {
446+ // Already visited - this is a convergence point, show reference
447+ output. push_str ( & format ! ( "{} ↗ (converges with path above)\n " , if is_last { parent_prefix. clone( ) } else { format!( "{}│" , parent_prefix) } ) ) ;
430448 }
431449 }
432450 }
0 commit comments