agus1111 commited on
Commit
5fe05f6
·
verified ·
1 Parent(s): d25a037

Update botsignal.py

Browse files
Files changed (1) hide show
  1. botsignal.py +70 -3
botsignal.py CHANGED
@@ -542,18 +542,81 @@ try:
542
  _M_LIST = ["1.5", "2"]
543
  MILESTONES_LABEL = " • ".join(f"{m}×" for m in _M_LIST)
544
  except Exception:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
545
  _M_LIST = ["1.5", "2"]
546
  MILESTONES_LABEL = "1.5× • 2×"
547
 
548
  # ===== Creative CA message with MCAP + links =====
549
- def build_midas_message_for_ca(ca: str, tier_label: str, *, mcap_value=None, body_snippet: Optional[str] = None) -> str:
550
  """
551
  Creative brand style untuk CA:
552
  - Tampilkan MCAP kalau tersedia
553
  - Sisipkan Dexscreener & Axiom
554
  - Copy 'first alert 1.5×' menuju discovery (no ceilings)
555
  """
556
- dexs_link = f"https://dexscreener.com/token/{ca}"
557
  axiom_link = "https://axiom.trade/@1144321"
558
  mcap_line = f"MCAP (est.): {_fmt_big_usd(mcap_value)}"
559
 
@@ -893,6 +956,10 @@ async def process_message(msg, source_chat_id: int) -> None:
893
  return
894
 
895
  entity_key = extract_entity_key(orig_text)
 
 
 
 
896
  duplicate_entity = bool(entity_key and entity_key in recent_entity_keys)
897
 
898
  UPDATE_HINTS = [
@@ -930,7 +997,7 @@ async def process_message(msg, source_chat_id: int) -> None:
930
  all_kws = _extract_all_keywords(text_norm)
931
  main_kw = _choose_dominant_keyword(text_norm, all_kws)
932
 
933
- topic_key = entity_key or main_kw
934
  if not topic_key:
935
  debug_log("Tak ada keyword/entitas cocok, dilewati", orig_text)
936
  return
 
542
  _M_LIST = ["1.5", "2"]
543
  MILESTONES_LABEL = " • ".join(f"{m}×" for m in _M_LIST)
544
  except Exception:
545
+ # ===== Universal Dexscreener link (guess chain from context or API) =====
546
+ CHAIN_HINTS = {
547
+ "bsc": "bsc", "bnb": "bsc", "binance": "bsc",
548
+ "eth": "ethereum", "ethereum": "ethereum",
549
+ "base": "base", "coinbase": "base",
550
+ "sol": "solana", "solana": "solana", "pump.fun": "solana"
551
+ }
552
+
553
+ def _guess_chain_from_text(t: str) -> Optional[str]:
554
+ t = (t or "").lower()
555
+ for k, v in CHAIN_HINTS.items():
556
+ if re.search(rf"(^|\W){re.escape(k)}(\W|$)", t):
557
+ return v
558
+ return None
559
+
560
+ async def _fetch_best_chain_for_ca(ca: str) -> Optional[str]:
561
+ """
562
+ Query Dexscreener token endpoint to pick the chainId with highest USD liquidity.
563
+ """
564
+ try:
565
+ timeout = aiohttp.ClientTimeout(total=8)
566
+ async with aiohttp.ClientSession(timeout=timeout) as sess:
567
+ async with sess.get(DEXSCREENER_TOKEN_URL + ca) as r:
568
+ if r.status != 200:
569
+ return None
570
+ data = await r.json()
571
+ pairs = (data or {}).get("pairs") or []
572
+ if not pairs:
573
+ return None
574
+ best = max(pairs, key=lambda p: (p.get("liquidity", {}) or {}).get("usd", 0))
575
+ chain_id = (best.get("chainId") or "").lower().strip()
576
+ # Dexscreener uses "ethereum", "bsc", "base", "solana", etc.
577
+ return chain_id or None
578
+ except:
579
+ return None
580
+
581
+ async def _dexs_link_universal(ca: str, context_text: Optional[str] = None) -> str:
582
+ """
583
+ Build the proper Dexscreener URL for a CA:
584
+ - Solana: /solana/<ca>
585
+ - EVM: /{ethereum|bsc|base}/<ca> (heuristic from text, fallback API, then default ethereum)
586
+ - Fallback: /token/<ca>
587
+ """
588
+ # Solana
589
+ if CA_SOL_RE.fullmatch(ca):
590
+ return f"https://dexscreener.com/solana/{ca}"
591
+
592
+ # EVM
593
+ if CA_EVM_RE.fullmatch(ca):
594
+ # (1) Heuristic from context text
595
+ hint = _guess_chain_from_text(context_text or "")
596
+ if hint:
597
+ return f"https://dexscreener.com/{hint}/{ca.lower()}"
598
+ # (2) Fallback query API to pick best chain by liquidity
599
+ chain = await _fetch_best_chain_for_ca(ca)
600
+ if chain:
601
+ return f"https://dexscreener.com/{chain}/{ca.lower()}"
602
+ # (3) Default
603
+ return f"https://dexscreener.com/ethereum/{ca.lower()}"
604
+
605
+ # Non-CA
606
+ return f"https://dexscreener.com/token/{ca}"
607
+
608
  _M_LIST = ["1.5", "2"]
609
  MILESTONES_LABEL = "1.5× • 2×"
610
 
611
  # ===== Creative CA message with MCAP + links =====
612
+ def build_midas_message_for_ca(ca: str, tier_label: str, *, mcap_value=None, body_snippet: Optional[str] = None, dexs_link: Optional[str] = None) -> str:
613
  """
614
  Creative brand style untuk CA:
615
  - Tampilkan MCAP kalau tersedia
616
  - Sisipkan Dexscreener & Axiom
617
  - Copy 'first alert 1.5×' menuju discovery (no ceilings)
618
  """
619
+ dexs_link = dexs_link or f\"https://dexscreener.com/token/{ca}\"
620
  axiom_link = "https://axiom.trade/@1144321"
621
  mcap_line = f"MCAP (est.): {_fmt_big_usd(mcap_value)}"
622
 
 
956
  return
957
 
958
  entity_key = extract_entity_key(orig_text)
959
+ # STRICT: Only process messages that contain a Contract Address (CA)
960
+ if not (entity_key and entity_key.startswith("ca:")):
961
+ debug_log("Bukan pesan CA, dilewati", orig_text)
962
+ return
963
  duplicate_entity = bool(entity_key and entity_key in recent_entity_keys)
964
 
965
  UPDATE_HINTS = [
 
997
  all_kws = _extract_all_keywords(text_norm)
998
  main_kw = _choose_dominant_keyword(text_norm, all_kws)
999
 
1000
+ topic_key = entity_key
1001
  if not topic_key:
1002
  debug_log("Tak ada keyword/entitas cocok, dilewati", orig_text)
1003
  return