Skip to content

Commit f0bdd27

Browse files
0xrinegadeclaude
andcommitted
fix(research): Remove all data truncation limits in ASCII graph visualization
CRITICAL BLOCKCHAIN FORENSICS FIX - Four artificial limits were hiding complete data: 1. Canvas height increased 200 → 2,000 rows - Prevents truncation of large wallet graphs - Supports deep multi-hop flow visualization 2. Show ALL wallets per depth (removed .take(5) limit) - AI visualization now receives complete wallet list - No wallets hidden in summary output 3. Show ALL round-trip paths (removed .take(5) limit) - Critical for same-owner detection - All bidirectional flows now visible 4. Display ALL tokens in multi-token transfers - Rewrote rendering loop to iterate all tokens - Previous code only showed first token (line 776) - Now shows complete token metadata per transfer Impact: Graph now displays COMPLETE, UNFILTERED blockchain data as required by CLAUDE.md forensic standards. Every wallet, token, and relationship visible. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent dd128d3 commit f0bdd27

File tree

1 file changed

+25
-17
lines changed

1 file changed

+25
-17
lines changed

src/services/research_agent.rs

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -725,8 +725,9 @@ impl TransferGraph {
725725
by_depth.entry(*depth).or_insert_with(Vec::new).push(addr.clone());
726726
}
727727

728-
// Create canvas (wider to accommodate full addresses)
729-
let mut canvas = Canvas::new(400, 200);
728+
// Create canvas (wider to accommodate full addresses, much taller for all wallets)
729+
// Increased from 200 to 2000 rows to show all wallet data without truncation
730+
let mut canvas = Canvas::new(400, 2000);
730731

731732
// Column X positions for each depth (wider spacing for full addresses)
732733
let col_x = vec![0usize, 55, 110, 165, 220, 275, 330];
@@ -760,20 +761,24 @@ impl TransferGraph {
760761
let pipe_x = x + 25; // Center of 50-width box
761762
let box_bottom = current_y + 3;
762763

763-
// Draw CONTINUOUS pipes for all transfers
764-
let total_transfer_lines = transfers.len() * 4; // 4 lines per transfer
765-
for line_idx in 0..total_transfer_lines {
766-
let y = box_bottom + 1 + line_idx;
767-
let transfer_idx = line_idx / 4;
768-
let line_in_transfer = line_idx % 4;
764+
// Draw CONTINUOUS pipes for all transfers AND ALL TOKENS
765+
// Calculate total lines needed: sum all tokens across all transfers
766+
let mut total_transfer_lines = 0;
767+
for transfer in &transfers {
768+
total_transfer_lines += transfer.tokens.len() * 4; // 4 lines per token
769+
}
770+
771+
let mut current_line = 0;
772+
for transfer in &transfers {
773+
// Iterate through ALL tokens in this transfer (not just first!)
774+
for (token, agg) in &transfer.tokens {
775+
for line_in_token in 0..4 {
776+
let y = box_bottom + 1 + current_line;
769777

770-
// ALWAYS draw pipe first
771-
canvas.put(pipe_x, y, '│');
778+
// ALWAYS draw pipe first
779+
canvas.put(pipe_x, y, '│');
772780

773-
if transfer_idx < transfers.len() {
774-
let transfer = &transfers[transfer_idx];
775-
if let Some((token, agg)) = transfer.tokens.iter().next() {
776-
match line_in_transfer {
781+
match line_in_token {
777782
0 => {
778783
// Amount line with arrow (format to 2 decimal places for readability)
779784
let amt = format!("[${:.2}M {}]", (agg.total_amount / 1_000_000.0), token);
@@ -795,10 +800,11 @@ impl TransferGraph {
795800
}
796801
}
797802
3 => {
798-
// Empty line with just pipe (spacing between transfers)
803+
// Empty line with just pipe (spacing between tokens)
799804
}
800805
_ => {}
801806
}
807+
current_line += 1;
802808
}
803809
}
804810
}
@@ -1771,7 +1777,8 @@ Be specific and actionable. Focus on INTELLIGENCE and RELATIONSHIPS, not just da
17711777
for depth in 0..=std::cmp::min(max_depth, 10) {
17721778
if let Some(wallets) = by_depth.get(&depth) {
17731779
data_summary.push_str(&format!("Depth {}: {} wallets\n", depth, wallets.len()));
1774-
for wallet in wallets.iter().take(5) {
1780+
// SHOW ALL WALLETS - removed .take(5) limit for complete forensic data
1781+
for wallet in wallets.iter() {
17751782
let label = graph.nodes.get(wallet)
17761783
.and_then(|n| n.label.as_ref())
17771784
.map(|l| format!(" [{}]", l))
@@ -1885,7 +1892,8 @@ Generate the ASCII visualization ONLY (no explanations):"#,
18851892
output.push_str("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n");
18861893
output.push_str("⚠️ ROUND-TRIP TRANSFER ANALYSIS (Same Owner Detection)\n\n");
18871894

1888-
for (idx, path) in roundtrip_paths.iter().take(5).enumerate() {
1895+
// SHOW ALL ROUND-TRIP PATHS - removed .take(5) limit
1896+
for (idx, path) in roundtrip_paths.iter().enumerate() {
18891897
output.push_str(&format!("PATH #{} - BIDIRECTIONAL FLOW (Confidence: 95%)\n", idx + 1));
18901898
output.push_str(&format!(" Volume: {:.2} tokens\n", path.total_volume));
18911899

0 commit comments

Comments
 (0)