@vizzor/cli 0.13.0 → 0.14.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +250 -191
  2. package/chronovisor-engine/pyproject.toml +31 -0
  3. package/chronovisor-engine/src/__init__.py +0 -0
  4. package/chronovisor-engine/src/inference/__init__.py +0 -0
  5. package/chronovisor-engine/src/inference/predict.py +44 -0
  6. package/chronovisor-engine/src/model_catalog.py +219 -0
  7. package/chronovisor-engine/src/models/__init__.py +0 -0
  8. package/chronovisor-engine/src/models/anomaly_detector.py +104 -0
  9. package/chronovisor-engine/src/models/blockchain_cycle_analyzer.py +217 -0
  10. package/chronovisor-engine/src/models/catalyst_event_model.py +70 -0
  11. package/chronovisor-engine/src/models/conformal_interval.py +50 -0
  12. package/chronovisor-engine/src/models/divergence_detector.py +247 -0
  13. package/chronovisor-engine/src/models/drift_monitor.py +51 -0
  14. package/chronovisor-engine/src/models/intent_classifier.py +189 -0
  15. package/chronovisor-engine/src/models/lstm_predictor.py +143 -0
  16. package/chronovisor-engine/src/models/microstructure_specialist.py +65 -0
  17. package/chronovisor-engine/src/models/narrative_detector.py +418 -0
  18. package/chronovisor-engine/src/models/portfolio_optimizer.py +162 -0
  19. package/chronovisor-engine/src/models/project_risk_scorer.py +184 -0
  20. package/chronovisor-engine/src/models/pump_detector.py +344 -0
  21. package/chronovisor-engine/src/models/regime_detector.py +127 -0
  22. package/chronovisor-engine/src/models/rug_detector.py +197 -0
  23. package/chronovisor-engine/src/models/sentiment_analyzer.py +257 -0
  24. package/chronovisor-engine/src/models/signal_classifier.py +191 -0
  25. package/chronovisor-engine/src/models/stacking_meta.py +56 -0
  26. package/chronovisor-engine/src/models/strategy_bandit.py +191 -0
  27. package/chronovisor-engine/src/models/ta_interpreter.py +341 -0
  28. package/chronovisor-engine/src/models/target_quantile.py +96 -0
  29. package/chronovisor-engine/src/models/trend_scorer.py +107 -0
  30. package/chronovisor-engine/src/models/wallet_classifier.py +261 -0
  31. package/chronovisor-engine/src/server.py +1686 -0
  32. package/chronovisor-engine/src/training/__init__.py +0 -0
  33. package/chronovisor-engine/src/training/data_loader.py +635 -0
  34. package/chronovisor-engine/src/training/pipeline.py +130 -0
  35. package/chronovisor-engine/src/training/train_catalyst.py +169 -0
  36. package/chronovisor-engine/src/training/train_classifier.py +159 -0
  37. package/chronovisor-engine/src/training/train_conformal.py +106 -0
  38. package/chronovisor-engine/src/training/train_direction.py +215 -0
  39. package/chronovisor-engine/src/training/train_drift.py +57 -0
  40. package/chronovisor-engine/src/training/train_isotonic.py +58 -0
  41. package/chronovisor-engine/src/training/train_lstm.py +217 -0
  42. package/chronovisor-engine/src/training/train_microstructure.py +102 -0
  43. package/chronovisor-engine/src/training/train_narrative.py +168 -0
  44. package/chronovisor-engine/src/training/train_pump.py +109 -0
  45. package/chronovisor-engine/src/training/train_regime.py +116 -0
  46. package/chronovisor-engine/src/training/train_rug.py +58 -0
  47. package/chronovisor-engine/src/training/train_sentiment.py +63 -0
  48. package/chronovisor-engine/src/training/train_stacking_meta.py +74 -0
  49. package/chronovisor-engine/src/training/train_target_quantile.py +115 -0
  50. package/chronovisor-engine/src/training/train_trend.py +101 -0
  51. package/dist/index.js +23803 -14468
  52. package/dist/index.js.map +1 -1
  53. package/package.json +6 -4
@@ -0,0 +1,261 @@
1
+ """LSTM-based wallet behavior classifier.
2
+
3
+ Input: transaction sequence features (tx_count, avg_value, avg_gas,
4
+ unique_recipients, unique_methods, time_spread, etc.)
5
+ Output: behavior_type classification + confidence + risk_score.
6
+
7
+ Classifies wallets as: normal_trader, bot, whale, sniper, mev_bot,
8
+ mixer_user, rug_deployer.
9
+
10
+ Trained on labeled wallet transaction sequences. Heuristic fallback.
11
+ """
12
+
13
+ import os
14
+ from pathlib import Path
15
+
16
+ import numpy as np
17
+
18
+ MODEL_DIR = Path(os.getenv("MODEL_DIR", "models"))
19
+
20
+ BEHAVIOR_TYPES = [
21
+ "normal_trader",
22
+ "bot",
23
+ "whale",
24
+ "sniper",
25
+ "mev_bot",
26
+ "mixer_user",
27
+ "rug_deployer",
28
+ ]
29
+
30
+ # Aggregated transaction features (from raw tx sequence)
31
+ AGG_FEATURE_KEYS = [
32
+ "tx_count",
33
+ "avg_value_eth",
34
+ "max_value_eth",
35
+ "avg_gas_used",
36
+ "unique_recipients",
37
+ "unique_methods",
38
+ "time_span_hours",
39
+ "avg_interval_seconds",
40
+ "min_interval_seconds",
41
+ "contract_interaction_pct",
42
+ "self_transfer_pct",
43
+ "high_value_tx_pct",
44
+ "failed_tx_pct",
45
+ "token_diversity",
46
+ ]
47
+
48
+
49
+ class WalletClassifier:
50
+ def __init__(self):
51
+ self.version = "0.1.0"
52
+ self.is_loaded = False
53
+ self.last_trained: str | None = None
54
+ self.accuracy: float | None = None
55
+ self.model = None
56
+
57
+ def load(self):
58
+ """Load trained model or use heuristic."""
59
+ model_path = MODEL_DIR / "wallet_classifier.joblib"
60
+ if model_path.exists():
61
+ try:
62
+ import joblib
63
+
64
+ self.model = joblib.load(model_path)
65
+ self.is_loaded = True
66
+ self.last_trained = str(model_path.stat().st_mtime)
67
+ except Exception:
68
+ self._init_heuristic()
69
+ else:
70
+ self._init_heuristic()
71
+
72
+ def _init_heuristic(self):
73
+ self.is_loaded = True
74
+ self.version = "0.1.0-heuristic"
75
+
76
+ def classify(self, features: dict) -> dict:
77
+ """Classify wallet behavior.
78
+
79
+ Args:
80
+ features: Aggregated transaction features for a wallet.
81
+
82
+ Returns:
83
+ dict with: behavior_type, confidence, risk_score,
84
+ secondary_type, indicators, model
85
+ """
86
+ if self.model is not None:
87
+ return self._classify_model(features)
88
+ return self._classify_heuristic(features)
89
+
90
+ def _classify_model(self, features: dict) -> dict:
91
+ """Run inference through trained classifier."""
92
+ X = np.array([[features.get(k, 0) for k in AGG_FEATURE_KEYS]])
93
+ proba = self.model.predict_proba(X)[0]
94
+ classes = list(self.model.classes_)
95
+
96
+ idx = int(np.argmax(proba))
97
+ primary = classes[idx]
98
+ confidence = float(proba[idx])
99
+
100
+ # Second most likely
101
+ sorted_idx = np.argsort(proba)[::-1]
102
+ secondary = classes[sorted_idx[1]] if len(sorted_idx) > 1 else None
103
+
104
+ risk_map = {
105
+ "normal_trader": 0.1,
106
+ "whale": 0.3,
107
+ "bot": 0.4,
108
+ "sniper": 0.6,
109
+ "mev_bot": 0.5,
110
+ "mixer_user": 0.8,
111
+ "rug_deployer": 0.95,
112
+ }
113
+
114
+ return {
115
+ "behavior_type": primary,
116
+ "confidence": round(confidence, 3),
117
+ "risk_score": risk_map.get(primary, 0.5),
118
+ "secondary_type": secondary,
119
+ "indicators": self._extract_indicators(features, primary),
120
+ "model": f"wallet-classifier-{self.version}",
121
+ }
122
+
123
+ def _classify_heuristic(self, features: dict) -> dict:
124
+ """Rule-based wallet classification until model is trained."""
125
+ tx_count = features.get("tx_count", 0)
126
+ avg_value = features.get("avg_value_eth", 0)
127
+ max_value = features.get("max_value_eth", 0)
128
+ avg_gas = features.get("avg_gas_used", 0)
129
+ unique_recipients = features.get("unique_recipients", 0)
130
+ unique_methods = features.get("unique_methods", 0)
131
+ time_span = features.get("time_span_hours", 0)
132
+ avg_interval = features.get("avg_interval_seconds", 3600)
133
+ min_interval = features.get("min_interval_seconds", 60)
134
+ contract_pct = features.get("contract_interaction_pct", 0)
135
+ self_transfer_pct = features.get("self_transfer_pct", 0)
136
+ high_value_pct = features.get("high_value_tx_pct", 0)
137
+ failed_pct = features.get("failed_tx_pct", 0)
138
+ token_diversity = features.get("token_diversity", 0)
139
+
140
+ scores: dict[str, float] = {t: 0.0 for t in BEHAVIOR_TYPES}
141
+
142
+ # --- Bot detection ---
143
+ if min_interval < 5 and tx_count > 50:
144
+ scores["bot"] += 0.35
145
+ if avg_interval < 30 and tx_count > 100:
146
+ scores["bot"] += 0.25
147
+ if contract_pct > 0.9 and unique_methods <= 3:
148
+ scores["bot"] += 0.20
149
+
150
+ # --- Sniper detection ---
151
+ if min_interval < 3 and avg_gas > 200000:
152
+ scores["sniper"] += 0.30
153
+ if failed_pct > 0.3 and avg_gas > 150000:
154
+ scores["sniper"] += 0.25
155
+ if token_diversity > 20 and time_span < 48:
156
+ scores["sniper"] += 0.20
157
+
158
+ # --- MEV bot detection ---
159
+ if avg_gas > 300000 and min_interval < 5:
160
+ scores["mev_bot"] += 0.30
161
+ if failed_pct > 0.4 and contract_pct > 0.95:
162
+ scores["mev_bot"] += 0.25
163
+ if self_transfer_pct > 0.1 and avg_gas > 200000:
164
+ scores["mev_bot"] += 0.15
165
+
166
+ # --- Whale detection ---
167
+ if max_value > 100:
168
+ scores["whale"] += 0.35
169
+ if avg_value > 10:
170
+ scores["whale"] += 0.25
171
+ if high_value_pct > 0.3:
172
+ scores["whale"] += 0.20
173
+
174
+ # --- Mixer detection ---
175
+ if self_transfer_pct > 0.3:
176
+ scores["mixer_user"] += 0.25
177
+ if unique_recipients > 50 and avg_value < 1:
178
+ scores["mixer_user"] += 0.20
179
+ if token_diversity <= 2 and unique_recipients > 30:
180
+ scores["mixer_user"] += 0.20
181
+
182
+ # --- Rug deployer detection ---
183
+ if unique_methods > 10 and contract_pct > 0.8 and tx_count < 200:
184
+ scores["rug_deployer"] += 0.25
185
+ if high_value_pct > 0.5 and unique_recipients < 5:
186
+ scores["rug_deployer"] += 0.20
187
+
188
+ # --- Normal trader baseline ---
189
+ scores["normal_trader"] += 0.20
190
+ if 10 < avg_interval < 86400:
191
+ scores["normal_trader"] += 0.10
192
+ if 0.1 < avg_value < 10:
193
+ scores["normal_trader"] += 0.10
194
+ if 0.05 < failed_pct < 0.15:
195
+ scores["normal_trader"] += 0.05
196
+
197
+ # Find top behavior
198
+ sorted_types = sorted(scores.items(), key=lambda x: x[1], reverse=True)
199
+ primary = sorted_types[0][0]
200
+ primary_score = sorted_types[0][1]
201
+ secondary = sorted_types[1][0] if len(sorted_types) > 1 else None
202
+
203
+ # Normalize confidence
204
+ total = sum(s for _, s in sorted_types) or 1.0
205
+ confidence = primary_score / total
206
+
207
+ risk_map = {
208
+ "normal_trader": 0.1,
209
+ "whale": 0.3,
210
+ "bot": 0.4,
211
+ "sniper": 0.6,
212
+ "mev_bot": 0.5,
213
+ "mixer_user": 0.8,
214
+ "rug_deployer": 0.95,
215
+ }
216
+
217
+ return {
218
+ "behavior_type": primary,
219
+ "confidence": round(confidence, 3),
220
+ "risk_score": risk_map.get(primary, 0.5),
221
+ "secondary_type": secondary,
222
+ "indicators": self._extract_indicators(features, primary),
223
+ "model": "wallet-classifier-heuristic",
224
+ }
225
+
226
+ @staticmethod
227
+ def _extract_indicators(features: dict, behavior_type: str) -> list[str]:
228
+ """Generate human-readable indicators explaining the classification."""
229
+ indicators = []
230
+ tx_count = features.get("tx_count", 0)
231
+ avg_interval = features.get("avg_interval_seconds", 3600)
232
+ min_interval = features.get("min_interval_seconds", 60)
233
+ avg_value = features.get("avg_value_eth", 0)
234
+ max_value = features.get("max_value_eth", 0)
235
+ contract_pct = features.get("contract_interaction_pct", 0)
236
+ failed_pct = features.get("failed_tx_pct", 0)
237
+ avg_gas = features.get("avg_gas_used", 0)
238
+
239
+ if behavior_type == "bot":
240
+ indicators.append(f"High frequency: {tx_count} txs, avg {avg_interval:.0f}s apart")
241
+ if contract_pct > 0.8:
242
+ indicators.append(f"Contract-heavy: {contract_pct*100:.0f}% contract calls")
243
+ elif behavior_type == "sniper":
244
+ indicators.append(f"Sub-second execution: min interval {min_interval:.1f}s")
245
+ indicators.append(f"High gas: avg {avg_gas:,.0f} gas per tx")
246
+ if failed_pct > 0.2:
247
+ indicators.append(f"High failure rate: {failed_pct*100:.0f}% failed txs")
248
+ elif behavior_type == "whale":
249
+ indicators.append(f"Large values: avg {avg_value:.2f} ETH, max {max_value:.2f} ETH")
250
+ elif behavior_type == "mev_bot":
251
+ indicators.append(f"MEV patterns: high gas ({avg_gas:,.0f}), rapid execution")
252
+ if failed_pct > 0.3:
253
+ indicators.append(f"Many reverts: {failed_pct*100:.0f}% failure rate")
254
+ elif behavior_type == "mixer_user":
255
+ indicators.append("Mixing patterns: many small transfers to unique addresses")
256
+ elif behavior_type == "rug_deployer":
257
+ indicators.append("Deploy-and-drain pattern detected")
258
+ else:
259
+ indicators.append(f"Normal activity: {tx_count} transactions over time")
260
+
261
+ return indicators