use crate::chain::jupiter::JupToken;
use crate::chain::SolClient;
use crate::types::{Flag, Severity};
use serde_json::{json, Value};
pub async fn analyze(client: &SolClient, jup: Option<&JupToken>) -> (Value, Vec<Flag>) {
let mut flags = vec![];
let dev = jup.and_then(|j| j.dev.clone());
let dev_mints = jup.and_then(|j| j.audit.dev_mints);
let dev_balance_pct = jup.and_then(|j| j.audit.dev_balance_percentage);
let mut wallet_age_days: Option<i64> = None;
let mut wallet_tx_floor: Option<usize> = None;
if let Some(d) = &dev {
if let Ok(hist) = client.signatures(d, 1000, None).await {
wallet_tx_floor = Some(hist.len());
if hist.len() < 1000 {
if let Some(oldest) = hist.last().and_then(|s| s.block_time) {
let now = time::OffsetDateTime::now_utc().unix_timestamp();
wallet_age_days = Some((now - oldest) / 86_400);
}
}
if hist.len() <= 5 {
flags.push(Flag::new(
"fresh_deployer",
Severity::Warning,
"Fresh deployer wallet",
format!(
"The creator wallet {} has only {} transactions — no track record at all.",
short(d),
hist.len()
),
5,
));
}
}
}
if let Some(n) = dev_mints {
if n >= 50 {
flags.push(Flag::new(
"serial_deployer",
Severity::Danger,
"Serial token deployer",
format!("This creator has launched {n} tokens — classic churn-and-rug factory behavior."),
12,
));
} else if n >= 10 {
flags.push(Flag::new(
"serial_deployer",
Severity::Warning,
"Creator has launched many tokens",
format!("This creator has launched {n} tokens before this one."),
6,
));
}
}
if let Some(p) = dev_balance_pct {
let p2 = (p * 100.0).round() / 100.0;
if p >= 20.0 {
flags.push(Flag::new(
"dev_holdings",
Severity::Danger,
"Dev holds a huge bag",
format!("The creator still holds {p2}% of the supply — one click from a rug."),
15,
));
} else if p >= 10.0 {
flags.push(Flag::new(
"dev_holdings",
Severity::Warning,
"Dev holds a large bag",
format!("The creator still holds {p2}% of the supply."),
8,
));
}
}
let section = json!({
"dev": dev,
"walletAgeDays": wallet_age_days,
"walletTxCount": wallet_tx_floor.map(|n| if n >= 1000 { json!("1000+") } else { json!(n) }),
"tokensLaunched": dev_mints,
"devBalancePct": dev_balance_pct,
});
(section, flags)
}
fn short(a: &str) -> String {
if a.len() < 12 {
a.to_string()
} else {
format!("{}…{}", &a[..4], &a[a.len() - 4..])
}
}