diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..b082b54
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,30 @@
+name: CI
+
+on:
+ push:
+ pull_request:
+
+jobs:
+ checks:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: "3.11"
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install -r requirements.txt
+
+ - name: Import smoke check
+ run: |
+ python -c "import debank_checker.api.client, debank_checker.checker, debank_checker.export.csv_exporter, debank_checker.export.excel, debank_checker.export.json_exporter, debank_checker.proxy.manager, debank_checker.ui.menu"
+
+ - name: Bytecode compile
+ run: |
+ python -m compileall -q debank_checker main.py
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a439fb5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,27 @@
+# Python
+__pycache__/
+*.py[cod]
+*.pyo
+*.pyd
+.Python
+*.so
+.venv/
+venv/
+env/
+
+# Output
+Results/
+debug_log.txt
+
+# Local inputs (do not commit)
+wallets.txt
+proxy.txt
+
+# IDE
+.cursor/
+.vscode/
+*.swp
+*.swo
+
+# Tool logs
+.playwright-mcp/
diff --git a/README.md b/README.md
index f843d0e..d0aeae0 100644
--- a/README.md
+++ b/README.md
@@ -1,56 +1,124 @@
-# FarmerPro
-
+# DeBank Balance Checker
-**[English](#english) | [Русский](#русский)**
+[](https://github.com/privatekey7/DeBankChecker/actions/workflows/ci.yml)
+
+CLI‑утилита на Python для массовой проверки кошельков через DeBank API (**Tokens + DeFi + NFT**) с экспортом результатов (**Excel / CSV / JSON**).
+
+**TG:** `https://t.me/privatekey_ai`
---
-## English
+## Возможности
+
+- **Массовая проверка** списка адресов из `wallets.txt`
+- **Прокси‑ротация** + rate limiting / cooldown (для стабильности)
+- **Параллельная обработка** кошельков
+- **Экспорт**:
+ - Excel (`.xlsx`)
+ - CSV
+ - JSON
+- **Фильтры экспорта** по сетям/токенам/NFT/протоколам (в меню после проверки)
-A modular desktop tool for managing crypto accounts and wallets.
+---
+
+## Требования
-| Module | Description |
-|--------|-------------|
-| EVM Balance Checker | Check balances of EVM wallets across networks |
-| SVM Balance Checker | Check balances of Solana wallets |
-| Token Collector | Collect tokens from wallets via swap and bridge |
-| Proxy Checker | Check proxy availability and quality |
-| Twitter Checker | Check Twitter/X account status |
-| Discord Token Checker | Check Discord token status |
+- **Python 3.10+** (рекомендуется)
+- Windows / macOS / Linux
-### Installation
+Зависимости перечислены в `requirements.txt` (ключевые: `curl_cffi`, `openpyxl`, `questionary`, `colorama`).
+
+---
+
+## Установка
+
+В папке проекта:
```bash
-git clone https://github.com/privatekey7/Farmer_Pro.git
-cd Farmer_Pro
-pip install -r requirements.txt
-python main.py
+python -m venv .venv
```
-For detailed documentation visit: https://privatekey7.gitbook.io/farmerpro-en/
+Windows PowerShell:
+
+```powershell
+.venv\Scripts\Activate.ps1
+```
+
+Дальше:
+
+```bash
+pip install -r requirements.txt
+```
---
-## Русский
+## Подготовка файлов
+
+### `wallets.txt`
+
+- **Один адрес на строку**
+- Пустые строки игнорируются
+- Строки, начинающиеся с `#`, считаются комментариями
-Модульный десктопный инструмент для работы с крипто-аккаунтами и кошельками.
+Пример:
+
+```text
+# my wallets
+0x0000000000000000000000000000000000000000
+0x1111111111111111111111111111111111111111
+```
-| Модуль | Описание |
-|--------|----------|
-| EVM Balance Checker | Проверка балансов EVM-кошельков по сетям |
-| SVM Balance Checker | Проверка балансов Solana-кошельков |
-| Token Collector | Сбор токенов с кошельков через свап и бридж |
-| Proxy Checker | Проверка работоспособности прокси |
-| Twitter Checker | Проверка статуса Twitter/X аккаунтов |
-| Discord Token Checker | Проверка статуса Discord токенов |
+### `proxy.txt` (обязательно)
-### Установка
+Прокси обязательны: при пустом `proxy.txt` программа завершится с ошибкой.
+
+Поддерживаемые форматы строк:
+
+- `ip:port`
+- `ip:port:login:password`
+
+Пример:
+
+```text
+127.0.0.1:8080
+10.10.10.10:3128:user:pass
+```
+
+---
+
+## Запуск
```bash
-git clone https://github.com/privatekey7/Farmer_Pro.git
-cd Farmer_Pro
-pip install -r requirements.txt
python main.py
```
-Подробная документация: https://privatekey7.gitbook.io/farmerpro-ru/
+Поток работы:
+
+1. Запускается проверка всех кошельков
+2. Печатается прогресс‑бар
+3. После завершения открывается **интерактивное меню** экспорта (что именно выгружать)
+4. Вы выбираете формат (**Excel / CSV / JSON**)
+5. Файлы сохраняются в папку `Results/`
+
+---
+
+## Результаты
+
+Вывод сохраняется в:
+
+- `Results/`
+
+Файлы именуются с учётом выбранного экспорта и времени запуска.
+
+---
+
+## Защита от «фантомных» балансов
+
+Под высокой конкуренцией DeBank-API иногда возвращает портфель **другого адреса**
+(response contamination): на кошельке с $15 «появляются» сотни тысяч/миллионы.
+Воспроизводится только при параллельных запросах (последовательно — нет).
+
+Чекер принимает баланс кошелька, только если он **подтверждён двумя независимыми
+запросами**, сошедшимися по сумме (корроборация). Случайный фантом не повторяется
+и отбрасывается, истинный баланс стабилен и подтверждается. Параметры — в
+`debank_checker/config.py` (`CORROBORATION_*`).
diff --git a/app/__init__.py b/app/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/app/__main__.py b/app/__main__.py
deleted file mode 100644
index c336f52..0000000
--- a/app/__main__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-from app.main import main
-main()
diff --git a/app/core/__init__.py b/app/core/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/app/core/base_module.py b/app/core/base_module.py
deleted file mode 100644
index f6f00bc..0000000
--- a/app/core/base_module.py
+++ /dev/null
@@ -1,45 +0,0 @@
-from __future__ import annotations
-from abc import ABC, abstractmethod
-from typing import AsyncIterator, TYPE_CHECKING
-
-if TYPE_CHECKING:
- from PySide6.QtWidgets import QWidget
- from .models import RunContext, Result, ColumnDef
-
-
-class BaseModule(ABC):
- """Базовый интерфейс для всех модулей FarmerPro."""
-
- name: str # Отображаемое имя в боковом меню
-
- @abstractmethod
- def get_config_widget(self) -> "QWidget | None":
- """
- Возвращает Qt-виджет настроек этого модуля.
- Возвращает None если у модуля нет настроек.
- """
-
- @abstractmethod
- def run(self, ctx: "RunContext") -> "AsyncIterator[Result]":
- """
- Возвращает async-генератор результатов.
- TaskRunner итерирует: async for result in module.run(ctx).
- """
-
- @abstractmethod
- async def stop(self) -> None:
- """
- Устанавливает внутренний флаг отмены.
- """
-
- def get_item_count(self) -> int:
- """Возвращает общее количество элементов для обработки. 0 = неизвестно."""
- return 0
-
- def column_schema(self) -> "list[ColumnDef]":
- """
- Defines which columns the ResultsTable should display, their order,
- labels, formatting, and sort type. Return an empty list to fall back
- to the legacy auto-derive behaviour (all result.data keys).
- """
- return []
diff --git a/app/core/config.py b/app/core/config.py
deleted file mode 100644
index 7c56516..0000000
--- a/app/core/config.py
+++ /dev/null
@@ -1,42 +0,0 @@
-from __future__ import annotations
-import os
-from pathlib import Path
-from typing import Any
-import yaml
-from dotenv import load_dotenv
-from .exceptions import ConfigError
-
-_DEFAULT_CONFIG = Path(__file__).parent.parent / "resources" / "config.yaml"
-
-
-class Config:
- _instance: Config | None = None
-
- def __init__(self, config_path: str | None = None):
- load_dotenv()
- path = Path(config_path) if config_path else _DEFAULT_CONFIG
- if not path.exists():
- raise ConfigError(f"Config file not found: {path}")
- with open(path, encoding="utf-8") as f:
- self._data: dict[str, Any] = yaml.safe_load(f) or {}
- Config._instance = self
-
- @classmethod
- def instance(cls) -> "Config":
- """Возвращает синглтон. Создаёт с дефолтным конфигом если ещё не инициализирован."""
- if cls._instance is None:
- cls._instance = cls()
- return cls._instance
-
- def get(self, key: str, default: Any = None) -> Any:
- return self._data.get(key, default)
-
- def set(self, key: str, value: object) -> None:
- """Обновляет значение в памяти и сохраняет config.yaml."""
- self._data[key] = value
- with open(_DEFAULT_CONFIG, "w", encoding="utf-8") as f:
- yaml.dump(self._data, f, allow_unicode=True, default_flow_style=False)
-
- def env(self, key: str, default: str | None = None) -> str | None:
- """Читает переменную окружения."""
- return os.environ.get(key, default)
diff --git a/app/core/exceptions.py b/app/core/exceptions.py
deleted file mode 100644
index 6c6797d..0000000
--- a/app/core/exceptions.py
+++ /dev/null
@@ -1,17 +0,0 @@
-class FarmerProError(Exception):
- """Базовое исключение проекта."""
-
-
-class RetryExhaustedError(FarmerProError):
- """Все попытки retry исчерпаны."""
- def __init__(self, attempts: int, last_error: Exception):
- super().__init__(f"Failed after {attempts} attempts: {last_error}")
- self.last_error = last_error
-
-
-class ConfigError(FarmerProError):
- """Ошибка конфигурации."""
-
-
-class ParseError(FarmerProError):
- """Ошибка парсинга входного файла."""
diff --git a/app/core/logger.py b/app/core/logger.py
deleted file mode 100644
index 117bb0f..0000000
--- a/app/core/logger.py
+++ /dev/null
@@ -1,89 +0,0 @@
-from __future__ import annotations
-import re
-import logging
-from datetime import datetime
-from pathlib import Path
-from typing import Any
-
-_PRIVATE_KEY_RE = re.compile(r"0x[0-9a-fA-F]{64}")
-_LONG_TOKEN_RE = re.compile(r"\S{31,}") # строки >30 символов без пробелов
-
-_LOG_DIR = Path("logs")
-
-
-def mask_sensitive(text: str) -> str:
- """Маскирует приватные ключи и длинные токены в тексте."""
- text = _PRIVATE_KEY_RE.sub("0x***", text)
- # Длинные токены (не URL и не hex-адреса, уже замаскированные)
- def _mask_token(m: re.Match) -> str:
- s = m.group(0)
- # Пропускаем URL
- if s.startswith("http") or s.startswith("0x***"):
- return s
- return "***"
- text = _LONG_TOKEN_RE.sub(_mask_token, text)
- return text
-
-
-class _QtSignalHandler(logging.Handler):
- """Маршрутизирует Python logging → Qt-сигнал UI виджета лога."""
-
- def __init__(self, signal_fn: Any) -> None:
- super().__init__(logging.INFO)
- self._signal_fn = signal_fn
- self.setFormatter(logging.Formatter(
- "[%(asctime)s] %(levelname)-5s %(message)s", datefmt="%H:%M:%S"
- ))
-
- def emit(self, record: logging.LogRecord) -> None:
- try:
- line = mask_sensitive(self.format(record))
- self._signal_fn(line)
- except Exception:
- pass
-
-
-class Logger:
- """Логгер с двумя sink'ами: файл и Qt-сигнал."""
-
- def __init__(self, on_log_signal: Any = None, name: str = "farmerpro"):
- self._signal = on_log_signal
- self._log_dir = _LOG_DIR
- self._log_dir.mkdir(exist_ok=True)
- log_file = self._log_dir / f"{datetime.now().strftime('%Y-%m-%d')}.log"
- self._file_logger = logging.getLogger(name)
- if not self._file_logger.handlers:
- handler = logging.FileHandler(log_file, encoding="utf-8")
- handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s"))
- self._file_logger.addHandler(handler)
- self._file_logger.setLevel(logging.DEBUG)
-
- # Подключаем Python logging иерархию "app.*" к UI-сигналу
- if self._signal is not None:
- app_logger = logging.getLogger("app")
- # Удаляем старые signal-обработчики чтобы не дублировать при повторном запуске
- app_logger.handlers = [
- h for h in app_logger.handlers if not isinstance(h, _QtSignalHandler)
- ]
- app_logger.addHandler(_QtSignalHandler(self._signal.emit))
- app_logger.setLevel(logging.INFO)
-
- def _emit(self, level: str, message: str) -> None:
- safe_msg = mask_sensitive(message)
- timestamp = datetime.now().strftime("%H:%M:%S")
- line = f"[{timestamp}] {level:5s} {safe_msg}"
- # Файл
- level_map = {"INFO": "info", "WARN": "warning", "ERROR": "error"}
- getattr(self._file_logger, level_map.get(level, "info"))(safe_msg)
- # UI сигнал
- if self._signal is not None:
- self._signal.emit(line)
-
- def info(self, message: str) -> None:
- self._emit("INFO", message)
-
- def warning(self, message: str) -> None:
- self._emit("WARN", message)
-
- def error(self, message: str) -> None:
- self._emit("ERROR", message)
diff --git a/app/core/models.py b/app/core/models.py
deleted file mode 100644
index 52cabe0..0000000
--- a/app/core/models.py
+++ /dev/null
@@ -1,57 +0,0 @@
-from __future__ import annotations
-from dataclasses import dataclass, field
-from enum import Enum
-from typing import Any
-
-
-class ResultStatus(Enum):
- OK = "ok"
- ERROR = "error"
- SKIP = "skip"
-
-
-@dataclass
-class ProxyConfig:
- host: str
- port: int
- user: str | None = None
- password: str | None = None
- protocol: str = "http" # "http" | "socks5"
-
- def to_url(self) -> str:
- """Возвращает прокси URL для httpx."""
- if self.user and self.password:
- return f"{self.protocol}://{self.user}:{self.password}@{self.host}:{self.port}"
- return f"{self.protocol}://{self.host}:{self.port}"
-
-
-@dataclass
-class RunContext:
- items: list[str]
- proxies: list[ProxyConfig]
- rpc_urls: list[str]
- concurrency: int
- extra: dict[str, Any] = field(default_factory=dict)
-
-
-@dataclass
-class ColumnDef:
- """Defines how a column is displayed in ResultsTable."""
- key: str # key in result.data (or "item"/"status")
- label: str = "" # human-readable header; falls back to key
- fmt: str = "" # Python format string, e.g. "${:.2f}", "{:.0f} ms"
- width: int = 0 # hint width in px (0 = stretch)
- sort_type: str = "text" # "text" | "numeric"
- visible: bool = True # False = only in export, hidden from table
-
- def __post_init__(self) -> None:
- if not self.label:
- self.label = self.key
-
-
-@dataclass
-class Result:
- item: str
- status: ResultStatus
- data: dict[str, Any] = field(default_factory=dict)
- error: str | None = None
diff --git a/app/core/module_registry.py b/app/core/module_registry.py
deleted file mode 100644
index 937a9ad..0000000
--- a/app/core/module_registry.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from __future__ import annotations
-from .base_module import BaseModule
-
-
-class ModuleRegistry:
- """Реестр зарегистрированных модулей. Регистрация явная, в main.py."""
-
- def __init__(self) -> None:
- self._modules: list[BaseModule] = []
-
- def register(self, module: BaseModule) -> None:
- """Регистрирует модуль в реестре."""
- self._modules.append(module)
-
- def get_modules(self) -> list[BaseModule]:
- """Возвращает все зарегистрированные модули в порядке регистрации."""
- return list(self._modules)
-
- def get_by_name(self, name: str) -> BaseModule | None:
- """Ищет модуль по имени. Возвращает None если не найден."""
- for m in self._modules:
- if m.name == name:
- return m
- return None
diff --git a/app/core/retry.py b/app/core/retry.py
deleted file mode 100644
index 7f5321f..0000000
--- a/app/core/retry.py
+++ /dev/null
@@ -1,35 +0,0 @@
-from __future__ import annotations
-import asyncio
-import functools
-from typing import TypeVar, Callable, Awaitable
-from .exceptions import RetryExhaustedError
-
-F = TypeVar("F", bound=Callable[..., Awaitable])
-
-# Заменяемая для тестов функция sleep
-_sleep = asyncio.sleep
-
-
-def retry(attempts: int = 3, backoff: float = 2.0):
- """
- Декоратор для async-функций с экспоненциальной паузой между попытками.
-
- Args:
- attempts: максимальное количество попыток
- backoff: множитель паузы (пауза = backoff ** attempt_index секунд)
- """
- def decorator(fn: F) -> F:
- @functools.wraps(fn)
- async def wrapper(*args, **kwargs):
- last_error: Exception | None = None
- for attempt in range(attempts):
- try:
- return await fn(*args, **kwargs)
- except Exception as e:
- last_error = e
- if attempt < attempts - 1:
- delay = backoff ** attempt
- await _sleep(delay)
- raise RetryExhaustedError(attempts=attempts, last_error=last_error)
- return wrapper # type: ignore
- return decorator
diff --git a/app/core/task_runner.py b/app/core/task_runner.py
deleted file mode 100644
index e6acf2c..0000000
--- a/app/core/task_runner.py
+++ /dev/null
@@ -1,81 +0,0 @@
-from __future__ import annotations
-import asyncio
-from concurrent.futures import ThreadPoolExecutor
-from typing import TYPE_CHECKING
-
-from PySide6.QtCore import QThread, Signal, QObject
-
-from app.core.models import Result, RunContext
-from app.core.base_module import BaseModule
-
-if TYPE_CHECKING:
- pass
-
-
-class _Signals(QObject):
- on_result = Signal(object) # Result
- on_log = Signal(str)
- on_finished = Signal()
-
-
-class TaskRunner(QThread):
- """
- Запускает модуль в отдельном потоке с собственным asyncio event loop.
- Concurrency управляется через asyncio.Semaphore(ctx.concurrency).
- """
-
- def __init__(self, parent=None) -> None:
- super().__init__(parent)
- self._signals = _Signals()
- self.on_result = self._signals.on_result
- self.on_log = self._signals.on_log
- self.on_finished = self._signals.on_finished
-
- self._module: BaseModule | None = None
- self._ctx: RunContext | None = None
- self._loop: asyncio.AbstractEventLoop | None = None
- self._executor = ThreadPoolExecutor(max_workers=20)
-
- def submit(self, module: BaseModule, ctx: RunContext) -> None:
- """Запускает модуль. Вызывать из UI-потока."""
- if self.isRunning():
- # Останавливаем предыдущий run и ждём завершения потока
- if self._loop and self._module:
- asyncio.run_coroutine_threadsafe(self._do_stop(), self._loop)
- self.wait(5000) # ждём до 5 сек
-
- self._module = module
- self._ctx = ctx
- self.start()
-
- def stop_module(self) -> None:
- """Останавливает текущий модуль. Вызывать из UI-потока."""
- if self._loop and self._module:
- asyncio.run_coroutine_threadsafe(self._do_stop(), self._loop)
-
- async def _do_stop(self) -> None:
- if self._module:
- await self._module.stop()
-
- def run(self) -> None:
- """Точка входа QThread. Создаёт asyncio loop и запускает задачи."""
- self._loop = asyncio.new_event_loop()
- asyncio.set_event_loop(self._loop)
- try:
- self._loop.run_until_complete(self._run_module())
- finally:
- self._loop.close()
- self.on_finished.emit()
-
- async def _run_module(self) -> None:
- if self._module is None or self._ctx is None:
- return
- semaphore = asyncio.Semaphore(self._ctx.concurrency)
- self._ctx.extra["semaphore"] = semaphore
- try:
- async for result in self._module.run(self._ctx):
- self.on_result.emit(result)
- except asyncio.CancelledError:
- pass
- except Exception as e:
- self.on_log.emit(f"[ERROR] Critical: {e}")
diff --git a/app/data/solana_tokens.json b/app/data/solana_tokens.json
deleted file mode 100644
index b1ef7fa..0000000
--- a/app/data/solana_tokens.json
+++ /dev/null
@@ -1,5754 +0,0 @@
-{
- "CVU6QRwpHz94UGyPFFehm1G1sFYRH7xDk9UhZ9RApump": "000",
- "F9JkmcR9oXaV5kZJKbz75ZqiYRVnAwgcBJXj8JRzpump": "1234567891",
- "CLD7wRUSwM68q51ayc1wt4Yipc6b2fwLqVm7Rv4Dpump": "035HP!",
- "oxynABVJXUEc9PLNx4m1XVdiFtRhStzRXG1G6qosni1": "0XY",
- "EaK5BoVLiGovVu1JNXJDguMtQyMid3zBX4xWVqhZpump": "100X",
- "DpeJ6CkihBJzSNvgMcB9e56NT6Qiu2HL3nAGwYWUJESt": "FIGS",
- "eLER748CTmFwiBiuU7nkz8iZQcaeV1KYc6AwZUipump": "VALENTINES",
- "6UmWzmUy1RFa4eRGqpCL9Rat7oY4xXNV5Lt6pa84pump": "19",
- "GMvCfcZg8YvkkQmwDaAzCtHDrrEtgE74nQpQ7xNabonk": "1-COIN-CAN-CHANGE-YOUR-LIFE",
- "Yd8w2KJQ7BXe6JJTxqae9eRfSXzK15poXAvRwcYpump": "COMMUNITY",
- "4R3DPW4BY97kJRfv8J5wgTtbDpoXpRv92W957tXMpump": "1DEV",
- "8erRtd8mLgNcNoWy2bhMdTgZyXaRR6u7t2hyXRc1pump": "1DOG",
- "4UTEFQjNMvfQF5NT8mVfXdMAKoL7hS7i9U4mMVAzpump": "$1",
- "1HubD1oE9D8L5FQuSBs8r8NTgL3BgMqK1nkDx6Bjch4": "1HUB",
- "Aih3sbAbu39Yn7jB2Qf4btZ5eWtDGQJH2gMfC4qdBAGS": "1LY",
- "85ymfLLfeyYA9wV1PorpLBW1pprWfPgnm3cMEx5ppump": "MEME",
- "Aea8zJW7jp1wkct3BjMeekBC1RQnHQyrvNutigc3pump": "CIRCLES",
- "8tLbMZWuwB9oyXaJdAuPpL4ecVTdiNqGGR9n8m3bpump": "NARRATIVE",
- "NJxAmP4tJZyRVaU5i2jG2ZmfguXzDjCQ67ZqRyBh111": "ONE",
- "3dwu2tw7kBFZvWEdJMbPCGm7MBwgziABChLV1kGspump": "1%",
- "bGxHNbsacaVL35pkYWae5PYQDZXSpuQb3QDyW31pump": "PEANUT",
- "2LoiyomEa13iWFXdFMPMgy9W1w17JusdYKgzQb4D1to1": "1TO1",
- "2GhzrpfpdoyttRwguGD38bWMvbTaCtL6ohjmv9J6pump": "YEAR",
- "EwEJ5R1im54MowvsGwYUkyfWRMV1qcRL21PumVd4pump": "2016",
- "J5ELogmzrdKiuSZxvKSKtfs8JRXMoR7YQEBHebr7pump": "2025",
- "CQ1eU5VLsw2WyaDgVJPDBb1RyroeZoJaMeRaNkwtpump": "2026",
- "HNi43Ue8Qz8XegA9q8AWbV9DxzJxcexm8czE1fhppump": "2077",
- "4vGHdzcNrDf8XVE8H19Rqea86RULz7xi89ew1sSJpump": "21",
- "4wDBLK2SzKRDH1SQgJkLQ9eEBggpBjYyLPMeoj6vPumP": "23",
- "FA532HAN5BVwNsKMxXxj8gBWQj8QL2p8x8zNn3Mipump": "GOLDPEPE",
- "7XJiwLDrjzxDYdZipnJXzpr1iDTmK55XixSFAa7JgNEL": "MLG",
- "375aiUqZERLrB9sHtsArKr4nuWCgBrtqibUDBMGeLvZC": "EAT",
- "GL3wQ5ADspXbAG3E8hUfSkWY884jSKfgFS6Fk9Npump": "39A",
- "G63pAYWkZd71Jdy83bbdvs6HMQxaYVWy5jsS1hK3pump": "3EYES",
- "Cz7LGKdZPpAxonXx23ZYPW3RtDQvjcf17ZDCZEzFpump": "401JK",
- "ACyP5VHmSYhixsHwFXh8BTqypPGBTjHGcJZjYdBvPKaE": "401K",
- "5CxtvaR1SskwLxfzHGurx8Enu8bgSTPyWF3YP4sWpump": "42069COIN",
- "EUfRMccYw5E8Jv7NFmcpgKVFABqTr3QVputRQrbZpump": "4.25",
- "5X742twtV5sf8ZnSWSZ3WhxHgR9wmVeQmvzpnK7Gpump": "DOPAMINE",
- "42c846hyuCL5vMfqWifNvddUqHSqAFeJX7rDQBEBpKmM": "42",
- "Pj3sX83x2gsxwwfzhUuszdA8EWcJvkJ4g3k3LCfpump": "4547",
- "3dhk95qAjdJVQgBdiWUY9uCytWqukRUJ7RAgpG8Emoon": "4TOOL",
- "HwPtbFpd3VTe3tfyosoVtPf9WPuSk5gAKkN5xp6Npump": "🟥🟩",
- "b37NMA81bSgVmC6E5TXyrUndRzwdYycxoLFsG3gpump": "PAPER",
- "FYdt8T5GXucuM8rTm72jNEk2iSpi74EcsmDKYQhppump": "501",
- "9qriMjPPAJTMCtfQnz7Mo9BsV2jAWTr2ff7yc3JWpump": "\" \"",
- "76rTxzztXjJe7AUaBi7jQ5J61MFgpQgB4Cc934sWbonk": "67",
- "4sxxEHW6XqX5YBYs29f1p2RhR7afXFS8wQWcMYQVpump": "POP",
- "EhNEwXZq89viTNhADmm5CT8GGHxF27694mzMUVjrpump": "6IXROOMS",
- "J2bUGZDxRDpsVfjZqKwn6yYCUKFmqzHgt8UajhGtpump": "∅",
- "FeKmTunVrXDKEoDJbuTwZi8vfFFw3MHzpPB79JD8ARYU": "FIW",
- "5puhwnyz2Tv8jSmmBD5DSqCwFVXwwPGZacymM7DQpump": "8008",
- "BzzPPSVod9sckAa4hSgpRFsTWZkQzYmJagRywpaUbonk": "發發發",
- "888R77WmcLJKyGeJjk1WktFAB5u5fkvmokHYsAu6Spyd": "888",
- "3xvLSHrLcM7246X1vu34cM9gNX741kQrzqj6T2HhLvXp": "COIN",
- "9fcfqnpSW3ifkZeaRS19uHeovDRBLy57V89zh2rtpump": "8CHAN",
- "8ZEfp4PkEMoGFgphvxKJrDySfS3T73DBfxKCdAsPpump": "8",
- "2fNexKk1XFVRqRmuak4hFcgfpTSJf3HE6BH6f6bjkxz7": "9TO5",
- "2QQVZpiCicFZM7wKHRvBtnvTxVBLxMtD1SJWbKSLpump": "A16G",
- "HuiVprCHCucHUb5bX6EXFJd7wuwvdASFzzge4ahXpump": "TILLY",
- "ENoD8J2J6wNHkcJkvVBkwq5JMiR1oNBfBZRkoHCQogyT": "AABL",
- "129gRoHKhVg7CvPMrqVsEB4uYZo6zV4yDZX6NBg9ondo": "ABTON",
- "XsHtf5RpxsQ7jeJ9ivNewouZKJHbPxhPoEy6yYvULr7": "ABTX",
- "MFerpBVGKZh2jXN7cbJdXRXQTp6j6pbSnSZrfWrondo": "ABBVON",
- "XswbinNKyPmzTa5CskMbCPvMW6G5CMnZXZEeQSSQoie": "ABBVX",
- "F2w7z5sVe72SXnkj5qc48KXgXY2Pzj1fNtJXarmGpump": "ABI",
- "P7hTXnKk2d2DyqWnefp5BSroE1qjjKpKxg9SxQqondo": "PALLON",
- "XsTTtPA5V19YwHKDv4xeVXNM6kdsQNJvg3MyWkRUckt": "PALLX",
- "DwRtkbsaQMGAS3oMeEGYh6M5vH4X9WECsQgqHjAondo": "PPLTON",
- "Xst6eFD4YT6sz9RLMysN9SyvaZWtraSdVJQGu5ZkAme": "PPLTX",
- "CgnZbDNzBfaLyJqUtd4esKLShRp7RznQuwP4uQaondo": "GLTRON",
- "HiNkp9CdKqTgPtB6WnnrrUAu9YwQqnrvT6Ceuxoypump": "ACCELERANDO",
- "12LxMMJYVSf4LoeqjFE47BQQNRciaH9E3nbDfjH4ondo": "ACNON",
- "Xs5UJzmCRQ8DWZjskExdSQDnbE6iLkRu2jjrRAB1JSU": "ACNX",
- "5MAYDfq5yxtudAhtfyuMBuHZjgAbaS9tbEyEQYAhDS5y": "ACS",
- "GEuuznWpn6iuQAJxLKQDVGXPtrqXHNWTk3gZqqvJpump": "$ACE",
- "GnHpRsrcyfHSMZNzmpjAzTFQA26vnbRMzbKQ11ZKpump": "ACE",
- "4rUfhWTRpjD1ECGjw1UReVhA8G63CrATuoFLRVRkkqhs": "ACHI",
- "HvQKzBzp1YhXdqDUrUB8fqrfbJ6rU9CytzscMyG7EFAe": "ACHI",
- "YN4U8xySzuyARUMTNCpMgkkek7nnh2VAkUMdMygpump": "ACID",
- "7Z1SttDgWt9UtcmSPnM9dmXztuiQS7oJS7NaYpJobonk": "COIN",
- "EajMGPYVMzqUjXwnmyagVGDS2CW5xJitb17TpB4uDifD": "ACOLYT",
- "8MxjSs3kEPmfiqKN1S4o3PABp198uYyx4gLF1TvZbonk": "ACT B",
- "6ofzqLnHhobh7cJ4C63rAf5qnKU8AoMxVBi7Kkm6n9wq": "ACTP",
- "7LSsEoJGhLeZzGvDofTdNg7M3JttxQqGWNLo6vWMpump": "FIGURE",
- "GJAFwWjJ3vnTsrQVabjBVK2TYB1YtRCQXRDfDgUnpump": "ACT",
- "E4Q5pLaEiejwEQHcM9GeYSQfMyGy8DJ4bPWgeYthn24v": "ADASOL",
- "4rVf66MSzyjpLLVnGEuFMuVikEfa4XLbrQq2Zuexpump": "ADILLO",
- "12Rh6JhfW4X5fKP16bbUdb4pcVCKDHFB48x8GG33ondo": "ADBEON",
- "XsDZMGEU8zadWFCkTtPBoPWYcUX3JHVmghnwf2Mve2q": "ADBEX",
- "AuQaustGiaqxRvj2gtCdrd22PBzTn8kM3kEPEkZCtuDw": "ADX",
- "7h7FjNZGZ54KJzUtvx2eS9u61HbPX8XZS8WjyQtrpump": "ADZILLA",
- "H8aWzESMpR8drxau9QYi95xPBdFZyFix1n5peFQKpump": "Æ",
- "B16bhVYwE9zQVjbYpnnmvfN7qJFDe21nx5iQC5LJpump": "AEJO",
- "CpEpquNgiGyeMeTBrJJCgMXL8vn1jCkWKVbSurhJpump": "AESOPERATOR",
- "BEP6KhDwv7K211JtZnszNcztHBffSCgRjUuNhucopump": "AETHER",
- "BYt1GhZfiWzynKc7WWo7y8kz38FRkyZyuypWUs6qc4Ls": "AIC",
- "DGNicx6qMPKSL1deR3fZfbHYjnm5ZJWmHNdY2NhDpump": "AETH",
- "Dm5BxyMetG3Aq5PaG1BrG7rBYqEMtnkjvPNMExfacVk7": "ATH",
- "EsirN3orp85uyvZyDrZnbe9cyo7N1114ynLFdwMPCQce": "AEVUM",
- "kMKX8hBaj3BTRBbeYix9c16EieBP5dih8DTSSwCpump": "AFK",
- "2z5VijfstyHnDsvGwMExtvjTgTB1TT3JSf29PRe9MvNG": "AKIDS",
- "6H7NbbGdn2Jo5qpJeHvVECnVMPgD32AfsjcDLK3zjfmt": "AH",
- "DH4MqNmSR7rSY1zLiEaszx8cyDPCNgTWWTm4w8TMpump": "AGAWA",
- "5yC9BM8KUsJTPbWPLfA2N8qH1s9V8DQ3Vcw1G6Jdpump": "AGENC",
- "CN162nCPpq3DxPCyKLbAvEJeB1aCxsnVTEG4ZU8vpump": "A47",
- "9g78Mv7JGsGCmnf7gJiEvVJNAn7fRLqjvJLMRMHbpump": "AGNS",
- "BKgcrCw55yb1ocLS2MnQLT2dSkWtAPjxTanLoWB8oZso": "CLAWLETT",
- "8k1eciW1AN1Bi6bdcpfh1qZn71oQTpNU31gdnMi2pump": "AAXN",
- "BkprZMuBFxWNFz9zhj7qSxZvRndnVKkq5pPQ5sqcpump": "AGENTBANK",
- "6V1vZKRFfu6eimDNk6w4BzxR4UTYxJvt5emuJkxTcMJv": "AIDOGE",
- "CuXmQvh4DVTdWBdC2d3pNq8UXqbKJ3w9RPBTAALcKcTb": "DIRA",
- "HUSTLFV3U5Km8u66rMQExh4nLy7unfKHedEXVK1WgSAG": "HUSTLE",
- "yLUD35WTiPLEY6DUqEj5W2JVXF2DfKB5arPkKJXpump": "APY",
- "8TC4ZJA5cwB5gmLemBfPP95v1Mft82kHGF9a87kepNno": "CVAI",
- "9gwTegFJJErDpWJKjPfLr2g2zrE3nL1v5zpwbtsk3c6P": "USEDCAR",
- "CNK4foXBWtyvNDyh5dk5DsNjsNouiFzdaKD4kHJdpump": "AGME",
- "F86LPriiF5mnqpvaX2UqtKeJAjjSD12EAFoBg4JRpump": "AGENT",
- "27yzfJSNvYLBjgSNbMyXMMUWzx6T9q4B9TP8Jt8MZ9mL": "ROGUE",
- "Ag5mMdBSxm8J893RazD9PGkxWKJ5o3UKdWW4ZmJAey9w": "AGENT",
- "GAMwtMB6onAvBNBQJCJFuxoaqfPH8uCQ2dewNMVVpump": "TANK",
- "D8RaN4ZXKkemC7pyu2noMB8n6ptDPkzuMFp4KfZSpkin": "TED",
- "EgGSqHYuysAEvtP1YxnjcBZNfucT7g4JWzdnURgKSXSr": "AWS",
- "AeAYE1LytXEqX4L8SpLPmnHFePtwhAYSxex8f4gCmoon": "AGXBT",
- "tWKHzXd5PRmxTF5cMfJkm2Ua3TcjwNNoSRUqx6Apump": "AGIALPHA",
- "6ob7KUVQtXMpP1R9YcDWqoYsGKtYhUsSkMC4d7Vtpump": "AGI",
- "8gUcEyfmuFvnK3byAzWALRaKSvgyzFbCwyU2eQ6tpump": "AGI",
- "F9TgEJLLRUKDRF16HgjUCdJfJ5BK6ucyiW8uJxVPpump": "AGIXT",
- "HC1sJQuYAdsjrPeKXeNkJGP9yPpdjpNtngUGhuKMpump": "AGOK",
- "AUSD1jCcCyPLybk1YnvPWsHQSrZ46dxwoMniN4N2UEB9": "AUSD",
- "AGAxefyrPTi63FGL2ukJUTBtLJStDpiXMdtLRWvzambv": "AGA",
- "AGRidUXLeDij9CJprkZx7WBXtTQC67jtfiwz293mVrJ": "AGRI",
- "CZkxnM5PNPak31JSFNzJ76CWcYRu4mgxvBwcHaBJpump": "AI4",
- "HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC": "AI16Z",
- "wUtwjNmjCP9TTTtoc5Xn5h5sZ2cYJm5w2w44b79yr2o": "ELIZA",
- "CANKciNUFnuJfWPc4jxzrPyJaR7gBpuNSyRdd6ULpump": "GUDTEK",
- "DKffyw1oEVWR3ik7q7tb2shhmZ3jbTkRzT6R5banCxai": "AI20X",
- "DvyxUPDrDSLLziu5YsTkyirRDTncqkrWTsUdNCuipump": "AI69X",
- "DS6qJNTGJUz26tjC6G75hGXGA6dvEyyiupS7okhLpump": "AI99X",
- "7bD1RTKSZSsneDXDoMincSswED3uBnzuRyHi5tJ7ZjwN": "KAIA",
- "sDLRYc96bWkJCVgRaR8FTvokw2iSg8bSQrHR7vHpump": "CARICATURE",
- "6W34k5VBA68DXFZPfLz4o8yJgJoiiR4YoQfbtAAZpump": "AICAT",
- "3zQ1XAcbSejFZNdbTBGvFGQatvViYbcwgXZ5pQ3KRRaw": "AICC",
- "BkgPQZirJDceEp82JmguB7WFvomwqMwxdSSM9XfXpump": "AICOIN",
- "217dt9idH1Q9UXT8rjpknnyFggizXUVD2r5EZNjopump": "AICOIN",
- "99ouK5YUK3JPGCPX9joNtHsMU7NPpU7w91JN4kdQ97po": "AI",
- "PD11M8MB8qQUAiWzyEK4JwfS8rt7Set6av6a5JYpump": "AICRYNODE",
- "GbUA2PVzxsVmUNfWkjRSzut4kw4y7mit9S6VRLY2CYC": "CYC",
- "AdJ7FFvw7Yo7LzKbcFuRpNqScLQr54FW9mE5ZatACvcJ": "AIDAOVC",
- "AD8ra3bPosVujHQDofATvPciT1Q9xY4DLEgXbGzopump": "AIDEN",
- "PLNk8NUTBeptajEX9GzZrxsYPJ1psnw62dPnWkGcyai": "AIDP",
- "6Bp9LWtyVXcEATi5nuquX5p1hPGUg1cVoUuXGN9Epump": "AIFRUITS",
- "9vtNLbN2qxPbrx666rP34s9PBGtyLrsupMGdVyqG7FzH": "$AIGCR",
- "2fdtCHuvyLcD2q86XZGFmYbDux9ZbbUgMmFhzChqmoon": "OLIVIA",
- "Bs7diZazUH2PgNyWh7qj3kgUFXqumZpkAjTGSzQKx4cV": "AIINU",
- "Ey8GJs2xgXcGJXjanwzB7qcaHftCa7HwxFBNEHR9pump": "AIKA",
- "2tgZJ6N7buMDq9HZWbzXvSPFq6MYWbrAGCoDD22Ypump": "AIKO",
- "3He53vyEdBSD3Pxx5vAJ4AzQz3GXLXYBvKcYiTJ2pump": "AILIVE",
- "haahyN2RTafHNNySeXKoowgGF7DdX5b5nGNGmghpump": "UAI",
- "FVdo7CDJarhYoH6McyTFqx71EtzCPViinvdd1v86Qmy5": "AIMONICA",
- "4c53VeEq8jVA9EoeGAz9tBC9hhNYHj5quwrMDqEiYxM3": "AIM",
- "4GaCFbxuQ6db8RAepnvvMLvuZCsSmbjZoBwkEyfYLN9X": "AINARA",
- "EiVMQrvdDYK77eK6N6cyh5sGBe5Y1MQWVA7YaURVpump": "AINTI",
- "BAezfVmia8UYLt4rst6PCU4dvL2i2qHzqn4wGhytpNJW": "AINTI",
- "5jpnC4Ty3dhbpjdVKihpF5tTpYN2XfH6Wmn67hbipump": "AIONIX",
- "5QS7RcHfGUa2ZtrovPvEJMB9coqroiT7H48dPSwFpump": "AIOS",
- "29BY5BHtLCG2mamRtC9hh9283U3QkbYLSCwXXmEJpump": "AIPETS",
- "BAEXK4X6B3hkqmEkPuyyZQ5fZUb5iZ6SaJ7a9UDnpump": "AICMP",
- "2w3A2P5juwg234spHKfps7WReWoVmujtErqjaZm9VaiP": "AIPUMP",
- "2jvsWRkT17ofmv9pkW7ofqAFWSCNyJYdykJ7kPKbmoon": "AIR3",
- "128qNYovdGv2YqayErcJgU7gDwbNVX1VuoxbtWz8ondo": "ABNBON",
- "67icoxwiNAVLqagX4kG2cfT9mkSFkwP97kQtgHA7pump": "AIRCOIN",
- "GpdRNotihwXZJ3z3y6yCRAhecFrALc4J8SX92pxnbonk": "AIRCOIN",
- "61V8vBaqAGMpgDQi4JcAwo1dmBGHsyhzodcPqnEVpump": "ARC",
- "4WRh23cmLWCwLgNnDd3V6CLCcMXFDgTQciB9tNejpump": "AIRI",
- "B37KG7jHv1TkhJwe9xTuLuQyzTXvgQjAmBaxLeCrpump": "AISCII",
- "G8mxEVehsoguE8xCYieHaS4r7hU5ioWkLkHYRgKdhdxn": "AISHARE",
- "G5k8QhXrkJuBDvYokADrwvJ27wMWG3x8Pwy3qKCzTidu": "NOVA",
- "g2M4twkhi5uGMdHQS8RbugciyABB2CmngqSUBDupump": "AISI",
- "2wzVMXhLypmP92mXNCq4fuFcd9TCC972AbMfuiH3pump": "AISLOP",
- "9ZFfZwZDfoSqj7HFD7BNGy57XVNkd1BR2UrNYKsnpump": "AISM",
- "D4G7rpcQBF5oVQwBzoDwHPiweJ5RYvuEVGdxqmPApump": "AIT",
- "4ptXaGHy4CcCBfr5SPQZK5bcH9N4njv4LCf1RaJqpump": "AIVIA",
- "7JNdLsAgBMi2WZW26SeifhMNEt3LrLcfM8oBQVT7pump": "WARPER",
- "2KgAN8nLAU74wjiyKi85m4ZT6Z9MtqrUTGfse8Xapump": "SHEGEN",
- "14zP2ToQ79XWvc7FQpm4bRnp9d6Mp1rFfsUW3gpLcRX": "AIXBT",
- "DRoPH9pb1eXQ3VvhwWuP1k5P5R9hkxVmniZCouihxH6w": "AIXDROP",
- "AiXxRGmRc5oDiFXbEeRX9obPpr3Zir7rks1ef2NjddiF": "AIX",
- "Akiox1GAxohWdggSLaFpChxLyS54vz7P7YaF1tckWEQu": "AKIO",
- "GwXvPgGQDEhy71yxjghTKDRsPSgUFwf2s4wkD4Xgpump": "AKIRA",
- "hUoehiMy279k95UeSijKkjx7RUsb676KSDgJ2i3xYbW": "AKT",
- "3swKY5FN4ENQYYJTYqQzGbT7iEv8yD5UngCWfk3fEVA7": "ALAN",
- "s3ghbbWBTtMizNJKGmeMBd1URpisoQJxuDLrheEX61g": "ALASKA",
- "FEj9JuKq7JMLtvZF3EetVNd5ufU2vPA4ZDiVGaUbiRkj": "ALBEMARLE",
- "B5KufqHkskgGYwMXtL8FSHgREAkMQvE3ykhH5Kmondo": "ALBON",
- "HNg5PYJmtqcmzXrv6S9zP1CDKk5BgDuyFBxbvNApump": "ALCH",
- "E5ndSkaB17Dm7CsD22dvcjfrYSDLCxFcMd6z8ddCk5wp": "RIN",
- "3UCMiSnkcnkPE1pgQ5ggPCBv6dXgVUy16TmMUe1WpG9x": "ALEPH",
- "9wvorGtBJ8gyLorFTmwXWcymPoGVUBn6MRzHwFpCdCeC": "ALI",
- "6Xx8p2WmY1Uk2GD35uxhEyuniNrVEeSu3CUThb8Upump": "ALETHEIA",
- "ATygpFdY1KUVn5YLB1CU6L9Xg5Z1FAY9qimtEae3wBLV": "ALG",
- "4b83cYeo4BYfP9NfFUQQWRQYfomJjjChfsV64m5MqifY": "ALGOAI",
- "1zvb9ELBFShBCWKEk5jRTJAaPAwtVt7quEXx1X4ondo": "BABAON",
- "8T988C2a8YNNbppjjd1uYUpmDqE8hLee1tuNokuepump": "ALICE",
- "HWrgYyGdivwuxV2ePxbk6vwkrKYqMa7is9fYMm5kcQWY": "ALICE",
- "GfkfESc5A4EkxCGWsymNY4ZfkCDdvtB7ajCybLfYL1Qq": "AOC",
- "GCSfrFVebzoJ9kK5jh8TGW8oJwWeN1n618F98ycLpump": "ALIENS",
- "65YnRAiThkUda2czNFXVuMaCTiNpiq3LLLWbtGTLpump": "ALIENS",
- "HPgsCBk6gkTw5FFPYc9WeeBU8EU2Ye1AYmeTYq5apump": "ALINAINTEL",
- "F3nefJBcejYbtdREjui1T9DPh5dBgpkKq7u2GAAMXs5B": "AART",
- "a11bdAAuV8iB2fu7X6AxAvDTo1QZ8FXB3kk5eecdasp": "ABR0",
- "ADNScivK6Pt2XsfsufuyUiZaKbRww5JANDvZ7texDid1": "ADNS",
- "HyDKNdnhZNVYQMruBevbNsUWruA9STmAQrS4srXApump": "ALLINDOGE",
- "5EaYZcaKfTVdpQ2avVtJ7BNWJ1Rnj86F1dWxppawpump": "DOLLO",
- "8ZeTmGGktvSwSSghx8btbTAVGdWogThKM4DQBJgRpump": "ROME",
- "9pCWprxbZMW2rYSMhPTeoyLMV2sN2WJqshdT7DQVt6hS": "EURAU",
- "Ai4CL1SAxVRigxQFwBH8S2JkuL7EqrdiGwTC7JpCpump": "AWR",
- "3Sf6oKCeEqCuco4aYtKHHDTBYLAWHiL47QjvkW1UYDEG": "NOTHING",
- "7gASrhXxE5u2oLASrAsZh3SAJrgSjKhb4qTe3FsqHTKb": "ALOKA",
- "8XtRWb4uAAJFMP4QQhoYYCWR6XXb7ybcCdiqPwz9s5WS": "ALON",
- "8ThSrRA6qpkva4bGE6DNfFKnuKuCPM22Db16zS1Mpump": "ALP",
- "FfgtU4bMte3JRZGX7kcNVywxiGoSqUTga8eZxTSFpump": "ALPACA",
- "8gJAaxa5YkrDpXRF6qw1fHW5nxM8sCUkQ9WfXasgpump": "ALPACO",
- "2zrH2jE542mzB4HABgBjdWMQPtNC5H12pwo1iLpfpump": "ALPHA",
- "2sCUCJdVkmyXp4dT8sFaA9LKgSMK4yDPi9zLHiwXpump": "ALPHA",
- "Cg93SZJkHePybZqGDuyXLf5Ag5sB2cpWfHUG8wNPpump": "ALPHA",
- "bbahNA5vT9WJeYft8tALrH1LXWffjwqVoUbqYa1ondo": "GOOGLON",
- "XsCPL9dNWBMvFtTmwcCA5v3xWPSMEBCszbQdiLLq6aN": "GOOGLX",
- "3wtGGWZ8wLWW6BqtC5rxmkHdqvM62atUcGTH4cw3pump": "ALPHA",
- "CotWkXoBD3edLb6opEGHV9tb3pyKmeoWBLwdMJ8ZDimW": "AIKEK",
- "FC5oim6UT5Zw1D5S5BZzMM7NQdzyuaSsGef9RT6Ppump": "ALPHAX",
- "Dst1UGBW312B8FbxWuxyPjZ82ALrLvRq4zzS8MnMpump": "ALPAY",
- "aqQRs3UJmHs7ktoLo46HZAzvG9P3oCoZ41nENqFbory": "PIE",
- "FwzpNxnabjZvc8QCnV6qPEBKxqLxSyjobc5Etdgxpump": "ALR",
- "Cdq1WR1d4i2hMrqKUWgZeUbRpkhamGHSvm1f6ATpuray": "ALT",
- "12XvRbmvA3AY8La3brnQGcMR5HBp7Cn3Fxc5kKiQ86FY": "ALTSEASON",
- "8m9fjYycXAFva1kScttQgsESVZT7yELhjZASqfHBuMa5": "JOWNES",
- "Trj7guTUcpDFqkycDzvMNjwRN1W4fYtsxSYbj3veBsP": "AMATO",
- "14Tqdo8V1FhzKsE3W2pFsZCzYPQxxupXRcqw9jv6ondo": "AMZNON",
- "Xs3eBt7uRfJX8QUs4suhyU8p2M6DoUDrJyWBa8LLZsg": "AMZNX",
- "XsaQTCgebC2KPbf27KUhdv5JFvHhQ4GDAPURwrEhAzb": "AMBRX",
- "amb1bbMCnsnMgXfqj6JK359B8T23FijFgiLQiCrd9FM": "AMBIOS",
- "9jaZhJM6nMHTo4hY9DGabQ1HNuUWhJtm7js1fmKMVpkN": "AMC",
- "C9xNaNujcF1a5fidWAAFReFYqhLRVbyk4yPyGqzondo": "AMCON",
- "14diAn5z8kjrKwSC8WLqvBqqe5YmihJhjxRxd8Z6ondo": "AMDON",
- "XsXcJ6GZ9kVnjqGsjBnktRcuwMBmvKWh8S93RefZ1rF": "AMDX",
- "kh35nynonqA4VYaoeAvn17ChrhMrWhJ26EbCayKpump": "AMELIAJAK",
- "8TuHAfTBTMW1fJNq5bNoeX4zhk2492DNsCgVSYzApump": "AMELIA",
- "2MwD89A8xuCpaiDqBsDEHe6rANhPou8PPKdTo7ETpump": "AMERICA",
- "4SkFDZZ1SxSw3M79ohRPfmdxYKKCd21hxQnhYeWNpump": "AF",
- "5GfXzzdxUZ4QEwwa5hhBMEazFSp9EhtYvm8RFLxrgyVc": "AIB",
- "9wYZetvT8J2ptfsRca5gzLBGvcUug38mp9yT3xaondo": "AALON",
- "69kdRLyP5DTRkpHraaSZAQbWmAwzF9guKjZfzMXzcbAs": "USA",
- "1WxT6NdK7uqpfXuKpALxL2n3f7Rq61XXeHA8UM4ondo": "AXPON",
- "XstYR6KGqZFchAuhHoEe4mL8W2kL9aqGW1EDBKRrmGB": "AXPX",
- "7ea3ifsARjj2TeuPgScj5fNENpVodU4vXrA8yQcH8FK2": "AI",
- "AoR5LncBpmpv6WwxCqiEM96Z9Lwiim2bSAyZAHt9MudA": "AOR",
- "39zSVsSHFqNhARbVh6n8ZF78nCmhV3gSg8D39xhBNe73": "AP",
- "4aQ7cA7vnfCQ8opcNBRarRYcm6Mnwioee74RXpMHbonk": "AMERICA",
- "9S4gfoHfA9Tt7tJka4dqKDRDS42uQDMAQMLDraCb4mfE": "AMERICA",
- "F9NydCB1rDB4orWsEwenXmT71ZjmuRDsqLcYL2Fgpump": "APC",
- "2oQNkePakuPbHzrVVkQ875WHeewLHCd2cAwfwiLQbonk": "AOL",
- "Hxai4E6xQdtQJXZJTfs67mdFGfF22y78ut9heLHpqUSA": "US",
- "SS6AEWhzRrxhL2cXzKKjhFt3rCzmHHGKmFyugDTondo": "AMGNON",
- "AY1Ww6MxwC3cCiyrandHqLrp4FXvzgcwQTZpJ2FEpump": "AMIKO",
- "H7ryQGvGeTFT4L6zVjwmombQPZHJ6nBbr1PS8tXytime": "AMOURANTH",
- "4CmYCPDzU22ck8hT6AiPVk2iTHg9SeYtPCXZNuonpump": "AMURICAH",
- "LmTMwmZLNZszn3qpjmnbhfP12U4qWDivaEBwSBSondo": "ADION",
- "7iT1GRYYhEop2nV1dyCwK2MGyLmPHq47WhPGSwiqcUg5": "ANALOS",
- "6d2Wze1KMUxQ28sFLrH9DKfgBXpUJSJYZaRbufucvBLV": "LOS",
- "93RC484oMK5T9H89rzT5qiAXKHGP9jscXfFfrihNbe57": "ZERO",
- "GYPxyPtu6g1NmnEPPkTcCdSZz7ZMs6A1S3wTjnLdpump": "ANARCHY",
- "EZGb7aaSbCHbE6DcfynezKRc9Bkzxs8stP97H6WEpump": "ANCHAT",
- "DVzrCErBzydh92bBzSJX1dKwVvb4omwhrvNz8CwRyxxV": "VONSPEED",
- "FdwpkZZs78rUJPRMavGqfFDujYmCbxQFLWqupY5Hbonk": "ANDREA",
- "7ekB2w3Rsxmg2YSL6axUHLmHEveJUbxBHRxmDSfX6ray": "WTR",
- "PresTj4Yc2bAR197Er7wz4UUKSfqt6FryBEdAriBoQB": "ANDURIL",
- "93n51i8anR3ziS6kxqXEACjrvJoXpAxt3qbbo3eaRFRz": "ANDY",
- "69P4cjVxSbrGfks5bcAC5yJGwRBvyeZ9exDmhoVCitVT": "ANDY70B",
- "667w6y7eH5tQucYQXfJ2KmiuGBE8HfYnqqbjLNSw7yww": "ANDY",
- "GRkAQsphKwc5PPMmi2bLT2aG9opmnHqJPN7spmjLpump": "ANIME",
- "B5cteji7DaRFWfY16BZeGhWMTaeX7RX1CokhbhCzpump": "ANGRYGUY",
- "9tqjeRS1swj36Ee5C1iGiwAxjQJNGAVCzaTLwFY8bonk": "ANI",
- "5nvNUh3ZU2Q3AJmD5YP8ykcUSv2P8C4Z8MKt5vmTpump": "GUNS",
- "CQkgAQg5qCor8UMee5s8SzGkpjoYxCxrNzUuhwAnbonk": "ANI",
- "45DzrxKPS4Rgerk7u6gBCB9iikF4gYVUtYE6GXbDdZkj": "ANIME",
- "AnXE9mZYWReqBw4v5HrY2S2utt42uEtcBGmuCXASvRAi": "ANITA",
- "4vqYQTjmKjxrWGtbL2tVkbAU1EVAz9JwcYtd2VE3PbVU": "WYNN",
- "5su44fkvYNM1WnMCgteXu7HFUywQBtKZqjwgmCk9pump": "PENCIL",
- "HqVZaYJnEcmKQKRf4K5N8eEuBjkTgpRzVfF7AYBFpump": "ANON",
- "D25bi7oHQjqkVrzbfuM6k2gzVNHTSpBLhtakDCzCCDUB": "ANONCOIN",
- "8VJ51bdE3xorQ1zB7FEa8CsHdM4kw77xCFiCgbnL2qbT": "ANON",
- "CrMwppXm5kQEbXPGNH45ASkQyRbd7uonD8heVQsEbgSA": "ACC",
- "FhvBDEr46meW6NHWHNeShDzvbXWabNzyT6uGinEgBAGS": "ANON",
- "94WxCtGPFYdyWQ29VmqYbX6y7xbpUteHtX3Mak6Jpump": "ANV",
- "6n7Janary9fqzxKaJVrhL9TG2F61VbAtwUMu1YZscaQS": "HOBBES",
- "HAs8hvTB8ZH6dBG26KQGik4fxitNYi41jnYd49bvtime": "ANSEM",
- "BfHkvKMEYjwPXnL36uiM8RnAoMFy8aqNyTJXYU3ZnZtz": "ANSOM",
- "ANTT2Ve8c3JC6fAksFxUGtByzEHmJs49EupP7htA5W7j": "ANTT",
- "7VnT8zHzorYS92snKC4CZU2veigEVnVVBSxTw7G1pump": "ANTS",
- "Pren1FvFX6J3E4kXhJuCiAD5aDmGEb7qJRncwA8Lkhw": "ANTHROPIC",
- "DGNm6z68D9iagDgjVNiSfadmyLT7vyNejDJ9jyy4BABm": "925",
- "9rTrsxzcDRMKpBHsbmdMkfPsU6K8FHepcyp43Dr6pump": "ANTS",
- "ts3foLrNUMvwdVeit1oNeLWjYk7e4qsn8PqSsqRpump": "ANTIRUG",
- "HB8KrN7Bb3iLWUPsozp67kS4gxtbA4W5QJX4wKPvpump": "ANTI",
- "BYdxrskh1HfVfvAd8a9aAjoLAU6Bo97AgN56gDwqpump": "ANTS",
- "G8s88jzPhiKdfCmwTKaShErB2VrbrsvDsDBzsXqjpump": "ANTS",
- "ACeWC77UeW2DBZMe7YBsuXoxLvk4dHMnPzneApau1Au6": "AI",
- "5fj8KkMfofVY3LmuLiYdxS7VprhKoLCwek57UzYYdoge": "AOGE",
- "2b6evX4o265k7MAU5QtTsw3G2g5uz2SUbAVkFr3gbvB2": "APARTMENT",
- "Ghp84ZTWgJhATi9UwnTSqzedihUsvup6Ejwiz4TaEA25": "APED",
- "DF5yCVTfhVwvS1VRfHETNzEeh1n6DjAqEBs3kj9frdAr": "APE",
- "984GBL7PhceChtN64NWLdBb49rSQXX7ozpdkEbR1pump": "APES",
- "ChNrhBZwGtn1ZRsrdzcuBqiKTYfVViCPZqJdsgBHpump": "APES",
- "KdF3kjqSHbWXFstBLA2dccDxuNBi4o3yZqtMhB7k5dZ": "APEWIFHAT",
- "6rE8kJHDuskmwj1MmehvwL2i4QXdLmPTYnrxJm6Cpump": "APEX",
- "51tMb3zBKDiQhNwGqpgwbavaGH54mk8fXFzxTc1xnasg": "APEX",
- "6k1rwsNMBwbRJrWck3sEVCjn4MvF9ty8A6iSGfxjxREV": "APOLLO",
- "FubtUcvhSCr3VPXEcxouoQjKQ7NWTCzXyECe76B7L3f8": "ACRED",
- "14VXAhoa1R74vi1ZuiQyGLJrnDMfoFBPJSCpGVz3ondo": "APOON",
- "acatzTjUeHDT3SoufN6NMxGUmBFtoqFHnFwusdw8kYX": "$ACAT",
- "123mYEnRLM2LLYsJW3K6oyYh8uP1fngj732iG638ondo": "AAPLON",
- "XsbEhLAtcf6HdfpFZ5xEMdqW8nfAvcsP5bdudRLJzJp": "AAPLX",
- "B6WqvLGXdGqpw7qgxeb5EGiRZEYo2apWpQybjYuondo": "APLDON",
- "7eRX747PSbVtGVx3qD5UFdkNM2BfTy86ikUiCMhondo": "AMATON",
- "14Z8rQQe2Aza33YgEUmj3g3QGNz8DXLiFPuCnsD1ondo": "APPON",
- "XsPdAVBi8Zc1xvv53k4JcMrQaEDTgkGqKYeh7AYgPHV": "APPX",
- "AhPo2fs5cfUyDhG7cvR67wwKg9UeFsF7mng368EB4oCn": "APU",
- "ECutGg12PNhqhkvnH1s1FcuXgCDzKDNhSf5aLtANioR7": "APU",
- "26s3UGB9hund1qspApy1zYgCritxAooGg7o63BMn89Yq": "APU",
- "5JnZ667P3VcjDinkJFysWh2K2KtViy63FZ3oL5YghEhW": "APYS",
- "5EkcKr582FkAPVnRmaDdnkekTtnNRzNNSxmQxqrFpump": "AQC",
- "C49Ut3om3QFTDrMZ5Cr8VcTKPpHDcQ2Fv8mmuJHHigDt": "AQUARIUS",
- "5mXAnC2LWxvNF6und1Mokrv4WnPDP9uxzRsyWATYpump": "AQUA",
- "BFpchrNVhyTRzMNAg9QkiZfRN2vqRBwcYoTX8qgkbDvm": "ARAB",
- "EDcdVtzW4HG7Xtg5yH3RbzMEyfudg63RmZgdXpQFUk3s": "ARB",
- "KcCVQxG9LhFYP5o9DWFKTFgFShPPQkDEemVbiFyondo": "ACHRON",
- "4VdSpMVR2ehiL3SNQyehEY3WwX2YhhpWa9HHMfBbbMeW": "ARCHIVE",
- "AdxNrCntq6YkYC2qVffF2Fw7WC1UatKhV8J6G4ekgNx3": "SON",
- "9XRpjZjhJPeWtUymiEWn3FW7uAnMeQca14ucTWWWyP2g": "ARG",
- "EbD3Qptmezx1mEwMfa88q5L5CrA4QrBwmvvZUhEapump": "ARGUS",
- "GhBPHgnNF99EThYxt4bxUfPX1hCPyAS72RCBgLjLpump": "ARIA",
- "GhFiFrExPY3proVF96oth1gESWA5QPQzdtb8cy8b1YZv": "ARIES",
- "4ZiYgt9nyPXvSfBWADGYHiWnTdnogrFgLTALdFWVpump": "ARIE",
- "Cq6QtvHpXbJWtFaiMhUDtHy8YVZ95gcD1oZ1cohondo": "ANETON",
- "HZXyLwwoxWHnnxfwFnQSTTBs3ys1xJsTQG8CzhUnzray": "ARISTO",
- "7ztJWBzawnLB1UeEC1zRiyuxqhd2r3oxYYD2ouKVnBLV": "ARITECT",
- "3VTXWW93L1WRfQ7QDPjvfBQgzFRVqDgHPnc8vwQmEpUi": "99CENTS",
- "Cph1zxsCUz18v6aa2hiUYwfVkSV7BSFHmCaJLqQspump": "ARK",
- "15SsCZqCsM9fZGhTmP4rdJTPT9WGZKazDSsgeQ8ondo": "ARMON",
- "ARMYZt71GXq4vw4mtDs5LnEp4ZgwWKEE2CdMU3WNnFEC": "ARMY",
- "3Gdx9LmKZJyciSz3mbge3YKLqskiMG71m1iDMPAwpump": "ARMY",
- "Cwe5k2iEy8dt7vCGY93GBrqQS4FWyac6pQjvjLcPD6qp": "AROK",
- "5RDjKNvXqs9Y5gkrThtCfpicZYYHs9MK7HhdXdUeaBLV": "ARTI",
- "EJRs2ephB8kZX1w196DBt7q3uvLAVqs6LEVgXEwhpump": "AGI",
- "7JH1tgtDjze6miPsFV3THUFh1r25JYUHdZsM6q9xGqZ5": "AGI",
- "7tAnusL3srXjzEriVL86a23KgwDZKXJTZ2ezEUubonk": "AI",
- "pGmqZA8iruRh7dtRH4x22cU4H5wPPWsJUA9h9vapump": "CLAMS",
- "61h3Lyt4BtD4g5YqztbHPUZE742sPU1kG3bfMxLpwWaV": "ART",
- "ATRLuHph8dxnPny4WSNW7fxkhbeivBrtWbY6BfB4xpLj": "ATR",
- "7rJp1KhptfCXd6K46bQzaGRYYUboyPE1u6fzEYBKffZB": "ARXIV",
- "9DMD8SzXwGLsUDbmJmMza8cEZLLsajZQvZ9tWWKepump": "ASCIIVISION",
- "45ZAM7JK8ZGHuBQiJ8kvhdiVdiQGsTQGgt3gRAEQpump": "ASHA",
- "4Uf883orBx89VQZiV4EoRpNqUWYN5ZuEvC4PCpQ9moon": "SPLAT",
- "EG6WeiR2DymUVVjNHEU4MEJXmWnzXJhk3JerRy4gpump": "SNAIL",
- "1eLZPRsn8bAKmoxsqDMH9Q2m2k7GMNp6RLSQGm8ondo": "ASMLON",
- "XshuHQ6o6SVpUNawvnnTMxsZ4tacZsNgVCLorv7TkFq": "ASMLX",
- "12XbSPVc5hmWjKUzf5ExTysM2pEL3tM953YkMXmLWkGd": "ASSAI",
- "G3EDZoS49NRVKP8X1HggHZJueJeR8d2izUHeXdV3pump": "ASSCOIN",
- "7Tx8qTXSakpfaSFjdztPGQ9n2uyT1eUkYz7gYxxopump": "ASSDAQ",
- "ASRRjA1R4RHVk5H9QKKm1jaQqMkxvv6nh5EypPrvwmxQ": "ASRR",
- "FRUnVTbSteDWYmn8URfsJkHYgfu9MDxjz7vwYj4fpump": "ASS&P 500",
- "FLxwDc58Fnb9h1Yq6Vc7YhXjFPwzZadhLPJpUHGMjups": "ASSTEROID",
- "HzN6MGRCi4QMpAeqvKnqsDDodAq2LWNdxSkPHnCpump": "HERIA",
- "Xs3ZFkPYT2BN7qBMqf1j1bfTeTm1rFzEFSsQ1z3wAKU": "AZNX",
- "8GQa5N9HJT5tW6vg3umYG5us1xHmiU948LfDihg2f8Vf": "APX",
- "B6ry9goGNvVbhq7gWHzs3p6emJ1gLaMhu4By9TTondo": "ASTSON",
- "XsR4LAtaBgTKTRUhiijY1ba13nx4bepeEcag2Pr4dZ1": "ASTSX",
- "DNMTk67urDBxEEVRx9HjVzCVu8en4Kgg5HfZy3E6pump": "ASYM",
- "9ZDghDhVrJih39y98dADEPKL9o3WLwXcLoks4Gvqpump": "ATNA",
- "WKMZummev5UcXz5nNKQZvTD6QjNSM2X58uwmDReondo": "TON",
- "ATSCZA9yeRDoLQQMTiiKDF2gW1gkFtzNaRr4tQXYVz16": "ATSCOIN",
- "Kkkhb2uaCYwXoTrWC7CMPLa7T5UsbVVeeiQXrTSuZUT": "ATTN",
- "FVGdJQVzAdKr8ZH7ahyhp4cvDszX3N8QYGSdzueopump": "ATTN",
- "XsqML71RLbyUM3CmY4EYN88zE6BJkpvJACnUKBdGD3x": "TX",
- "AT13ipG8K4HDyEJm3H1ZVQV2Bw8sihewoLQReSMsYo3o": "AU79",
- "9LzCMqDgTKYz9Drzqnpgee3SGa89up3a247ypMj2xrqM": "AUDIO",
- "5EoNPSEMcFMuzz3Fr7ho3TiweifUumLaBXMQpVZRpump": "AURACLE",
- "4rwPNRSFgcS7EGphFdX7VwXuhjZGxph7gYyb7Zp2pump": "AURAFARM",
- "5eTuF52LmxisGfPPhZeiUkBPMdTkF3WfF1w5P5FUbonk": "EAGLE",
- "DtR4D9FtVoTX2569gaL837ZgrB6wNjj6tkmnX9Rdk9B2": "AURA",
- "CMkj12qHC9RjAUs1MED38Bt7gfyP3TbEpa1mcBno3RUY": "AURA",
- "9tF4vuYRQY3d5GPnE9pjUevukgo6vHiepe3E1w8Jpump": "AURORA",
- "bozdUuCb2kdipxES9PzsYHmDVrf7FBTSW3p1CFBpump": "AURORA",
- "3YmNY3Giya7AKNNQbqo35HPuqTrrcgT9KADQBM2hDWNe": "AURA",
- "AURYydfxJib1ZkTir1Jn1J9ECYUtjb6rKQVmtYaixWPP": "AURY",
- "9h5y3WCqfeNt2fiAP7iM2ZRp9apFb58ipvTzcWi9pump": "AUSBAGWORK",
- "BkVeSP2GsXV3AYoRJBSZTpFE8sXmcuGnRQcFgoWspump": "AUTISM",
- "8jiVXftnn2ZG6bugK7HAH5j2G3D6TpsG521gqsWwpump": "AUTISM",
- "6QbkqyarW5ET7TvNsENGmV7e4fg7SpACdYb8ba5Ppump": "AUTISTA",
- "9QRknyCszLEmzgfEHuW4v8cygf4Hu5Dwc1LjgSaRpump": "AIT",
- "8QhSMvYfXome11VgxFMD75hNbGQXW5QTnjA8khENkY2c": "ATM",
- "Ez3nzG9ofodYCvEmw73XhQ87LWNYVRM2s7diB5tBZPyM": "OLAS",
- "GNp2Vzrf5VfjA1vRF7MyzpcC3YfF8LEiJLY7rNsRpump": "ATNM",
- "6d5zHW5B8RkGKd51Lpb9RqFQSqDudr9GJgZ1SgQZpump": "AVB",
- "DKu9kykSfbN5LBfFXtNNDPaX35o4Fv6vJ9FKk7pZpump": "AVA",
- "H1vAwYTZkL2Bq8tpS5DhC4pPJjhMLviH2ScGjuePpump": "AVA",
- "KgV1GvrHQmRBY8sHQQeUKwTm2r2h8t4C8qt12Cw1HVE": "AVAX",
- "63rvcwia2reibpdJMCf71bPLqBLvPRu9eM2xmRvNory": "AUI",
- "HdYskPuX5cBApzGqFtoyKdzLxfsLCQxucQfmX2FiquWo": "AVIAH",
- "BANKJmvhT8tiJRsBSS1n2HryMBPvT5Ze4HU95DUAmeta": "AVICI",
- "GdZ9rwHyKcriLdbSzhtEFLe5MLs7Vk6AY1aE5ei7nsmP": "AVO",
- "EE5L8cMU4itTsCSuor7NLK6RZx6JhsBe8GGV3oaAHm3P": "AVDO",
- "9R6qezCXoY5fX8nC7SA4bZ1zHrwG9WnnKVGt1SRoMGF": "AFK",
- "7f94zk1EgfoeG57Vj5FtDDjMmPNHM4DYs7KRiyd2T4bA": "ALMC",
- "Dr7r38EvuFzezm9FhHgVw6eaPjGNRaj9JMAknAprpump": "WHITE",
- "ovutZfkUMXRBEH4hAXJE42j2GK3Az9ZjTdbG5taWoKe": "AWOKE",
- "9tLUnDz6G2dUGVhiLEEEpfM8e1YBiXnWrdT4xVeopump": "AXI",
- "HHf2VfXSPUVqQth6tXypfdUX2vawCiVKfkbAX4CJpump": "MAXIS",
- "4TaBYbgQyErDQx67rJRnbABd2tqHCzBvMN1a2M4vY8fc": "AXYC",
- "5JP1Loni4DtDgvHupQAzcRXQtsWnWWVibdsD4igVpump": "AYYLMAO",
- "CCEDUV4wfDUog2Lb4o1vA9Wpzz4WXn7fqf5zsW46XuS9": "AC",
- "387y7v7vPvCguwmsuN56QuxankZdES97ExqSp9CNpump": "B",
- "cBnVXDyZgaaLZM18wAmqsUKnRUFAEJWbq6VuUoaondo": "BTGON",
- "Bpn193geWPDvWW2po4cr5hpudLha8LeZYngmWHh2bonk": "B33",
- "6dEJEuFvaD8jMyotbvbMx7ixpP2frXnZCSgDexwqkE6B": "BABA",
- "FhrFGKvx32aSJW4tdygWnjEs8wKnD4FzxyjezBLg6sfE": "BABYAG",
- "HkrchFiWgRuPTdmNvqrPRLANDdeuuCTQERaB2dJSpump": "BABEL",
- "5hmf8Jt9puwoqiFQTb3vr22732ZTKYRLRw9Vo7tN3rcz": "BABY",
- "FjtQhyaGmYioRKA3enZkq3wVXLT121DwQ24W9d5Vmhw2": "BABY",
- "8467ssuj6Gkw15ABv6BvxJAKnGJALXJu6dxDxt4upump": "BABYBTC",
- "Dx1Lq5FjangW5ifRMEogAiakm24LyB5AoHmQifepvNjV": "BABYBONK",
- "7dUKUopcNWW6CcU4eRxCHh1uiMh32zDrmGf6ufqhxann": "BABYDOGE",
- "9ceEjz32cv8jBcqsppgjrryiE2tor7PCm7j9mYk8gzTk": "BABYWIF",
- "AnUmd399EDCEmoXjSpUAVWE4TcyT1xFMJcPgAZ2VgChn": "BABY DOWGE",
- "3Bbj7eZTuMd2FrfeZ2degzckxhgB5b63crGoHLtrpump": "BABYFWOG",
- "F4aLcMxQy6CPcXAuER3J5QgB89n4fqBMs2bcrqQBpump": "BABYGOAT",
- "8uSFaAvg2BHZ3QYAnkshoi6AxErPJvJG53NsjKjDbonk": "BABY GROK",
- "HpLfPx1NkMghAEVq6d2nv84LiZt4nKvGJ2aRiUFno1DX": "BABYDENG",
- "Ey2zpSAJ5gVLfYDD5WjccbksJD3E9jPFMPaJ8wxvpump": "PEPE",
- "z9ysNwXCYrh4xXRyQG9ujWqxNrdcChoicoJA9ebd7iF": "BABYPNUT",
- "83xejQ2QoHWD47REppszZPbvkzHUyem5SSkjyXBFieoC": "BABYPOES",
- "Ej9jJDCD85mZysgorrY582Vpv7HLgDyi7Fa2jRCjgscZ": "BABYPURPE",
- "Uuc6hiKT9Y6ASoqs2phonGGw2LAtecfJu9yEohppzWH": "BABY",
- "8nKP8Vc72pRZB6bhCy8D1UYf6ZjwYT859i6awyinpump": "BABYSHARK",
- "5Nu2hLo3ffU4fs2yVtsCvAT7ymysuYs5NSFRpvLMVSBi": "BABYSHIRO",
- "8MdkXe5G77xaMheVQxLqAYV8e2m2Dfc5ZbuXup2epump": "SINCLAIR",
- "bsAwuVJMPAazbQSVpPQND69mvwftQutZhxpWqsf2BUE": "BABYSOL",
- "54meDtup2K7pqyhUK24AymoLzMPtrkhNTbEzQ6gSpump": "BABYSOL",
- "13RbxjgWhXhgSN4krVwadunLSAJjph7b9QFU4GWEpump": "BABYSOL",
- "HysNUGUyrapf4A9AtkDz2JaAHCQKmv3rsGV41mdVpump": "BTRASH",
- "M3NC8TeMfosXhHLZC26BP8Et2h6ozcCXYF18nx4pump": "TROLL",
- "7xAinob3Fmi6Sf1zA1kUDkuSuBh4KEVtuKqL6WM1DWKr": "BABYU",
- "7pmuGLLYdJ2mc7chZwEJAaxuWALAYqaVqbUwzzyHcA7D": "BWEN",
- "8sbaCMtqUKHwmPkBfe1m4u738u4MjvTCDbRXLDjppump": "BEET",
- "BPxxfRCXkUVhig4HS1Lh7kZqV6SPJhzfEk4x6fVBjPCy": "BP",
- "BPSoLzmLQn47EP5aa7jmFngRL8KC3TWAeAwXwZD8ip3P": "BPSOL",
- "E7MYzWD8GtLYNsgRyECSts2p1s2mu5JLb6wR9CiCBAGS": "BB",
- "EW7cWbNmTgL7PLQNiJ6tBVC62SJzJXa2pFYJjDPPpump": "SOBAT",
- "57Tfcj7Ak3qpBKQQ2k5LTrsJLg3csDdY7Q1rC6y5PumP": "BADDIE",
- "8kp7gVCTWVbNP257A7MHgsYheshqYGnqWbApS6f3pump": "BADGER",
- "777Z92HqqGEav312yx8CfakajosBRFFUMbemyLaqbonk": "BADRUDI",
- "GvkxeDmoghdjdrmMtc7EZQVobTgV7JiBLEkmPdVyBAGS": "BAGLESS",
- "HMaJxXp3Ja81jSwigF6zGaMt79hNZuczrw6i7LjTbonk": "BAG",
- "7Pnqg1S6MYrL6AP1ZXcToTHfdBbTB77ze6Y33qBBpump": "BAGWORK",
- "54CoRF2FYMZNJg9tS36xq5BUcLZ7rju1r59jGc2ondo": "BIDUON",
- "4tViJmZ7LKREaqxrh3tXeCB5TfK7o67W3WhykHrr49ZC": "BAINANCE",
- "CQbXk942c6GPcRwtZ2WMFP5JcQ9NqbXtb8jUewBi7GoT": "BAKED",
- "Hz4CJCpZky4YD75Zs2R2nBjP5wY6tYbraaT2hVZCpump": "BAKKT",
- "FqnqT1GKi8S4Gyk5wnSKvJjXW48HqGtKJt9WS4o2pump": "BAKSO",
- "BH4TZqN9TXnkjiLEQZ9xuXo85YaGoonM4PHpcjHEoTAx": "BALN",
- "31ovHdpQJTMrmxwiSRWpZQ6oY3AP9wu8RWZh8adepump": "BALLIN",
- "6BFPDdf7VdkFdzePjWzVENzgigzs1DJmZJhKtjiTpump": "BALLSACK",
- "4yCuUMPFvaqxK71CK6SZc3wmtC2PDpDN9mcBzUkepump": "BOF",
- "xN9Qd63mUYg7npanmdksmcqp3NQjTcGFQPTyq2F1TQC": "BAMBIT",
- "5sM9xxcBTM9rWza6nEgq2cShA87JjTBx1Cu82LjgmaEg": "BMBO",
- "CWY3XDTbN91sSmg4XR3ZgxAVgrhiFv4Ue8gUwwJLbonk": "BAM",
- "31GUGbRSct8MsJJnditGy98xMxowq58sFsZ9CGQRMLT8": "BCAT",
- "Co4692bPPQXAqqxSLAeTTvF1bnhY26FUWt2YuWQPBgfU": "BANANA",
- "FuQASH8ps9NPeDu4h3rVtMBygKYoSiSTZ4uSiA5tpump": "BANANA",
- "4ytpZgVoNB66bFs6NRCUaAVsLdtYk2fHq4U92Jnjpump": "BTW",
- "BMocPvavt5CLXvJpQohTRbg17WhPMfkFxibHEQpSpump": "$BANE",
- "8SVVCGzYwnAkDwwvc5fSHZdCenUyhPccnGirWecVpump": "BANGCHAIN",
- "HmRpmbeGosahTzChmTmKzFHR5SmgSgXFAXKumajgpump": "BANJO",
- "k5AMg1yUxaYTNXpVDpkrVn8VSgBe9K4t1pQYVCzbonk": "BANK",
- "Wk8gC6iTNp8dqd4ghkJ3h1giiUnyhykwHh7tYWjondo": "BACON",
- "XswsQk4duEQmCbGzfqUUWYmi7pV7xpJ9eEmLHXCaEQP": "BACX",
- "EecSMXvvhszENGs7SAWMejLgBHBAhCvkMDWY88JR7hog": "BANNED",
- "BXFD1Dd1AT87MADC6SYZ95QQQjrTKEnDRwvVhAiLpump": "BANKSY",
- "BANXbTpN8U2cU41FjPxe2Ti37PiT5cCxLUKDQZuJeMMR": "BANX",
- "4bXCaDUciWA5Qj1zmcZ9ryJsoqv4rahKD4r8zYYsbonk": "BAOBAO",
- "7Da1f2wibgzZZheXnVvqYgbWpccnGPM2CJPUkdcebonk": "BAOBAO",
- "UHaVCzi4ZsGrzHhAFbokkXfaugfYbkdVME8XYaR7eKu": "BAOS",
- "6Gci64E133ZSQ8VCMrfWQb9ekVNAwHzRobqt4vkjbonk": "BAP",
- "8Ga7ExC7toM9v1PqCB8jjKRTKqiYqQGLCua2VnXdbonk": "BARKCOIN",
- "3B1ijcocM5EDga6XxQ7JLW7weocQPWWjuhBYG8Vepump": "BP",
- "Em4rcuhX6STfB7mxb66dUXDmZPYCjDiQFthvzSzpump": "BASED",
- "275K6a8XzouqPaX3Ue8QaafSL5kw8dL1E1g8jwHzcmpL": "CHAD",
- "8Y5MwnUM19uqhnsrFnKijrmn33CmHBTUoedXtTGDpump": "BASEDD",
- "EPeUFDgHRxs9xxEPVaL6kfGQvCon7jmAWKVUHuux1Tpz": "BAT",
- "6gnCPhXtLnUD76HjQuSYPENLSZdG8RvDB1pTLM5aLSJA": "BSKT",
- "EtBc6gkCvsB9c6f5wSbwG8wPjRqXMB5euptK6bqG1R4X": "BTC",
- "C3JX9TWLqHKmcoTDTppaJebX2U7DcUQDEHVSmJFz6K6S": "BAZINGA",
- "Bv2AYefUcEe8StuRAAsvGLyeB8fkqVeEUVvYAiPApump": "BQC",
- "coqRkaaKeUygDPhuS3mrmrj6DiHjeQJc2rFbT2YfxWn": "BCOQ",
- "BCNT4t3rv5Hva8RnUtJUJLnxzeFAabcYp8CghC1SmWin": "BC",
- "CqMybyWjNGn2FGt1JY5HDUGMiCpQjAsyj44csfMUpump": "BDC DANA",
- "BMBtwz6LFDJVJd2aZvL5F64fdvWP3RPn4NP5q9Xe15UD": "BMB",
- "FdFUGJSzJXDCZemQbkBwYs3tZEvixyEc8cZfRqJrpump": "BEARCO",
- "PvhC1i1uu1xmB8bsaoTj3mLf1ihYdQo7MtVQebppump": "BIB",
- "B7sn8nJZtGSQzR7dUwSuLALGWMG16PmASRTqC2Pspump": "BEAR",
- "EGedTSu2zdFNT1k7phURksCpcwHNyxepLzSMYGApump": "BEB1M",
- "brBg8x9yT4WnQd8Z43aX7wfrGMrimLfT2WCWRibHo3d": "BRBTC",
- "B2BsVuodH2eBGRnFckRYYW6yjur7Tn8cCxaSE2Xrnj5V": "BEE",
- "BeemGmKYvz52af2myrx7xE82rE8ZvW9MgpvX8ikJQZNe": "BEEM",
- "9sbrLLnk4vxJajnZWXP9h5qk1NDFw7dz2eHjgemcpump": "BEENZ",
- "FHT57nzPTw6FFk3XK2gjFsCvxqYWbh6qM8dEiGK7pump": "BCI",
- "GCKTFLxkMeUTUbuQM1k6f1cy4o4tC2V13ye2ebL3p52r": "BEER2",
- "AujTJJ7aMS8LDo3bFzoyXDwT3jBALUbu4VZhzZdTZLmG": "BEER",
- "2Tr3i2qjSPUb7e7BSFWTq7gsRzJEnYBKc7wRAYu3pump": "$BEFFAI",
- "FdzVFSP9KX58GzpJywdqhAmADr3XTEypawHyenShpump": "BEING_AI",
- "CQhbNnCGKfDaKXt8uE61i5DrBYJV7NPsCDD9vQgypump": "BJBN",
- "CP4w2B3og2TaFUpye1kr8pdeJwwahtESKppZnffN9n9d": "BDX",
- "GT9SetU8UWKJeCQsmMcNHH4pGPVSKrxgQsgu2wtYmZHW": "LEAF",
- "HoQYRCnUeyZZyFiPtYDw48kHyGwjsaUXJxDVtxcK4yPg": "BELIEVE",
- "5tRLPc3JsbMh8QU7EebaPvTpExinXNA7B7R9MQcijBLV": "PNTH",
- "2GPJhV9jNrj7TaLYMRgWkcy6sTKLcwntv7nZ7qDyMRGM": "BIS",
- "EmhVWGUa2Q9PN4QjzFjvuVyzFKg4s3ERwjKR9dQDpump": "DTF",
- "H1pRLTGu9Q3Kv6ziV9DCvTxNQA2vAVocYuGb41wZ1FBk": "BPAD",
- "4PYijC1Xas63cxdoYnUg7SQgcg23UgNNcPmvbj6KNUSz": "BSCREENER",
- "92kxUXDsBQLy5ptGxtmH9CDYd5E6ZQynzf2eFPiUpump": "BLOB",
- "5bp5PwTyu4i1hGyQsRwRYqiR2CmxyHt2cPJGEbXEbonk": "BUMPER",
- "AuPMJ2VqiJd6gd2e65ALYhpSctzCYancBYLG5usfBAGS": "BEL",
- "5xL15htnLsMN44DyUQyztEYSFBn6pgF41cngBkKMpump": "BEL",
- "E63CDwLy9Dwr3EptAzopV9RuWoQnn5ZVYEjLWnJX8dCw": "BELUGA",
- "HFtLLofzSqJUP5Hk96jyrBjyZq6PcUjfSA8AbKoopump": "BENHAM",
- "BLVxek8YMXUQhcKmMvrFTrzh5FXg8ec88Crp6otEaCMf": "BELIEVE",
- "AHW5N8iqZobTcBepkSJzZ61XtAuSzBDcpxtrLG6KUKPk": "BENDOG",
- "FTdkGcfFUDcXbqRQL3YeLYJa3e3Pnaz6kJH1sBsapump": "BEPE",
- "5kkkNahbYVYZUQthCZCU6ax4zkcN622jAMTnAvJApump": "BER",
- "G8XfMyCLW82Hq2duaf3Kw9hQXf9ntLsPvSx8qZhZpump": "BER",
- "Xs6B6zawENwAbWVi7w92rjazLuAr5Az59qgWKcNb45x": "BRK.BX",
- "HgBRWfYxEfvPhtqkaeymCQtHCrKE46qQ43pKe8HCpump": "BERT",
- "FQMoiNiQGLngizBVdhxqD1o2k6rvcX9ComxjKucgBByH": "BESA",
- "8f1zccZPpbjz17Ay9wZKT5Mx2oPtUyxAVz5p5yzEbonk": "BEST",
- "93EpfRSroBwD5DmDBXkaCdLZy8nnShtrVCLMCXjxpump": "CULT",
- "CKrVUhFFKxjBshAWHE3ZkiPiBTkN3CfrMfbdWBH1pump": "BETA",
- "A6jBzMFsrxGEi2s8SDejWHojGu2j2RF7LvwTD2NTpump": "BETA",
- "A1r1SooLp5GHZoAWmY3BErwByYoCrV2StAiCEa3epump": "BRUH",
- "7uJrMsDN2Wxdc3VAq1iK9N5AHaTA7wUpbm1wqRonpump": "$BETH",
- "5XgpGK83mxVdcGuZxv7My99ZmuSzdJo4noLaaD4bpump": "BETLY",
- "5CLSw4viyMLfnRHHxZpDF8CuZt5e1ceq1AJqd4GjAJNX": "BET",
- "BMHkAMoj2B8VUPPfEkops8XqPgN4oJkjR2oFRpRG2oqL": "BETURA",
- "7gsdvvoREQbKesWJCDCb8reeM65yQuQDwT2jcH1JUG9V": "BEZO",
- "HUhmmhEiT8H969TS775PiF9w3sDyHgBYkMjGiyMQpump": "BEZOGE",
- "57Wdx3uikKcAt2w8F9GMwgGeEvkaU6pXacYScW1hpump": "BHAD",
- "3W52uCb8NW8ruMF9mmJX3oKiYAjdPai4633srsZFQCS6": "BIAO",
- "2ru87k7yAZnDRsnqVpgJYETFgqVApuBcwB2xDb19pump": "BIAO",
- "7UiTAJhzDcqc5CvVAUWS6sUyeXcQWUXuh7zsbUrNzb8K": "BIBI",
- "4YuD8JVXFeyeowJacXMLY3QKhd6NwaJhto1Xqrnwpump": "比比拉布",
- "GkJxELgJXpQRm7dfc2yS18vBDRxP5SjVJgbrmTGgpump": "BICHO",
- "FT6ZnLbmaQbUmxbpe69qwRgPi9tU8QGY8S7gqt4Wbonk": "BIG",
- "YXE7mph6XhsgnyezkMEcTuohSuWhbLWfwx2Hh6mondo": "BBAION",
- "BhwwEnvzsEdncGWdDZv2airsw1HZVbRBBGfYhgZfpump": "EAGLE",
- "ATBR4i19gcQ31Rfr7ymA2XvkCQEAkNFGBtVKTmdqpump": "MACHI",
- "FAKDHD3GuHMvHmgMPgFKNknZJDEnGT6AQFipaQ4ppump": "$CHEUNGUS",
- "H5gczCNbrtso6BqGKihF97RaWaxpUEZnFuFUKK4YX3s2": "BDE",
- "CeK6k4BMmiqkxkzYAbQuUp3hrVFSHxuQ1LJXmNybc3vz": "BINK",
- "8U5SJfExR7QMhPWWKLFV5F9L8mX3vioEP29GxocBpump": "BIGFACTS",
- "4mswMCYRz4ifCPh53b48ecXJvwurCJRqMwKSHuP4pump": "BIGFOOT",
- "HbACvu9eKjCJE7h4oGFSnX6fvbDqwugRGYeuJebRVBkR": "BIGJIM",
- "CX9YDTED9TWgVXVoFy8JL9gSSAEWcTv4mzjLSv17LQsj": "DRUGS",
- "FtrH7NCrPDkhDmKCCdTnsDBFxiibc1X5aJPHqKQnpump": "IMERA",
- "14kLsQVmc64qZexYuR4XGop9y8BeMkd77pJUm1Rhondo": "BILION",
- "A94X2fRy3wydNShU4dRaDyap2UuoeWJGWyATtyp61WZf": "TRYB",
- "wCtiCRJz69a5Mqkk2nHmvQwBGQCrUvM8fELoFGqpump": "BILLBOARD",
- "BDCs2xEqzXyRpp9P6uPDnAvERpLKBfzHPEzbe3BfCxDY": "BDC",
- "DdWVqFmdQpyjdU3AeUSEhrsnJQBPH7iK9xdCFrBgpAy2": "BINU",
- "5o817YNoR97F1h5suzBghwc8dP53oureRuFbgJiaCFuZ": "BILL",
- "3B5wuUrMEi5yATD7on46hKfej3pfmd7t1RKgrsN3pump": "BILLY",
- "9gP2kCy3wA1ctvYWQk75guqXuHfrEomqydHLtcTCqiLa": "BNB",
- "BNso1VUJnh4zcfpZa6986Ea66P6TCp59hvtNJ8b1X85": "BNSOL",
- "4ysWSPRkmqY6Y99SN86D2MBHXrvnR2358SaGb47Fpump": "01001000",
- "BeFtLwLtS9Rva12KrHKRMY1H5WoeM1Y2ULMnNJKopump": "BINDER",
- "ABc1BqTSZEwZoZr6kJUyUCMQTTxWSh18DyK5GM4Spump": "BINGUS",
- "AQuuQ4xktyzGBFnbKHnYsXHxsKVQetAoiPeCEG97NUJw": "BINGUS",
- "DMYNp65mub3i7LRpBdB66CgBAceLcQnv4gsWeCi6pump": "丙午",
- "9hfajwF4pPRtLG1psEq5s7yBCSieKkUXGSUrvJXXcmcH": "FIREHORSE",
- "7dxQE4YXrWqtwUVb8W8HjfPT3t4H4dWZfsDWRWKupump": "BIO/ACC",
- "2xU5oEz6w8iHyLyarGiMdeVYTTyR3uJTgvZdzMYYBiok": "BIOK",
- "9oxGicd5KXNcthYM6yD23X9zcznQVnHjrAEN38fFpump": "BIOLLM",
- "bioJ9JTqW62MLz7UKHU69gtKhPpGi1BQhccj2kmSvUJ": "BIO",
- "qcdogbnRfbhadxEjAwRuBoMJXPPt7z2Csm8jjtbB1Po": "BIPO",
- "2EBjqPYGLUExdWwJJRLqtGPawzb2aMjE1wTpUYKhy2UQ": "BIRB",
- "3XTp12PmKMHxB6YkejaGPUjMGBLKRGgzHWgJuVTsBCoP": "BIRDDOG",
- "EUxS8Kqvbe8zDr8bG1RYtgjVNzEhMTG6B6H3WwrCHfwA": "$BIRDFLU",
- "FTPnEQ3NfRRZ9tvmpDW6JFrvweBE5sanxnXSpJL1dvbB": "BIRD",
- "4NTREQyLwcxYddh6TmmiwQt55zvGtngCLyYDBJQ8pump": "BITBONDS",
- "BSkz8QHwk1DaT3Dcf1L5vWsCRzgrfrLR3qYmwSt1rtUM": "BITCAT",
- "3XFiHA2gexzBjqtM5Z7FjJhP6f28D2m79UihBCfkpump": "BTCAT",
- "4j9bDg7iWNah1Qa61rrqwWZMtEdqV3fV56SzyhfNpump": "BITCAT",
- "78KiD7Y4rWuKQeyfnue9ayYNTzqxXvv2DK4bBj8Wbonk": "BTC2",
- "DL9sLSN488yMbots3wsbzHZ3UpKSkM42kr1y13CPpump": "BOB",
- "GTiMaW6FNPLrWNVLYk5KkLApxiHvCwbGr9KdueGypump": "ISAAC",
- "6WNva7iLjTvxSfXPSmbjceW5Yc41LUH4SJNqKom5pump": "SASHA",
- "F1Tq1a8NVJfgimf1dDyJivhFxah4tT82fMvFJn5Xpump": "LOBCOIN",
- "G9ivB7K41a4G8m1k4QdxxN4L5eGKL7Mr12S26B85pump": "PIZZA",
- "7dGEYMPsAVxJY3qQJaCHwLPkCCx9SSE52H4k1wF617uE": "BRRR",
- "8jbjDAUAvXuh3tGjqCWUve71rWd5QEbgjYwsuq5npump": "PIXIE",
- "5Xc1AycwC2ENTDWwGV41twqCyKkeoAfjnqLGMKKd7ytX": "BTM",
- "JmQCbJEiPBDkvfjDLPBRxeuR4QXX8JeRiMQvUSppump": "MIM",
- "8sv4W4uQ9qML87Kr2XFkYBDwsiFEJVZZ1ScsM71Hpump": "BWAH",
- "GiSC3EA7C2kZwESb53cJybcmeRRExM4gqzV5UTz9pump": "BTCWIZ",
- "F76Go1TqbZwnG17BhbQMovEJQHnmXuBBHAjGd3v1pump": "BITCORN",
- "FSqH8gHUdt87mwJJm8figSz8kJyLdietRcPwDcfopump": "BITCORN",
- "CyyhLNKtLrJ3ckVZkvytBW3TieAaAz7P6qsJLChDNfp": "BIT",
- "XsPLBFy59Q3hY59KLAJur8QyvziMF4xUxGTxXqXE7cT": "BTBTX",
- "aiddowDsfMxaxPtVmmmnaX9B8DNzM78YypD84dVra7B": "AIDD",
- "DR5cCdABB5sZjyVF7i3mestghxGzvHawQk35sP9QFNjf": "BFBTC",
- "XsHt1AVPshZpfFWGGpooJ8tdeGknUQVJ9CwhvKrnZrw": "FUFUX",
- "bgSoLfRx1wRPehwC9TyG568AGjnf1sQG1MYa8s3FbfY": "BGSOL",
- "bgJWGuQxyoyFeXwzYZKBmoujVdatGFYPNFnv1a6ondo": "BTGOON",
- "XsvHMmbDcd14DHHW16PkxPGW7ks77ehxUv1E9Zmxgj4": "BTGOX",
- "2XEm27fupa295SSXpmD8coakcFpCJn3huMsH5V77ZixP": "BTM",
- "MYXqkDYbzr7vjXAz2BapR4AiYRXzoikGirrLoRzondo": "BMNRON",
- "XsrBCwaH8c46xiqXBChzobgufRKxQxAWUWbndgBNzFn": "BMNRX",
- "ErSZNwsamWjR9Hj2o18GLwVyTkooyGbdptjMjuv72X8A": "BRISE",
- "63SRKBw34MJtwKevMgK6GXBJgj5MQFsn8fgrQRvR1wof": "BTSLR",
- "ASq6BSBLc9sj8eg33eDyhk8xssq4zSnetrM5zTtUpump": "BITBABY",
- "7ePhsDXkpPJs6rPM3TQScpbgonzKUPo9vuQr8GXMMGpf": "FTW",
- "9xsF8KqQn7E8cwDS3jL45rZNDQJsCKatHgYH1KV1pump": "BLACKBALL",
- "2oCxjpWWEmCuNaXiBSVahUKP1xRMRAiBfCg98YyHpump": "BLACKBULL",
- "J3rYdme789g1zAysfbH9oP4zjagvfVM2PX7KJgFDpump": "BLACKCOIN",
- "Be6a7UZT4k6yUgQibJczPat8C2qGujEAoje7wY7Pgegr": "BLACKCROC",
- "DjgujfEv2u2qz7PNuS6Ct7bctnxPFihfWE2zBpKZpump": "ANGLERFISH",
- "i3s1iZgKxLNs39S9JDceHmFtVhJH1WFZHkGNWFUmoon": "BD/SOL",
- "8dmHzuMkdssGeycyiJFDhkmeuViLBn4GNdH8w6qkPp7i": "MIRROR",
- "Hz5umnpTrCjXNUrZtZAdviEfmXDzmaBZiQefVdb9pump": "BP",
- "D7yP4ycfsRWUGYionGpi64sLF2ddZ2JXxuRAti2M7uck": "RACKS",
- "5H1VpMzRuoNtRbPTRCz35ETtEUtnkt8hJuQb9v7ondo": "BLKON",
- "GyWgeqpy5GueU2YbkE8xqUeVEokCMMCEeUrfbtMw6phr": "BUIDL",
- "Xs5ywCCaayf3TFdxFxuJCr25XMoqY6vdfJKkSHE4D6r": "BLKX",
- "3jyiXJ9zi4B8j6EXvdH6pCKTJsYHWvzN5nY8Mecbpump": "SWAN",
- "8TVr3U85V3Uazkxd5DJbmzdUWaxhQdEGNNGJ7eNTpump": "TULSA",
- "bSo13r4TkiE4KumL71LsHTPpL2euBYLFx6h9HP3piy1": "BSOL",
- "A1t2UviBYwyfYZDJyKY2W6Td8ritgsCriUDuNaAQN49S": "BLESS",
- "BLiFF7FoZrs9AMnZnn8dXn89wybGiFgQtpRDqMsdLQF": "BLIFFY",
- "AbeDBXvqGnmcvX8NtQg5qgREFTw7HynkCc4u97xcpump": "BLIND",
- "2mESiwuVdfft9PxG7x36rvDvex6ccyY8m8BKCWJqpump": "B402",
- "b1nkm6skdrwXoMku8CVx8Fk4LfC2jAqxV3m9VDNjYqz": "BLINK",
- "62CsquahdQ3J286G9UTqV6whxryfihdV4yg7kSJnpump": "BGG1",
- "DgG9sM56ZcVidBV8bNArQPm93a2rmjzHkrrUntGSpump": "BLOB",
- "2zwuFv4tzMrJMA3Gq5nNH3i4ojWPtCkjmGzTMXe4RpMc": "BLOCK",
- "6CcuCL1LESQqTznT6wi9kjLPnAZs6b4GM1D1GeS8pump": "BLOCK",
- "BF393sQtcNVrMEY3jLDuho5eTEyMjqAfuQ4o1jZ5XcHq": "SOA",
- "NFTUkR4u7wKxy9QLaX2TGvd9oZSWoMo4jqSJqdMb7Nk": "BLOCK",
- "9JJdWb2y4K1V1aHZJeZdiyScfHWGW3cLF1XNGDd2pkin": "BLOCK",
- "BWxe2FVciUbwrCUZQPUKiREBh5LmVa5AiUqNLAkondo": "XYZON",
- "F1By3oDsf4YY4WTNAMznXwsBgGt7KBQPFfoMA2BEjups": "BRS",
- "FoRGERiW7odcCBGU1bztZi16osPBHjxharvDathL5eds": "$FORGE",
- "CsZFPqMei7DXBfXfxCydAPBN9y5wzrYmYcwBhLLRT3iU": "BLOCKY",
- "9TwGzR67b7pVjhiDZyHoYk5ynYGLaCG3hezKXK6642US": "BLOCKY",
- "GiUgtv3NiUteADLBUg2Sc8Y2c3d3doYLpnZkagZqpump": "CHANT",
- "4vKEwZ2ZHmHFuQEE69emXV2Zq1EKeJYVCESsMqydpump": "SPERG",
- "6xdfpmgALwfsnFcXUtiwSxdbH8Y7ew16UBaxKEmspump": "BLOOP",
- "FJnUYrGfdb9386ybtwjUt3i63c3KxYBANeg2iionpump": "BLOP",
- "71AZt4P5kc5vpfTJR1HjNbMzD84G7vxam4DtL3kJpump": "BLORMMY",
- "CFB4Ff7W87uN9Gf2DSj63L7prZycJvzQeg1MbGxwBcqC": "BLOWFISH",
- "B1rGc4HM4Q6q4nU78ADM7fGguxqiasH53fh6ViDXpump": "BLOXX",
- "myrcAs6bpP2g5oGHZ3qpgrfZQAFkbo9KUHdqYDXMjGv": "MYRC",
- "2u3ufZ5defxwPXMixvvQpSs68PDNzHTdE52t9Crspump": "BLOXWAP",
- "GEJJkUe2MDSsRg64iJBdKSRdsuo6V4kdUzrgyPogpump": "BLUEBERRY",
- "CmAtKbUSM2HErtaQmonrxiV7qXo3mDganWw9KEimbutt": "BBC",
- "676k7xHRPBxEQ1NsjEKHBtGqRHr3gPev3JBje3VApump": "BLUECHIP",
- "DHJVYXsikcimtcVo49FAZqYd1XPYPaXezYhbKArJbonk": "BLUECHIP",
- "CWQVqTKuH1iU8zSfFfvaUXaVzLzqU1E8GYU5d6EcGBNe": "BLUE",
- "jcztDWkrkxyMorbBVd4Amm7PbGHafCLMN94aAKZdrug": "VENOM",
- "VjMa3mzfBgCyKRTQHg8pSuZRKCvKF8zMqVXQMU3pump": "BST",
- "kub2QX17qMx6jLuyG5gR4kSmmbiRtvUHt4gxqNd4wZB": "WHALE",
- "ERuVbcuTrs3UCQ64391JfrpVdv4JLkqABCiZNujxpump": "BLUFF",
- "6h1ACr3LWM1YgVqxwcqEVJtHA2ygT8Z7tutYMy3gbunt": "BLUNT",
- "7qpKH1bkvoZPDGbtmjHa9opCGnzfeycD34iuDrJBpump": "BOB",
- "bobaM3u8QmqZhY1HwAtnvze9DLXvkgKYk3td3t8MLva": "BOBAOPPA",
- "48yNDqabAvGNfnkhadsV1MAvtp44fFDdHBRBdFhvpump": "BOBBY",
- "2XYgocKz9MvkNVVyj85kdM2VxsUwrJeQUZVD4qmD4dYT": "BTC",
- "BoBBYtpE2kpAJwh5TPPky72KND2cWmtdYa63bqo2yiKs": "BTC",
- "nnt8dZU4ZSiPXUdcmku4VcJFmhp7SsNDipzBKSppump": "BOBLS",
- "ArRRiz4XsPbLXNCUWb2dqE85hPxD4MtMhec5jaJMcW5R": "BOBO",
- "Bobo54AXWLGQWqCK6EZdrBQz4bKJXeBE9ExD1HJGbXed": "BOBO",
- "2CzW1Z6zGqvVHTfF9yeKFsgR5Swq6D2ySETXHTiWpump": "BOB",
- "2G4i17fv5oCYbPVeEccV4ZZuM1VeJaxoRjRdmF85Lcef": "BOBUKI",
- "9EbJs7KsoWqAoUPTtcYf1kVyvydQgoxcvcitSbcUpump": "BOBY",
- "DGMARinczhSb64n9ezNxrPLbcfcftYom9xZo94LVK8PN": "BDGSTRAT",
- "BqLQq6yXT4i9W2geFiq5aaPks67FywEnXEbdFG9fpump": "SCANAI",
- "1YVZ4LGpq8CAhpdpm3mgy7GgPb83gJczCpxLUQ3ondo": "BAON",
- "GMEhF4sFXd9PRR9KJo7hyPjeHdcdg5yxTNP22KKNyWvZ": "BOGGY",
- "9zxKFBkFVcyh46r6pJNjZTtFwFZMuJFqrXsTDn8Lnw7c": "$BOJACK",
- "1KSpDNUbFmE7uB662rCEVVD2oxsW45T3w9EodeX7b78": "BOJI",
- "CQ6VXxQYD1nH1SobagiQDbhND3SLEKhqSxHCPaavBoLD": "BOLD",
- "6P7emJG6eErTv8KZhxRJDsFUdLxrx4eKs2td4B4npump": "BOLTAI",
- "DfMuAxjpKMb1bi3Wn1kwGaA35HMLoBUdTfwzeDybpump": "AMBALABU",
- "BjCmA9ZYwJ1BwusMGaSxe4pgaa9gfXTtdyX27NYEpump": "BONECOIN",
- "3MrwYcAvGNNtMcHwscSqFQJ3qhMpKwxZCbprYrz1RYWi": "BONER",
- "EchesyfXePKdLtoiZSL8pBe8Myagyy8ZRqsACNCFGnvp": "FIDA",
- "HnJ1rwyEZcSMWjXQX4XruLFWqmqquGdXn9zJsRakQFex": "BONG",
- "9Es9ttvHj9UUHwyy7QLEPBTyJatYo2FbkuHcQR4cVxJr": "ASK",
- "HPJALtLtydXym5Tbv6udQCKcXSihnz3B7aD3PNMNbonk": "BONGO",
- "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263": "BONK",
- "Gh9AcyeZezm5DBvVpG9eSwN1pArtFGNU9q7RzLKkkQ8n": "BONK 2.0",
- "6yiDKPDbqWLGAEBkDvVg6UNrKsLsPVkLbA1TJo4KCdzP": "BONK2.0",
- "GMLEFvNsZ8WgZuewxVqdT2reNgABdfVPnjWsjmm6bonk": "ARMY",
- "BEyp5W9oQosUDD2hPt2Qeg6fuAkNUbnvR6ZJhD8Ybonk": "BONKBOY",
- "D3CVUkqyXZKgVBdRD7XfuRxQXFKJ86474XyFZrqAbonk": "BCT",
- "CKfatsPMUf8SkiURsDXs7eK6GWb4Jsd6UDbs7twMCWxo": "BERN",
- "CmJWm7B9JrqA5145bCqXMzVDbGfdhaJfVCt474Sebonk": "BONKER",
- "41ffYTdG5r9oyPqVaKRPC3rpawLwNTGQ1YTTrdnRujg7": "BNKRS",
- "28iQookNbPzdd135zBqmPmMbWfy9kH6p8sbz7nU8daos": "BONKFOLIO",
- "E3enwdJowhDeRe3f7mMwAZGVkJ5aWEtPUGRusP2Jpump": "UNIPCS",
- "6fHPh6b1WrfoS8f6ZhoziVhNBzTs5LCLnAEtnzfMbonk": "BONKHOUSE",
- "BP95AFpABStmiAo5En9a9RXXQoqq5xKSfdaNu2ETbonk": "BNKK",
- "6q6tqND6J8fPpAf2VNbFYLuXKVgbPC7BUbPjQTyrbonk": "SAVIOUR",
- "5Htub56zFC6gyp4UKKjEb21JTSrWheHbNwbxmXedbonk": "SAVIOUR",
- "BonK1YhkXEGLZzwtcvRTip3gAL9nCeQD7ppZBLXhtTs": "BONKSOL",
- "BgQ2Tj4y4YQume4guQrkK8RWB8oRQtHYtAta1tXubL1G": "BIF",
- "oha3mwwm2tqWRouJ2KGUiz4Vz9FCRcPm1fApm87bonk": "BONKYO",
- "booe3XGMztBMB9RhCgNodhJQeaaMmhdGehMCVPMGza2": "$BOO",
- "9zqre5sRRdFvKqyTyvEd1jcKDRF4g47s7mZSGUnQpump": "BOOB",
- "CEvvz6J1NAxyE5uYBdWNqjMVMKCy7wSu5VVaBDN9pump": "BOOJI",
- "XseQvfvuDT3KHKiwPNW1gcjfHbFjEMVTV5NJzDdNQmu": "BKNGX",
- "VvgeRQNHRHdYubKC9K2GN567LXTzSVcB7mpu7b1VF4r": "BOBE",
- "ukHH6c7mMyiWCf1b9pnWe25TSpkDDt3H5pQZgZ74J82": "BOME",
- "3dCtyq4JBQJpRq5SX8mzkXFHF7BxQNhS49CfNWy4QBoK": "BOOK",
- "7jmaTFBooHkaSrBJDftu3LcK85KPtqWTCaFZCDxQV7ZW": "BOOMER",
- "2HrZ5R18H48b8ptL3n8N5zX65zDB4o2cMCHcP3QfSfye": "BOOP",
- "Gx2yQqgguqpKwGCrrgx4dr8toTYevczEtGd6B1pKpump": "BOOP",
- "boopkpWqe68MSxLqBGogs8ZbUDN4GXaLhFwNP7mpP1i": "BOOP",
- "JmMRbLcKgNCu17yHZDAn4strE5NjmWJ4pCeJ7s7boop": "BOOPA",
- "7fodN5Vn21kZdGfvA178ZNctqsZ2kCGVRHfFNEkboop": "BOOPI",
- "2wP76beSJ8NB8bgFEkZkQCGtWErxqkxTYEGjx9jYpump": "BOOTSTRAP",
- "bootyAfCh1eSQeKhFaDjN9Pu6zwPmAoQPoJWVuPasjJ": "BOOTY",
- "F5hqdbykXuksp8P78CAZenSvpPShAYKrP2U2MiZMdgFN": "BOP",
- "2kATD4v94ahnHyB8rHywAdLUwWAWAiDq9heMqmVEpump": "BOPPY",
- "BorGY4ub2Fz4RLboGxnuxWdZts7EKhUTB624AFmfCgX": "$BORGY",
- "BdN2AF7h555TiTpxASirVBhG21dwcr5VNCcnW2BJbdG6": "BORIS",
- "4jZXkSNgTQKCDb36ECZ6a2aNzcUniGcDeXgTdtM2HxAX": "BORK",
- "Fn8UCBRMAAuK9ivmUv3Fzpxz4McnuqS8CKS15jQrpump": "19",
- "Bv2ajiWdngTyRFabXCKiwGDJh5SEfJwoRPkkTQ2uf6EE": "BORPA",
- "BorpaZo2RdiYcriLJu2GRefZdgQPmv63nA8jsVVsMV7W": "GORPLES",
- "5h5YCbybHMpVj378FrxrypY9eXKoy92Vpw9xyru1pump": "BOSSU",
- "BYZ9CcZGKAXmN2uDsKcQMM9UnZacija4vWcns9Th69xb": "BOTIFY",
- "76SYfdi8jT84GqxuTqu7FuyA4GQbrto1pLDGQKsy8K12": "BB",
- "GsKuLQsKCEnfQxuk4icTEQjc11Av8WiqW31CxZqZpump": "E𝕏PB",
- "6TcoT3vcexjsMuuLvS9DhBUrVVcoqBMHEppQGQLMpump": "BNTY",
- "H2yHLoC24dM5v1Vjh2Poqx7fZ9mp8EfR2MYseXScpump": "BOXABL",
- "9cLx6w1fN6b67VxsGxaFaCTgQcNqsA51p4uMWdkgQqmC": "BOYS",
- "BoZoQQRAmYkr5iJhqo7DChAs7DPDwEZ5cv1vkYC9yzJG": "BOZO",
- "EJPtJEDogxzDbvM8qvAsqYbLmPj5n1vQeqoAzj9Yfv3q": "BOZO",
- "BW8ejBnHKPGBZsQN6aoGdR83Vccrw41KD34ph3nfbonk": "BOZO",
- "E69gzpKjxMF9p7u4aEpsbuHevJK9nzxXFdUDzKE5wK6z": "BRC",
- "evsoXvNK2RG3ZBUWjqwDzoLHWhUjJbWdMrMza2Ppump": "BRAIN",
- "8NNXWrWVctNw1UFeaBypffimTdcLCcD8XJzHvYsmgwpF": "BRAINLET",
- "APoM2sXUzdRHTkUjXSsdUheX1wPPdP4HFLotmtRNMU8P": "ROT",
- "BeMn2NsTi9Pg34MAihvWfqAq2vkBtGAkpQMs5knppump": "BRAINROT",
- "7iX4yQ4zTraFSRXEGpF89emA9xGrhgv6jX57dMENpump": "BRAINROT",
- "HoBmCAQp75DHEPvhHqttPUuBTj29K5KRoM9naCkSBAGS": "BRNRT",
- "GKgNhpLxCEmBSQgiGmPGswR1QU2shSb7wCApC8KbRAN": "BRANDY",
- "BQDMYwgnWr9UBcUCvLX67yXriTVe1bkPEiTQ1TzKpump": "CRUMBS",
- "8tH8YMg2h1TigY36iPX33UG8dsm7tff13yo9WSbApump": "BRBR",
- "FCMvYCULu3EprrFQBVnCuDaii7gdacSCsFHi6uwhpump": "BREPE",
- "XsPHkGBbztHCCe1RMhiAs7CxVqoghmyd6zDUfrbfVWG": "SLMTX",
- "DxtssVdyYe4wWE5f5zEgx2NqtDFbVL3ABGY62WCycHWg": "BRETT",
- "DXBYAw9aQheMdujaLZYnVSpKSK4n8jMS7HfLbiv5RWnS": "BRETTA",
- "F6ExBzKdLRcJkCAknQgfbhRXX78EhqoNxPnegJWPpump": "BRETTGOLD",
- "FxVxbhxq4xqAjSjVCsYNFHgVr44hF5i5CnSTpgNvpump": "BREWSKI",
- "Fv73EXJBRfctJzLVC3P7uQP6er6JU8b4KtDr4LQFpump": "BRICK",
- "86Qzt4Dpx51pYGj7TscfEEBbTspsnQJQpNQxodm6pump": "BRIDGE402",
- "HaP8r3ksG76PhQLTqR8FYBeNiQpejcFbQmiHbg787Ut1": "TRUMP",
- "BriXYhFVy3aXLiuVUfeG6ZMwHvifJLtxSuS5zgozDnAJ": "BRIX",
- "1FWZtdWN7y38BSXGzbs8D6Shk88oL9atDNgbVz9ondo": "AVGOON",
- "XsgSaSvNSqLTtFuyWPBhK9196Xb9Bbdyjj4fH3cPJGo": "AVGOX",
- "6h5QZc6MoMyZL471g2K5WCyQVpBaeh8AhUXGK6fTpump": "BRO",
- "CXXed5DrpgNVPfyMzjTMeBarcCe2c9VTBpU99cbJpump": "IF",
- "Ga4oZoNRLkZkruJpS8NLwa8DJCwKP9hbTBSNDQZ9V43v": "BROKE",
- "DAMqxQRG5FKsnMNXEdBQMdTSiz86b5BziH4p6FS6pump": "$BROKIE",
- "4MPD7cGs9746SkZnqhfRigNmpNq17EgTt76YHKC6GEbN": "BROS",
- "BroodjAHbyJ5eisR17AZ5rEvZFzACo4Pk4Yx4zm6AnQ1": "BROOD",
- "DdEWen5QEDFZmBJLscgwY81mbZLNZ642zMuR5YLVv8vH": "BROT",
- "33rVymHHPxfMvg4EHKBRF3h8a37cG7Et3eQWZzAkpump": "BRO",
- "7ou4W7LAkm2QyZWrfsCA2U37bbQ1MCrETCYxHdpFpump": "BOG",
- "7C5SPivzYtk2umHScjLXN7WZnstLFf1r5TCsMNaTpump": "BRUTE",
- "BRUV9DjBeDZRamtWjhzQEH5roosnBApPhfqS1HQ23Xgy": "BRUV",
- "HibC3jm1oq2jVzMR2NSX7xdCNnsGLQ13yK8FEkmhpump": "BRUV",
- "FtgGSFADXBtroxq8VCausXRr2of47QBf5AS1NtZCu4GD": "BRZ",
- "6xbPNG5m1PPJh8ts9B9zxeqgjkjkgdbxxJp8gJqpsEFK": "$BTC25",
- "G3T87339h7sw7NFDnYRko9mfeqP77vxnF4eEbQFbBAGS": "BTCDEX",
- "BMt3pq4g8ggWWBnd6DJ1jhVyTkHfWjAfJwWW6sRCbQJv": "BUBBA",
- "66Vd315STLu1MaiJkgAuryYB5konVAehDkJeqZTZpump": "BUBBLE",
- "FQgtfugBdpFN7PZ6NdPrZpVLDBrPGxXesi4gVu3vErhY": "BMT",
- "BQQzEvYT4knThhkSPBvSKBLg1LEczisWLhx5ydJipump": "BUCKAZOIDS",
- "Asuu49BSxjz4Qj9hkdrwt3GpxdjvYUfbt5rXnsNWpump": "BUCKET",
- "H7w7UWLkUs1pJG2tfr6pPz2eyxurga9NigidDk1Vnnzd": "BUCKY",
- "7hZmPPkBDYbFpvzQW54sX3DQHQjEVsVcCFRWsvCdbonk": "BUCKY",
- "3iY5ZSkRnevSMu4h8nZyywyeY46osdmC1LAosmv3pump": "BUDDY",
- "BHX4SUvAcchzxd3hPr1KH4w83tzu9QdbYwjyXdK7pump": "BUENO",
- "3HfLqhtF5hR5dyBXh6BMtRaTm9qzStvEGuMa8Gx6pump": "BUIDL",
- "AuLFCTA8V8katsgpkFsezQtkHodJby5M4KB2VryTpump": "BUILD",
- "5SFjpjNXo8mXPw9Mfx49jzWBhoiqFTsPm4DCKindpump": "BUILDR",
- "vsDLJBTQZTFcnvrosoA49Czqy9qZGu4tgjh768wpump": "BUILT",
- "2g1Dh2j9AsdpnR5Js24cdtuUEE3KQD1YpHG8NgQ2pump": "BON",
- "8RGy4BZUEkW9dc2UEZ3QHYYdas66X63vazdZJezGJw5e": "BUL",
- "GuKMr2mAFh4CFM4Qo2LkU6MKS2fmReTGcmu8GSudgos9": "BULL",
- "Et2bFLuPCW77hGW2g7UdrboPVuxatFZt4BaCzhCqpump": "BAR",
- "GmTXrcQtTvnzJoTJANqmbbBE9FpFwnmHCDsFHpCKpump": "BULLCAT",
- "D3DmEyC5p7LLkvEmtQX58EwGk5LmjqRJVNRmULRLpump": "BULL",
- "HdzMjvQvFP9nxp1X2NbHFptZK1G6ASsyRcxNdn65ABxi": "BULLIEVE",
- "DNyxufTEwqNCgGruJ4W2ue6u1RTFcH61H4sa42LGpump": "BULLISH",
- "C2omVhcvt3DDY77S2KZzawFJQeETZofgZ4eNWWkXpump": "BULLISH",
- "A9PFmw9Hu8zzxDUoU351pio1E1XWBWBfWnjT9qoondo": "BLSHON",
- "B46q6AJ4xRwWtxuWtCu1sk5DVUiEhAeGLPPoTJbipump": "DAY1",
- "XsRiRZg9NGkL3WEZZmqnxvxEoyeHG8LhgzMQF2HRE6F": "BLSHX",
- "5cBPkTSaQ2UnPG7xLccQHYs3Sv6QFrAnEFgjsgVVbonk": "BULL",
- "HQDTzNa4nQVetoG6aCbSLX9kcH7tSv2j2sTV67Etpump": "BUNCOIN",
- "B3hgxnFwveJNzxah9rrx5HnoiSUdz2b8kmggKyYKmoon": "BNDL",
- "7y1TrdzE1cEeCgBvgdNB9DViMYdQ7UU2FKhnPDLYa7ae": "BUNI",
- "2nhjjqSkA8FYCUdJvQhYjbtZdPjZbNo8VtNKTkJ3hncb": "BUNK",
- "8NCievmJCg2d9Vc2TWgz2HkE6ANeSX7kwvdq5AL7pump": "BUNKER",
- "7XeR2pjfqocWAVmV3fefcCPgZNE4eByV2vgdcjs9pump": "BUNNIE",
- "4mAKVgyAP7DGmQA9fcskevDWkpfoEgbnak1w6nTrbonk": "BURKAT",
- "GQe8DCQTBkuX5E2sjvwuKDZsjGYhU8k3DN5dkSbQLfqJ": "BURN",
- "3aLhoQ8YuyeSfgGzrpnh9WGLozsgt5FNTJe596q3pump": "BURNCOIN",
- "AnRZ2wegdibrTSTZZbsF3JxwkGU5EMDYXnaRtSRyjups": "BURN",
- "ygPRx1SuXQLqnrFTp2LWKQ8SJZv75Pq7vuXtiDjpump": "BURNINGMAN",
- "AVdsFsS45YjGEitb7yQy3XqnNsMVGL3o4cYA53bpump": "BURN",
- "6bESwyduZ6hZGSE2S2CVpZvfDUzB5WgfuyK2vZ6yBAGS": "BURN",
- "F8qtcT3qnwQ24CHksuRrSELtm5k9ob8j64xAzj3JjsMs": "BURRRD",
- "4AcNRnBBz7NsMfkdcLwgaAu2dijxkxuzg9v7P3MgA4ny": "BUSINESS",
- "77KhqraBouiU91KRchLPY8DYbVtfsH4nSBgHCd4UAwBY": "BUTTCOIN",
- "FasH397CeZLNYWkd3wWK9vrmjd1z93n3b59DssRXpump": "BUTTCOIN",
- "1PNnDdzy3hfKaUW6L35fmwDUwDkuCjwJqaBkAeubUTT": "BUTT",
- "Cm6fNnMk7NfzStP9CZpsQA2v3jjzbcYGAxdJySmHpump": "BUTTCOIN",
- "3dCCbYca3jSgRdDiMEeV5e3YKNzsZAp3ZVfzUsbb4be4": "BUTT",
- "58Ghft9TvGNuBiDzy9cFD2Px9rz5cDVZ1XoMFk1xpump": "BUTTFISH",
- "CboMcTUYUcy9E6B3yGdFn6aEsGUnYV6yWeoeukw6pump": "BUTTHOLE",
- "EVgPUtiE6Fg7T6RY16ACmydX7uucpCaqsK3es3u2pump": "BHOLE",
- "5EvPAtkL5r8PhGedwafiTvDDLi5JoqZMyiSQFfUvpump": "BUTWHY",
- "28tVhteKZkzzWjrdHGXzxfm4SQkhrDrjLur9TYCDVULE": "BUU",
- "8iP5QbqS34FTi2Vdrny6SHicJEM8C5L3Vy1QYT8jpump": "401K",
- "FneWQD6Ycu4yn6gGGYK1BawrVu2Pf91B7Q8X5MUkpump": "SLEEPCOIN",
- "8mejbHqzKhPZvZ6j3vikLrbi4GsggZ3UJrBcYdGvpump": "FOREHEAD",
- "ESBCnCXtEZDmX8QnHU6qMZXd9mvjSAZVoYaLKKADBAGS": "BTH",
- "D5xCPJ38YDAM8taHxVdjNZJrLMeQBeWi7Y47xjpNBAGS": "BTS",
- "9H6t1ao2XP2ZeNKRo2gQ3ckrxcUTXgjDmSY1ZB6fpump": "BWED",
- "5nfDdZFMsDz34y6p1PAm1yN4FpXrGjFRj2V48dgPpump": "BWED",
- "ke7MBNmmhXDegLgAbaVboquYiPYb1SagGpSazDapump": "BWULL",
- "BYATmZ7ry2pewxW3213sczJYB7ZJzPr921uvcRcJYYZQ": "BYAT",
- "Bybit2vBJGhPF52GBdNaQfUJ6ZpThSgHBobjWZpLPb4B": "BBSOL",
- "ArGfk9JJ72QETcmckxVjCZ9ApuATgP1mf9ysVHnPU4ut": "BYTE",
- "9dnDosD15dKqPTJqvFwzB99HXjEuMaVZr2Xju5QuwzkR": "$BYTE",
- "C8PzjhdNVFdP7PxV8YrRXCRghEqw6fr3feAFMfJ88888": "CTM",
- "F9TBTkUELa39d8mpVvJDdcE7VrAcEGgzqBy5xoregCke": "CABAL",
- "3tbzRgmVg8bnYPizDc3DiBHEBiDUP1cTfLwJZV8gVFNi": "CACHE",
- "G4uJcvo5UAJ3fU1gj96e5DjBJU2RDDPx9Txzbjw6Y3LA": "CAESAR",
- "6sSKobm4TSRqJuXMuczGdV2BZityP76PGBJJ2ALHpump": "CALICO",
- "Cod7wUkjhcwcgbsRMAT6dJuqJGK3U936LMLrNQF1z7ht": "COD",
- "4KMTubLvU8pMRffjr6C7Uy22SxXjxSCjkKXr849Npump": "CALUM",
- "Axo7inGzj9dhTH4R4LHxC3kxuRq7uxhiuxLqqLZeBAGS": "CALVIN",
- "76WApFF6weYWkhCYHrAogDe6YfrGj5uZYvBdi945pump": "CANELCORN",
- "AHeSgUwaAqXLXuoidLWeHMeYVH8SgaHB7QjwG3DZZDw6": "CAMEL",
- "733Xr5c3PThmBce5uLSnTzKT4LrAWoGy8tvQvcu8pump": "CAMEO",
- "CmomKM8iPKRSMN7y1jqyW1QKj5bGoZmbvNZXWBJSUdnZ": "CANCER",
- "6iFUKWGDksVvmnSYJUGYnsu168xstni8xJkTF7QrpPAu": "CANDLE",
- "A8bcY1eSenMiMy75vgSnp6ShMfWHRHjeM6JxfM1CNDL": "CANDLE",
- "3nCkzXUKY5eqbeJ3RAx3rmqqbnJHqMc2WFhvXqSJjRQi": "CDG",
- "FF4dN8Qy8NNF88HRgMA3TkbRVZ8PTXWXZCZJb59X3Sbg": "CAN",
- "6fYLNrp7ymmNy2kJnqJNFDpbSkyzQdS6i4kwfe5kpump": "MOON",
- "7E2iF4WFs5biCtkAVFCBPEdnpg7t2D19VzxjxEPvpump": "CAP",
- "EvDWFiEhRWxpJM1wJHFpe6sy8M14KLTV2bNAh7r6pump": "CAPITALISM",
- "R2uDbMtmHq5xSS5SserrovdRKdpiqnVBCd2AHLhondo": "COFON",
- "Ec2817RwGNA6wjBxTd2HWU1ohB6tfit8tT5gvr2npump": "CAPI",
- "3C2SN1FjzE9MiLFFVRp7Jhkp8Gjwpk29S2TCSJ2jkHn2": "CAPRICORN",
- "BS8zoc6pmALQnBhBDFak6eFhgGHjpebnHzsxApgondo": "CAPRON",
- "JD3S1oqnjG5trRTZXpLmKnS7LsKsppyFa51rPBBMWogv": "CAPRI",
- "BCZUX1BMFrRJT4WwAK8YdLNYnL9MF6vP3JESpgXFpump": "CAPRA",
- "BfdzpiKdTJi81rVWo1gXjav48DUzo7hqxCY9nxRbpump": "CAPS",
- "QdyjMr627PR7NtWdcEcgFmDm5haBVUWEcj4jdM4boop": "KUMA",
- "2umQqRyexgfHcndkULDKStmJJ8xgDz7oBL3EfDJNmoon": "CPT",
- "D3S1AW1Tj1BbQVCo34D9frJDoD81dU8YRCPhbtUUpump": "CAPY",
- "8QkG1NE8mpgzAc3og6UVxeN3S3uRiaQJPP3fzUYNpump": "CAPY",
- "7VENy6wCjBChAMGpjPQCPYJDeYJGFr5NZUxk7uQ7bonk": "CAPY",
- "LWPihkg8SWDiAzG5TXAsgQuJeSZ3cXem1VStNX8PLAY": "CAPYSIM",
- "D6xWgRCSHoMEB5fqPwk3p6Stxirn5ytm2WwboSTTx4oE": "PYBOBO",
- "EQs4DEeaSyrhRPM6JPsf2ptLf4EHkcGXB7ybeufxpump": "SAINT",
- "CDwKAreA1ipd1hUDBKsfVXVFWqNEeGDdvmZ7RHdiQk1U": "CARR",
- "CRTx1JouZhzSU6XytsE42UQraoGqiHgxabocVfARTy2s": "CRT",
- "55paRYJNk2hcjjuAKEACiZdaCiYz1okeuWq1cWit9Ket": "CARTEL",
- "AFJtnuqGMaj5jAo6Pwxo28r1f7XAXXTSA8q3rG3q8b4A": "CARV",
- "FGmUDXqA3AbWfo5b3NUcsvwoUFCF4tr9ea6uercondo": "CVNAON",
- "3up9oA3hqCYRoxXhnAeUBfLv3oNrTCyAqL44t82qpump": "CRISPR",
- "CASHx9KJUStyftLFWGvEVf59SGeG9sh5FfcnZMVPCASH": "CASH",
- "CSCojiafv6WLUtT2AGTHgcfnYiGoTZpGgBRwhvfuWQFY": "CSC",
- "DjUeSoWmxfVx3Lq6y7a4kUH8WNaKZNuqEFWxfwgypump": "SLOTH",
- "3Lbxn3uPP58u1KEULn3iJyaKNWLgxbRsS1kgcUeXpump": "CAT",
- "9jyF1gnzazzmsNH1BxbcfpE8QrBge7sMsqMBfmp6pump": "#CAT",
- "CATA4f9X72ErPxZydy11EGk3e5WVVkxrm2B17tfzDuSP": "CATA",
- "GmbC2HgWpHpq9SHnmEXZNT5e1zgcU9oASDqbAkGTpump": "CATANA",
- "mo7mapMrCsyci5w1td1wgrKPtNeCfjfkKi96DknWi5N": "CATBAT",
- "7hWcHohzwtLddDUG81H2PkWq6KEkMtSDNkYXsso18Fy3": "CAT",
- "CATTzAwLyADd2ekzVjTjX8tVUBYfrozdkJBkutJggdB7": "CATDOG",
- "DFwxYdmfLJsPTyrNJCapGadF58Y74e2TFpVAyhbgpump": "🐈",
- "AErxJJxGbc9cZzZoZepN62BNfg5RXns8tmEc3Zpondo": "CATON",
- "AcY6RWuWKM5NU7BeSE4c4zQxBZpyU7pTLNF3g5DTWUC2": "CATFISH",
- "fESbUKjuMY6jzDH9VP8cy4p3pu2q5W2rK2XghVfNseP": "CATFROGDOGSHARK",
- "FP7NvFXQXoZL1nQC5QZtE1bzwgALdxj1TeA9J25epump": "CATFU",
- "CkW5tFrQiGVoKcYxxpKNLLUvTXxnpY6qc43TwyUvxYoB": "CGF",
- "GVwpWU5PtJFHS1mH35sHmsRN1XWUwRV3Qo94h5Lepump": "CATGF",
- "FGf1Us3kqu9AXu2x1yWKfiKE8uSx42ACvRiUrbuAodzq": "CATGPT",
- "MEW1gQWJ3nEXg2qgERiKu7FAFj79PHvQVREQUzScPP5": "MEW",
- "HodiZE88VH3SvRYYX2fE6zYE6SsxPn9xJUMUkW1Dg6A": "HODI",
- "1A3CZ3b8f878LfqpT3stoiDC7C1EDMjda6A1xHakkMF": "CATINO",
- "9CvxZKiSrszi7wNRVRnnHnPzBiN2F2soJ1PUpg7apump": "COOL",
- "JyTYXrqcYkvRhotAaYBvFbm6zk7vimHc86hwLZzpump": "CATJAK",
- "EavJDLh8cYTAnt3QDitpKGMsPL2hq1My5g9R2P6at6Lc": "CATMAN",
- "5p2zjqCd1WJzAVgcEnjhb9zWDU7b9XVhFhx4usiyN7jB": "CATO",
- "Dnb9dLSXxAarXVexehzeH8W8nFmLMNJSuGoaddZSwtog": "COK",
- "6zgbwgsiQkNP6EXHx7gEXqgKGK4RPpFWvW2HFwi7pump": "N64",
- "E99fN4tCRb1tQphXK1DU7prXji6hMzxETyPNJro19Fwz": "SOLCAT",
- "4HBQm2EhdpUWZkTYxttxNDnsoWi5beRAGWHpjVo8pump": "CAT",
- "EnYkmHKm13mLnBgpvHJZE2T6rqi8weQXoFuPccW9ZiD5": "CATTON",
- "Ag9TVNiyh2dDbVAzf1fZj6rjPLRTCLGXQzEDwWuZjupx": "CATTY",
- "5Fxk572o7JgkNhv4VbHt7DKfvKiBpapGr3fxjGd6pump": "CATULU",
- "EVDoPXkWNRMc7fQirg7emNdc17KNqsCyzVi4mWPmDvni": "CATVAX",
- "D8r8XTuCrUhLheWeGXSwC3G92RhASficV3YA7B2XWcLv": "BAG",
- "jkGKKj3MinQg8nkcWZBid6XxeSnn75Xoy9AqkqLBAGS": "BAG",
- "Uh6aMRwUduFFpxXiyvbfBRUHv1cyw5vuPtLfbtdpump": "DRIP",
- "G3vWvAaXPHCnncnyAbq6yBRXqfRtEV3h7vExzasZeT6g": "CIF",
- "2gkevSAUExkSUwwwj6uNbzwwNCXyzEBkGLg4wAyUpump": "CWH",
- "7atgF8KQo4wJrD5ATGX7t1V2zVvykPJbFfNeVf1icFv1": "$CWIF",
- "Avb1PBRudW7uUV9MqTUqfZ3EZTDvNkKS63W3wyPseudf": "CATWIF",
- "6MQpbiTC2YcogidTmKqMLK82qvE9z5QEm7EP3AEDpump": "MASK",
- "921a1GKnx3B4jSEc8M9dzT9j7oQAuioF8ejKQBGNzFQ4": "MELON",
- "8XSRFmCAaMU617gv7RTS7j8nQ5MEgBVVmVcp24cDpump": "CMD",
- "4SZjjNABoqhbd4hnapbvoEPEqT8mnNkfbEoAwALf1V8t": "CAVE",
- "HZqjjeso24PDVdLsVJQyVb8kDnbo7HhXfY1Jane66o9C": "CDR",
- "BD3zHHcK6aqz1RVBawMyhp5DfXFaDYaBXzwBH8cEpump": "CEDAR",
- "8PMJczfs9W8TDKiNBD85AuqxE8tWACCDeUwxpUeadL3j": "CEICAT",
- "CE11ARyXsqrw5ncLfPf6ZVbsqKjofF3CmUnoKNo2giia": "CLR",
- "C9FVTtx4WxgHmz55FEvQgykq8rqiLS8xRBVgqQVtpump": "CENTS",
- "7oBYdEhV4GkXC19ZfgAvXpJWp2Rn9pm1Bx2cVNxFpump": "CAR",
- "2KFZCkfxj1Us8YRQZa5vktSxy3GPzFZvVhWj91n8Fv2J": "CBDC",
- "2jUSPvEuxSxJ6nGpUHyXVAcNxyhugPC1iBeNjhTXzAUy": "CNS",
- "CERBERR9kg7MQqL6kXJPhNRqD1VwunTau1DDvjSZ14HD": "CERBER",
- "ai6rQuLGBsLG2AJiTjRA4ms2n1e9GYi5gtgw1rDpump": "CRBRX",
- "7jiDHV9wphDKcseQaVdY8v3qe5CsciCQW5Lip5DQpump": "CBM",
- "neuRodi6Saw2cwDpud7FyAcjzqPBJDtr3fDTXE2Fu4j": "NEURON",
- "CETES7CKqqKQizuSN6iWQwmTeFRjbJR6Vw2XRKfEDR8f": "CETES",
- "HQPMEbkZmwxCscm6wQmDXc5Ywyft7aRsbKdooh6Ldr8a": "RS",
- "DD8GJwAZHZZsLEtKnxdWfm8JbBhUj1oVwiGigfPUpump": "CGAI",
- "9Wkcek2EZFmJf5L2XmC5rfnNVBrdndbMe6yW8fbfbonk": "CHACHA",
- "8i93CHmhcqtCWMvaAdiTngwbQMQRKFW6g2ojnyhUpump": "CHAD",
- "CmUnSFZCKUFGs2L8eZGQukAj833Y8r2SiJav55Nnrihd": "KARMA/SOL",
- "Akd634sRBJQWKgosKCYDKQdxNuZr5J7r2VZ2Fwxmv6Zx": "CHAD",
- "DZd5bxpRezxkeDz18QJ2BzrxhDk6w9go7qAXgMfaLtjV": "CHADAI",
- "EvPUFsBikS1B3GpbmVvUWAc4DXaBXD4zLDER9SVSEF27": "CHADCAT",
- "3pGyE8coXwBy8rx71zjtHDRrSA5TvKmuRgqwhK3Xmoon": "CHADETTE",
- "6f41LGHuU2HVV67ao9GwJ6kv2jNUz9HL6FJPVYcJpump": "PEMDAS",
- "9y4zGixmVFGj47RCtbjgdjqWRASnp2HM1X8t7SHoM3HA": "PUTNI",
- "RhFVq1Zt81VvcoSEMSyCGZZv5SwBdA8MV7w4HEMpump": "CFXSOL",
- "Fo9wJVqWYXEgsG3UKekvK1R7YVewyUGodRfBrmjaBAGS": "CFX",
- "CCDfDXZxzZtkZLuhY48gyKdXc5KywqpR8xEVHHh8ck1G": "CGPT",
- "LinkhB3afbBKb2EQQu7s7umdZceV3wcvAUJhQAfQ23L": "LINK",
- "8SgNwESovnbG1oNEaPVhg6CR9mTMSK7jPvcYRe3wpump": "CHAOS",
- "FxUniKYRESjn43wt2uM656kdSCxdqEXEnc9vTkAepump": "CHAPO",
- "EwBUeMFm8Zcn79iJkDns3NdcL8t8B6Xikh9dKgZtpump": "KING",
- "cnc6M1zXLdrGR5LAQVcaJDfgezMiVWNtGQsVy1Kondo": "SCHWON",
- "22smSdhoAo5KhmXx9Y6WoSSgKtguzaJ3EFJSMW2Tk7Pj": "CHARLIE",
- "DBpVGmVbMrw2vEbkhBu2cC3MvEg63opeRHdakVMEpump": "CHARM",
- "4nKvQ6gMrTKH17kr9kmHmvRzA5G7Jd7xwxyCyr9Xpump": "YARNCAT",
- "9EwutmiMiLHoH5hj5aCLMDJUdsLZVg926ZmDdr8Ppump": "CHATTY",
- "Bhu2wBWxfWkRJ6pFn5NodnEvMCqj9DLfCU5qMvt7pump": "CHATOSHI",
- "Ak3ovnWQnAxPSFoSNCoNYJLnJtQDCKRBH4HwhWkb6hFm": "CDT",
- "GLiB37nqnPDghvVHFS9CJ21c5BDUQxSJS3BXBWduVoPm": "CHEDDA",
- "3FoUAsGDbvTD6YZ4wVKJgTB76onJUKz7GPEBNiR5b8wc": "CHEEMS",
- "FwBixtdcmxawRFzBNeUmzhQzaFuvv6czs5wCQuLgWWsg": "CHEEPEPE",
- "AbrMJWfDVRZ2EWCQ1xSCpoVeVgZNpq1U2AoYG98oRXfn": "CHEESE",
- "B1KrhWbacPi3tpjWqnsbjKQJEkp3RvWppGxNzUYBpump": "CHEESE",
- "3BeJ9zCgQhaqKMu2HgKJ79yQBChD1Pf3hPwRX44fpump": "CB",
- "9wV5ix8WSWLpdpLe5BSSwUJhYptShHfiwBxdYorBkFqi": "CHEEZ",
- "h415SDExtTrKXwmxYn7SyAV8QTpiVJojz9T3G7kpump": "CHELON",
- "BEsnQvkfeaQ3G8qbeN5FmUnsQUqXzXW5i83Hv3syoTTc": "CHENG",
- "7JofsgKgD3MerQDa7hEe4dfkY3c3nMnsThZzUuYyTFpE": "GRIN",
- "7tgKziACteG26VjV5xKufojKxwTgCFyTwmWUmz5ondo": "CVXON",
- "XsNNMt7WTNA2sV3jrb1NNfNgapxRF5i4i6GcnTRRHts": "CVXX",
- "y7WrhyUxATe9xMmdQKGp2pcgZYZPie8wsZuCV1oUkcj": "CHWY",
- "2zGQGkLnQgWLvfSiWTXnnxdMA7fiP4ah6hyJPQQe3Eoe": "CHWY",
- "8J5e2FPmBJ1subEUeVkELpeBZv9aYUrMmfHys7sREeXr": "CHEXBACCA",
- "6dKCoWjpj5MFU5gWDEFdpUUeBasBLK3wLEwhUzQPAa1e": "CHEX",
- "UrAE9vVdrWxncikcCRp7TgNqEsArFtP22iXzH7gpump": "CHEYENNE",
- "5aUemPEExdpnRYwrHTsALeQgDFda63dAP5bNnSdgbonk": "気",
- "HfXLMuSCHvsuYHRLekyW88oiz1LJvRerKh4QH1y5f8xk": "CHIBI",
- "FZRh6uAar3gEJb53ruHNjHibCPqiGHghfGiSRVeFpump": "CB",
- "CEeeVEznH4bpZDyNPkR9BhrkrKHk8Fh3j794BKEQcRF3": "CHIITAN",
- "8s9FCz99Wcr3dHpiauFRi6bLXzshXfcGTfgQE7UEopVx": "CKC",
- "J252vEBJq8iABpPqAz9M7AYn6y6F3FoEssjXwF81pump": "CHIKUN",
- "Fy1RLA8gvudCj1x4tcpcCDRWG1jfuYHT7zpWKP1svJam": "COTS",
- "GPyzPHuFFGvN4yWWixt6TYUtDG49gfMdFFi2iniTmCkh": "CHILI",
- "2pb1ny5NA51GbBFNGfo1XYyUpsAacuSdmFRByx6upump": "CHILLCAPY",
- "CSr7HhUyBxatPMuTqAs3Z33fwQ4dx8cNAArMert1pump": "CHILLFAM",
- "AH9oMYaNWwwh93rthazxXcJB7kyFsLgZMxDJxbwpump": "CHILLGIRL",
- "Df6yfrKC8kZE3KNkrHERKzAetSxbrWeniQfyJY4Jpump": "CHILLGUY",
- "Zdq34g8CKSMTjNrcudRWCP5P6UDXHaWgqCfxPGvpump": "SUZAN",
- "GkyPYa7NnCFbduLknCfBfP7p8564X1VZhwZYJ6CZpump": "CHILLHOUSE",
- "Mse6hcdxMWgQgEW7AcidAYw2G5ucW5fC8XK3NWYpump": "CTOAD",
- "G36mpCk6NiSqSXxviwc3FYtdvNLFkaniZ1pgsCZTpump": "CHILLMAS",
- "E9HkGyDrjJnDDQek2dajCZJ3CMEMBiPc8Q52UDRmpump": "CHILLT",
- "CkAtD6EBUjryNJfX9Y9MxC4VKoXUrZG5Xep7juDPj3aY": "CHINAU",
- "J3FnBoPv9vLTPi2Lj1S4NFRaWoEDQ47Sy3E4ZfrVBAGS": "HATON",
- "FkwpBGmeZpkuZmffZiAJ3gKraw63i3QTDrze61N6pump": "PENG",
- "FLrgwxXaX8q8ECF18weDf3PLAYorXST5orpY34d8jfbm": "CHINU",
- "chiPiQTvkQ7oPtAD7YLQaEeHmPqXCa2wcRQdwFNneTe": "CHIPI",
- "5owVsVFSHACQuippFYdLp3qWRobp2EGcwxMmsr6ondo": "CMGON",
- "3T9mBXQzfAn8Rf1LKDutvGMTd1EruJbFh3cM7MSMq3Py": "CHIPPY",
- "7kAux1bLGB68VzisQaaXiNKg3sjP89uDDotpuKmTpump": "CHIP",
- "Cy7rUZ5rK2ukitsAVVfK5Kn8t35TR417RRuURPWoRBAF": "CHIRP",
- "J95PxHUEytzTGbf9DpLpyPHXnUTWN4FbRk2Jnc5nYKa3": "CHITAN",
- "BYhskqqbXdhEydYY9NAfYopn43LsPnbb6KvcTAKypump": "CHITO",
- "DFy12AkbxKnR2s2gaYz1AvxgxqGDrMEjjzK1GG3Ypump": "CHOCCY",
- "EVrGfAj99Xr1NjqqZv6E2msVKZVmhGaThHhcZXzrpump": "CHOCTOPUS",
- "59McpTVgyGsSu5eQutvcKLFu7wrFe3ZkE2qdAi3HnvBn": "CHO",
- "EngayhhahJGPZ4mqbnDQtVRnhjjf1uoEmbpevBVFJdLM": "CHOMIK",
- "F67smWaqebM2zbk1eofh9ihF1vNaDPD1FTA6EGVDLwWN": "CHOMP",
- "9tcChCm93yuM93GDiwnERZQrD7wgyU21pHPRFmnxpump": "CHONK",
- "CdNWibyKcLUJKvzj41zWtnRsWPiWexbgConijXaUbonk": "CHONKUS",
- "H7ed7UgcLp3ax4X1CQ5WuWDn6d1pprfMMYiv5ejwLWWU": "CHONKY",
- "2MwjFE1zbXyNKw6VjzGWa3BhPtFcs8htuX2xwRAtbonk": "CHONKY",
- "361pUXTPohPEgcnCVm7DUvNziizK37gVxLN3cw9Vpump": "CHORUZ",
- "FEhKKF3xMEzgHkBHRGJArdQ8TpkCX9KQD6DhJRMzpump": "SHIRON",
- "X2h2pyb81yWFw6fFCF864F9sYYs3d7us4ZHBq2pFSnf": "CHRIST",
- "BJkgs94YDeAhSjXRSMestfM4CgMQ8L1m55NSEKjrpump": "XMAS",
- "tGSHqcbojd4uSmirz9iXHvuRBBFwbHaDjSatbuupump": "CHRONOEFFE",
- "4gBDhgCqTtzyJocskewXARgcLoAfSxkmmoUwwfhbpump": "CHUANPU",
- "ELST1oAp3czkRRRWGeTgttGsEqkD2qjDRJXR4Asmkk5y": "CHUCHU",
- "6yjNqPzTSanBWSa6dxVEgTjePXBrZ2FoHLDQwYwEsyM6": "CHUD",
- "BKUFQTnhsBnzZFBq3s9V9bFwi4EVZd7KXBP3GqY1pump": "CHUOI",
- "A3t817aK6XkhqQA148bjXKWJMhBmP9t2d9caWvQNaHQR": "CHURRO",
- "exRqAuXs967fDkymNXo4eqZEQihEubstBCXPXxwpump": "CIG",
- "25EDYHRPkywy4X8aE1s6iNTztGRbsaRMMwBEerompump": "CIGOL",
- "Ciphern9cCXtms66s8Mm6wCFC27b2JProRQLYmiLMH3N": "CIPHER",
- "WNZBSkNBNP3Ct1pcFn6Fu4sZQFhnu48EsM9voCEondo": "CIFRON",
- "3qAR4mq5X8WTuyqDeie2Mj9wGrYVb83TiGdkEgYbpump": "CINET",
- "6xHEyem9hmkGtVq6XGCiQUGpPsHBaoYuYdFNZa5ondo": "CRCLON",
- "5fKr9joRHpioriGmMgRVFdmZge8EVUTbrWyxDVdSrcuG": "CRCLR",
- "XsueG8BtpquVJX9LVLLEGuViXUungE6WmK5YZ3p3bd1": "CRCLX",
- "7DWcZE1uVc8m2mf9pV8KNov28ET7HsvHkhrhgr9ondo": "CSCOON",
- "Xsr3pdLQyXvDJBFgpR5nexCEZwXvigb8wbPYp4YoNFf": "CSCOX",
- "PjtfUiw6Hwd8PZ94EcUw8mBSYxp7SjjzSLeNTDKondo": "CON",
- "ENJpMVwQ5Cxi4SNtSmAX1ZTm7KBHPwQ3WaRWgRyvaLB8": "CITYBOY",
- "6WBynoJreWH4dfayG1Qzrq5PBUstDMUkR1c7mSemBAGS": "CJFT",
- "3KT4KA8yJpAVXQ8xxbYzGjBCYhcAtxCsHaB9iyWeyyNU": "CLAIRON",
- "HW5SN5NH9jsUbYsGfTHfzfkhtAdtTiztF4qzsNQ8bonk": "CLANKER",
- "CLaNxaMQ3S4gyiwo8GeJLE7s8uCjeEzv5DWhg9ptC6to": "CLANS",
- "9b8jL2wcVjBFpieC5TUR76BDJ6sW8Eghd3fyq5VJmzir": "$CLAP",
- "3oaRkLHm94Y2fisjNPwkcHV7iUjTMdh5cSQyGarUpump": "CLARITY",
- "HaL8cPcEZgwLaCbwyf6aAPh7rhw7iHck22zFXSNjpump": "CLAUDE",
- "6b1Gj8h5N7TSZv3HwnqXkGShZGZJ6GCrfRkha3Djpump": "CLAUDE 2",
- "2xh1LVN7yD1dBGfrGcKz4BCTvcgrEyjouoHp9Nq28FZB": "MCP",
- "DSyAs4y6siDcC3qYaz4yhhXZSu6ShMgjYvrn7xD1pump": "BLOX",
- "2TsmuYUrsctE57VLckZBYEEzdokUF8j8e1GavekWBAGS": "CMEM",
- "FJPoRjKUkE4BP3cULAKiqztBjTxRG3qcRTV9SFf7pump": "CLAW402",
- "C9jkxMsjYhaZN6CiMqEbUfEc87kqf8dN15xmwTUWpump": "CLAWAPI",
- "ELusVXzUPHyAuPB3M7qemr2Y2KshiWnGXauK17XYpump": "CLAWED",
- "EahUihCyvsJVg8wWafXc5ytxaReFXms514wKvmBQcLAw": "CLAW",
- "739dnZEG4yaBWFsY8L8ZwrfhGG6dhtCSercW8Umspump": "CLAW",
- "77UrDzChDJmSQbQDEjBGLmaKqyxbWiEEzSTtEWwbpump": "VAULT",
- "6N5cSpWghA9p5Q8PRNkZnvh3aZB2gf3regzQXcnZYaMo": "CNZSTRAT",
- "Xsn3H7ACEpSF2ULxeiD6kW4jRZXpurh8ZPttyfoS56W": "CLSKX",
- "AeXrLftu8chuY4ctc6oDeG4dUx6Yr4aqeakUMFNvACdg": "CPOOL",
- "7Gg6J1nkHLVV2TMqhVGHS1BrYycDmLoux9R3GSy2pump": "CMD",
- "Dh69esKUndpk3yAG2Cg4VHMfYLaAHSeu6kuLRGv7pump": "CLICKME",
- "6tSUENw1SsuffbBdBYmv9iP7c6fq1jQ8wPJyS6wcpump": "CLIFF",
- "9LjLmk78kDbpsR18kYcdbEJe9yWALwkkSWaXA76Epump": "CLIP",
- "8WHMgk4kRdZaBDZkgyBpb6bw9XkZzJ2jXCv4gj1zpump": "CLIPPED",
- "GKjAe1bQXXLoEitJYSuyw6qt97tTVoKkGEgWPEo6pump": "CLIPPY",
- "7eMJmn1bYWSQEwxAX7CyngBzGNGu1cT582asKxxRpump": "CLIPPY",
- "3g7Lv7KKCXH6Hyb2vUKYmAFJvKgspWD3CER1NxAY71AR": "CLIZA",
- "BrZmDQwbdLXme3uaea8znLhy9Bb3fucMJmcFBuRPpump": "CLOUDY",
- "Fxb2Spt5fxoRZNeiMro2RFvr5vDKAggJYdgZVvJvpump": "CLOUT",
- "Cwq13pofafd7KNbWBabULgt7QC1w53NjiPgES49Ypump": "CLOUT",
- "AWGCDT2gd8JadbYbYyZy1iKxfWokPNgrEQoU24zUpump": "CLUDE",
- "E3yUqBNTZxV8ELvW99oRLC7z4ddbJqqR4NphwrMug9zu": "COAL",
- "CuTmqTAkdpTufMrSM2sUHG1SWPHZsaZxn1ZzfEeHpump": "COBRA",
- "8WnQQRbuEZ3CCDbH5MCVioBbw6o75NKANq9WdPhBDsWo": "COBY",
- "cocvP5K8DsDYbJkRGasSg69xWFenrVVdBLLKjJKPJSo": "COC",
- "e6G4pfFcrdKxJuZ4YXixRFfMbpMvgXG2Mjcus71ondo": "KOON",
- "XsaBXg8dU5cPM6ehmVctMkVqoiRG2ZjMo1cyBJ3AykQ": "KOX",
- "DNeC4WPqdjcptsx39nfM4bkpQ1zeccAD4XLpPBP1pump": "COCK",
- "APXsvXT37zZocsMtdzfgGrAFzYJJuwGYQCUzuHxwaW4i": "CDX",
- "125FKUxLgRuVUkiJZoTvcNSuXhDJ8Hsaw8HBoreaSPL2": "CODE",
- "69LjZUUzxj3Cb3Fxeo1X4QpYEQTboApkhXTysPpbpump": "CODEC",
- "2Se6tpGxjBPvuvk93LphyvUKVk7M8J5LMQkKEf4Gpump": "CODED",
- "H1XL8qRsthUTZg2XpM8YmkfYuryL9cA7wywyYGsdpump": "CODED",
- "BqyjVnfh4WaTXC23wyNnB8EMhJXUZDqJKvZnNagY9Exp": "CODEPUTER",
- "DjAbfe6EjhvZs4RAajYs8r3jcC1cFqqK4beTfGS7Lidd": "CDR",
- "28ECNMKBj66GMBJxq1c3VyzJiKY5gDp2sEYc92Ybpump": "CODERGF",
- "85Yf3z6zwgLGQLfxww7KoHGw4sHpx4iki2P1Ci7k7gqZ": "COFFEE",
- "8s5X3yLEx2rx8BxGT5uSwR9Z5FP5T64VLr4kkPStpump": "COFFEECOIN",
- "dFVMDELpHeSL4CfCmNiuGS6XRyxSAgP7AwW266Lpump": "COG/ACC",
- "BXMkru8ded26p71gJ3AMMwJmwZaYYfQjRo8vbZzondo": "COHRON",
- "9LjvTxWgtoEVdwRucY9hJLqmTcPnCRxoDiwbpzRvpump": "COINS",
- "zDhCPQhQC8GPV2N6n8TMBcWBQehYkMHBuBZMzy3pump": "COIN",
- "C98A4nkJXhpVZNAZdHUA95RpTF3T4whtQubL3YobiUX9": "C98",
- "CUSDvqAQLbt7fRofcmV2EXfPA2t36kzj7FjzdmqDiNQL": "CUSD",
- "5u6KDiNJXxX4rGMfYT4BApZQC5CuDNrG6MHkwp1ondo": "COINON",
- "cbbtcf3aa214zXHbiAZQwf4122FBYbraNdFqgw4iMij": "CBBTC",
- "Xs7ZdzSHLU9ftNJsii5fCeJhoRWSC32SQGzGQtePxNu": "COINX",
- "3gNjMbdpnLDXNsTPYBA7xvvk6W5NQ8XQyEzkTgZcpump": "COINE",
- "6CzvM95SQABhdjX4taXdpXYArz5daqcin4iM7CGjNwmW": "COIN",
- "CoiNdEjucrH1268Q6eSdkF7N9f6ZFq67LQjZRPxiebp": "POUCH",
- "74eSRkPotxr8VjiZYKFnoYr9JDVEycWkrzHhFpuKmoon": "COLDPL",
- "JCRiQKaujJjAjfVH8CNo4htGFMuTTnZtwvasVwneT7MA": "CLS",
- "3oEHLDg8VokqBM37u7ohkbKUKcdPE8sT8Btgrxovpump": "COLLA",
- "C7heQqfNzdMbUFQwcHkL9FvdwsFsDRBnfwZDDyWYCLTZ": "COLLAT",
- "AFDzaLz3cQZNWjnWbyq2q81TLVTPbHTbfkj8qKqTk74e": "COLLE",
- "CARDSccUMFKoPRZxt5vt3ksUbxEFEcnZ3H2pd3dKxYjp": "CARDS",
- "A15y4AUrNwxZu9qSiXuZjVsMDLUGEEGaAc6mEAfSpump": "COLLIES",
- "DCmeU6DAdNqMNamxw4Uw4Zp6rdVwwRcJDDpbPVJCULT": "COLORS",
- "XsvKCaNsxg2GN8jjUmq71qukMJr7Q1c5R2Mk9P8kcS8": "CMCSAX",
- "9PR7nCP9DpcUotnDPVLUBUZKu5WAYkwrCUx9wDnSpump": "BAN",
- "FpBL8Ta2XGw4VrpDrw8EH1Qm3mb1o4brHweASeszBAGS": "COMET",
- "H1MHqq1dsExxeuYTd8JZzM51z33RvxjuM5sx2oB11WJ": "COMMON",
- "3R4WF1RzaZNe7tyJCdYcwuFbcADrfQbHTAA8Xyribonk": "COMMUNITY",
- "4bY7N2hPq4aHQJwbhawceNqS5ksyQAayiLEsjNMwpump": "COMAT",
- "4chpewx2GE33XeBowzN1KA46KrR4gYvWoAfUnaUcgfZq": "COMCOIN",
- "2s9MXSwWLYQGycPrno3KaohfZNriPpYoggcMeZXCpump": "COMMUNITY",
- "Hv69wUkD225TYq111eAar9CtjhNpzBTRFpHkpY3pbonk": "COMPANY",
- "6JvpHB2ngA7br2V1JoC7nU8J1MS7Zf3MRcGFcGaBpump": "COMPANY",
- "5Wsd311hY8NXQhkt9cWHwTnqafk7BGEbLu8Py3DSnPAr": "CMFI",
- "3jiqwBQVRC5zRwHyqvnkQurebJ5RNxg3F5fXMwaxgkv8": "CNGN",
- "J3NrhzUeKBSA3tJQjNq77zqpWJNz3FS9TrX7H7SLKcom": "COM",
- "7XU84evF7TH4suTuL8pCXxA6V2jrE8jKA6qsbUpQyfCY": "CONAN",
- "CQvadZTR8vikRqqwyhvYV8YpdfCRjUCGyQwCuY4rxBQt": "CONAN",
- "3cL96frxAmNwpPHFqHCuzXscGvdpzmaACjbx8sH5BAGS": "CONCENTRIC",
- "G8LfyGVsjsLzetJ5RWZVAhMo4H9cb58ET1Z6gEZJQdPM": "AVA",
- "WCTk5xWdn5SYg56twGj32sUF3W4WFQ48ogezLBuYTBY": "WCT",
- "X68p9qTpEMkR1TLpXUP2ZJo8PG4Qge2Y2ZLdjA2ondo": "COPON",
- "7NWHifsBnn9DimUeNnsHdEXkTZhXmJTiXxcCngBondo": "CEGON",
- "CobcsUrt3p91FwvULYKorQejgsm5HoQdv5T8RUZ6PnLA": "PEOPLE",
- "bXubNUrG4z3cKi2yVTkYEDTfCLQqXKQFxEtzUNzsBLV": "CLUB",
- "B7zNKphr8fjczB71oi9uF9pCd5XSNJvBn78TVF7kpump": "CVGT",
- "4AKYKa4JLKQau7m8B7hmFdN8ur1SvqUDqJt6D44Npump": "CONVICTION",
- "KnrmAHo1wW2fGqVXcSZSpo6kmiKam5vNbDByrURpump": "CONVO",
- "7z5MTBLrz3Bj6rWUj8yVry6GvuTP2eHMcbi4k3rycook": "COOK",
- "EKgUxSq2ucFYwaoGfwz3sUpqDepky2vSfpr7jCEGpump": "COOPERINU",
- "8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh": "COPE",
- "DMwbVy48dWVKGe9z1pcVnwF3HLMLrqWdDLfbvx8RchhK": "COPE",
- "o1Mw5Y3n68o8TakZFuGKLZMGjm72qv4JeoZvGiCLEvK": "COPE",
- "2pASaZVMQCusTpUc6MdfFBXSML9yKeJQZGLf8L8RyYwQ": "$COPPER",
- "HWMYPcKxRoSHyBGEA5SZfFpDkKWBeiXwx2PYoxTTbonk": "COPPER",
- "61Wj56QgGyyB966T7YsMzEAKRLcMvJpDbPzjkrCZc4Bi": "COPPERINU",
- "C3VLBJB2FhEb47s1WEgroyn3BnSYXaezqtBuu5WNmUGw": "CPERR",
- "BM8b4U4cyXCieBRPDAAAygiQwKQemEJntt2yWJ8Jpump": "CC©",
- "CoRAitPvr9seu5F9Hk39vbjqA1o1XuoryHjSk1Z1q2mo": "CORAL",
- "4FdojUmXeaFMBG6yUaoufAC5Bz7u9AwnSAMizkx5pump": "CORE",
- "HQasg9aKwQzHvAQn2zD1mhVmht84BACdeycJLYEwBAGS": "COREJS",
- "XsFnZawJdLdXfBSEt5Vw29K5vdBiHotdPLjUPafpfHs": "IEMGX",
- "XsBGEXxbBcuu8Nrokj14G8v4ezT3JYWWLneTzXK8t6Z": "CORZX",
- "BfPGpgNyxe6rjAru1EJarjSBAcCABuMF5L32v7nondo": "CRWVON",
- "79F32BvHBE49gPsvypYTGzcpWGvt66mgvenQow3mJjXu": "CORGIAI",
- "DbPCbgJ7a37VgUMb17DF9vRucoL1ZuG5YrqF7y5Gf7qJ": "CORN",
- "ApqLH7ovTBeEjgBMXH8udnBttwR9k5JEv9pNnVQV7Xsa": "CORN",
- "92BJKpAnkoaTh7uyt5TYAFPu3CgBdZYNQKiF6zo6pump": "AUDIT",
- "CortexFv3fRcLKTgACr7aLqckGh5eP7TP3z9JHoKqMc6": "CX",
- "9AyLH5Puifc7v9MkTgA36JabS4wiVTEZ3aEPeNoTpump": "CORTISOL",
- "CoPRYLGHc7Qadere13xSPhRvgwwStCZn9dHpBZQ7pump": "CORVUS",
- "Av6qVigkb7USQyPXJkUvAEm4f599WTRvd75PUWBA9eNm": "COST",
- "6btaz134wjHkR8sqhAYrtSM6tavftfxnRvnyMd8ondo": "COSTON",
- "XsiRaD8qZm1P3KViowDYFS8rZ8BYT2g7ZEeyztthRye": "COSTX",
- "2TEy8cA4bmYSrA5Y2VbifUuzbeS764K6YtbibHAspump": "COT",
- "9civd7ktdbBtSUgkyduxQoHhBLtThf9xr1Kvj5dcpump": "COULD",
- "FpZWLF31ymwJQNKwdhxAog9HwFEJGWjk6JqQUWYnuHry": "CBTM",
- "NKyzy31w2J7odLb2CW3Ft4fpKXkW3LBt1pvpkVLondo": "CPNGON",
- "DcU8uHn7abXgYL8AJUK3t8FckeAXrNcGYYBK7uBFpump": "COVE",
- "BgbnCT47z1uhPmRpG6X2FeM8dkmuP67MALFzXGgGpump": "CRME",
- "Gst1mHM4sqEgUeZVNLRaDhVZBKngsnpch4abiVyGpump": "CRAB",
- "2o86pbkvCVru88TLtsBthcHHn4aR2yEUapPKbYtmpump": "CHEWY",
- "HdiyGfMmWk3tSXKAkKcY8oxoCXxABNjfbhxfiJA8pump": "CRK",
- "8gRCdUnRpQ4XcwfWFzJGymX8ze6rEk8ZcfZME17Ypump": "CRAPTO",
- "6JGSHS9GrE9uG8ix63w3DPMYHrgrJ6J4QyHbBhAepump": "CRASHOUT",
- "2ncKzZN6b2GbwWZVxQ4Q7nRQZbzqaR61MXrp4J7VE4Zj": "CRAZYBUNNY",
- "E7ENfG7EA1oGAtgZiaL8YL3THoSwu72LbsYmpN6n5ZXw": "CRAZYPEPE",
- "6EEWHJBFbF4jQtXTn1NyGoA7WawF7W8fy1GQyvhqpump": "CSEED",
- "CRGqUDQ4JQKx5pTqWHRpwiA95fmpuQe2ir92eBi6hgmW": "CREATOR",
- "65svCEvM4HdBHXKDxfhjm3yw1A6mKXkdS6HXWXDQTSNA": "BUDDY",
- "VTaqS4G29U5UUfYbXwzPjK4sDPcswuKZfMY34DbsGqb": "CREATOR",
- "H94yBE9hRVFHEcyqtbP4tW7YGRqBUA6qFQrDHMZTe56J": "$CREC",
- "Fg4TqUxx6E9L7Pya6fMUGzTD4s2jwSMzjrWeeBHvu7ZC": "CREO",
- "DXJTZkJSCHw3XRrD7rMkw5HDvDEbq2fqt4CCWd5Wpump": "CREW",
- "LoLLZBUGyTPNWyFF48KbcmkZGc1ajwaFdWoLhF2nBfQ": "CRINGE",
- "AaV3hry7G3kLTAmM1dKwxDiqfGuPCtuSvvQCcozRpump": "CRISP",
- "5V9qpFo8NMFyhYHbrqY2c1TJrvzZSnRJAdj4ryPVB18n": "CROC",
- "GvcNXdSehfNSNyhDVDj27kc459LzFqWozt9CSJywMy6r": "CRODIE",
- "5Hx5iXtTFDGNpXPyTMbwMvkH6Uh3bycUz6Atdmzmpump": "CROISSANT",
- "CTAyri1T4d1QRfnmtSRpEsPS5tyH6shA1WTskhybmrMT": "CTA",
- "AZGFPtxBRbnZtXw4hgQF4BuSmWK3EhUg8omdUA9DEL3Y": "CSW",
- "FWMad1gzugDrifDTxUYFxkAH8SWWSoDT2BfZP8Pnpump": "CROW",
- "cdKfoNjbXgnSuxvoajhtH3uixfZhq1YXhQsS1Rwondo": "CRWDON",
- "Xs7xXqkcK7K8urEqGg52SECi79dRp2cEKKuYjUePYDw": "CRWDX",
- "GDfnEsia2WLAW5t8yx2X5j2mkfA74i5kwGdDuZHt7XmG": "CROWN",
- "CRWNYkqdgvhGGae9CKfNka58j6QQkaD5bLhKXvUYqnc1": "CRWNY",
- "CAW777xcHVTQZ4CRwVQGB8CV1BVKPm5bNVxFJHWFKiH8": "CAW",
- "DTEqTxxGFn3SZ4C8tNP35X8iegCCgCBrX974WFSuYVZh": "CROX",
- "6yUoLKSJtLejPNbHfk6FaUBXLJHVkjdqgTtgqaYSpump": "CROY",
- "Hz7MeU72BNF9rCWyUFAwKTyCcjr6qsJm1jwYehnqjups": "CRUMB",
- "9iVJR1tjDgNHw88xtXXGaU2We2fR8qEm75ZSgztqDkag": "CRUNCH",
- "HkBWJJiaUW5Kod4HpHWZiGD9PQVipmMiPDgiRPcNpump": "CRUST",
- "DkuhDqqxnXwECj2XGhLyrZbWuuRgqyFvU1W4xFJ5pump": "CRYFI",
- "Ep5tnKTSkLDeQ12ctS3RhQNcbcApkcyJcGPgHh4dpump": "CRYING",
- "HfYFjMKNZygfMC8LsQ8LtpPsPxEJoXJx4M6tqi75Hajo": "CWAR",
- "5e6Y8yJ56i7nFwiks1Bqs5BXyN4DuvwHvdzoGYxjsHsn": "CRYPSI",
- "9YZZtRDqd9kiJMqgZ8XmFaE1mfK2T4kNpYgW1Nfn9rYV": "CT",
- "12You7a9CKuEH6QMdjqX2Wuvxo8bkGjK4YEDngmiGsub": "CRYPTOAI",
- "BNeaFbk7DRjMr1UhGuchRGMKvk2Z5bU9W8sNpn7Wvr9Y": "CBC",
- "Bksfke6KWgpftafmbR3E9J4wHr4bBfKDrztXN6etpump": "LARRY",
- "CDCSoLckzozyktpAp9FWT3w92KFJVEUxAU7cNu2Jn3aX": "CDCSOL",
- "4ikwYoNvoGEwtMbziUyYBTz1zRM6nmxspsfw9G7Bpump": "CRYPTO",
- "44fvUC89PJcFDNFFXXevaqMa5BXXCQXNGJRfTMiEQhBE": "LAI",
- "o86kpPZy4Vo37Pdg3SBkmzgTNhkAM2sfghirvgSpump": "JOKECOIN",
- "ESsCdmGyPK9sostFbWV5iM6owxcqsGNfBQaj3xkAkREV": "CRYPTOK",
- "CFhgTUXw7of3PYdbw3YrPeE9EVzVGo435i8FEmd8dr6w": "CLOOTS",
- "Eme5T2s2HB7B8W4YgLG1eReQpnadEVUnQBRjaKTdBAGS": "CRM",
- "EqQFU4AoRVKJjQrpshmp89YxHAgNecCpJdMS8PJLpump": "CSR",
- "6fUwECXzRQeh2wYuTg3xeQHGt4wSbiUbsdd1PYw3pump": "CT",
- "xGPMieA2M8aUrfp7MMsioSLanaXWwS7rVxYcvrMbonk": "CT",
- "EiUKEQXENExJjjuU2ZPVK3RgrJ1gDpaQb5w3UxAwpump": "PICKL",
- "CudisfkgWvMKnZ3TWf6iCuHm8pN2ikXhDcWytwz6f6RN": "CUDIS",
- "CwxXrctZ9cR4RzFy2vzZUcbCgG2TUncwwjS59Bymbonk": "CULT",
- "6Q9cTZABHC7cGNXWjBwPQmGa2AH8eyg1oVybANV6pump": "CULT",
- "4J4W2tdq8gLLEdrq62HqCAbpPAci8SSQdSVvy6uLpump": "COPE",
- "9Poxe5aDkt8ggFWvcYZ9AX8QBBAAdgW844cgooNCULT": "CULTS",
- "3zu566b1F47koogyGwwmcCDeo4dnE8zaYCtWYmBfpump": "CULTURE",
- "9KbgSh6XZaHiDBQE26tGTDuJuUZmVyvJGGabrE7fpump": "CUM",
- "5PsnNwPmMtsGZgG6ZqMoDJJi28BR5xpAotXHHiQhpump": "CUPSEY",
- "9qU3LmwKJKT2DJeGPihyTP2jc6pC7ij3hPFeyJVzuksN": "CURES",
- "8TbsZ3yH1mBHytVpmMn4qED2UeF3FgWUVt1pd5RBpump": "CUR",
- "4gWDfyqELKDoVv1xv3NczHEpMgWDg5kDXZMHmvsypump": "CURLY",
- "GtfNTYbt41BzVvNLj9ijeYsWsAAVEGidoDoERwg8bonk": "C:\\MEMES",
- "jGFnKSMVw5EuGiTZj3nr9Xqrt5tBQ7PcRZVkv5Apump": "CWYPTO",
- "FXJAdx38aXJdQd3ABAVu7fQ7Bjh9oMN92eTxszFNpump": "CDOGE",
- "4xieJTWvYfWGTdZYjxZNePjqGu74NexmcjLUpfFLVAPx": "CYB",
- "8X7emJy8CV5pK7UjyBKCywdfc4MTKShpUddqrqyepump": "CYBORGISM",
- "HJ2n2a3YK1LTBCRbS932cTtmXw4puhgG8Jb2WcpEpump": "CYCLE",
- "6QztfmSoxygymjzKwGHiWBcVEUxJEkXVQedKycYyyQHS": "CYLA",
- "B1bY1U7KYLhj9iSEBCjpAMQB77taEndFSwwBbqRrpump": "CYPHER",
- "CexCXDGoZUWqkSnaovysnHXkF6teX4p8tjhns6rhaCZ2": "42",
- "6Tph3SxbAW12BSJdCevVV9Zujh97X69d5MJ4XjwKmray": "CYAI",
- "GyuP7chtXSRB6erApifBxFvuTtz94x3zQo3JdWofBTgy": "D2X",
- "9DNYFn5fMTkFq9Tr92ByvF9vEC49X2cB4Z1PabDnfEYi": "DABOO",
- "FabjHjc1druUQoHVtudpNiCpnf73rtLzMkRM1b5NSbb6": "D/ACC",
- "8TzeV2nUFfinLkCD6W71DcNRnbTow61DB2nADpCboop": "DACHU",
- "APfYrsmioST7R2pdBLfTWi9f1gmgrtDAvJJnUnMWpump": "DADDYCHILL",
- "4Cnk9EPnW5ixfLZatCPJjDB1PUtcRpVVgTQukm9epump": "DADDY",
- "F4ZL8sHPXAoUaAQ6DVY4Si6uhHu9T5dvciNozdPZdoge": "DAFT",
- "HsNx7RirehVMy54xnFtcgCBPDMrwNnJKykageqdWpump": "DAIGE",
- "GatSD8nUEA7AZLb8xB9ZCjL8HWC7agVbBYQZv3pTpump": "DGC",
- "7mwikw88GRsAHbFpbpyuM3QMq1hXH87d4rYNuM8Earay": "DAKU",
- "7MDApufGNAKDDTcM3hrUpUfZ8jcaXdaoSZy1sQdRpump": "DALE",
- "98aprruoAHdVvoeRQJmcARd2HhJC4QN32AL9c2bnpump": "DAM",
- "G4HrTxyKzLWuyVNJYAKUD3nzm9NW7ADmMUNz4MV3pump": "$DAMMIT",
- "Xseo8tgCZfkHxWS9xbFYeKFyMSbWEvZGFV1Gh53GtCV": "DHRX",
- "8QwqzHgsGcVrxgT8Bf4U3MMsiAsFUpxTEEJu3RF7Mpvr": "TRIANGLE",
- "6wUUYjt3gFT6QFQTTsGtP8GGN4VfmZmAjfsbdaCmGX9P": "DANK",
- "GPwwihLa1w9Qsz27SmNrj7aLVnE7pr2cAvHe6aVVpump": "DANK",
- "7xUV6YR3rZMfExPqZiovQSUxpnHxr2KJJqFg1bFrpump": "DGPU",
- "85aM5XJhdDeUw4MbGKM56zmWnsRyh76zUVut97uPjiCg": "DAO",
- "GEJpt3Wjmr628FqXxTgxMce1pLntcPV4uFi8ksxMyPQh": "DAOSOL",
- "nQ1qgSpXWi71twnWPFjyfCtcbUXbVyQb64RfHKwRpKE": "DAOT",
- "9hnmRRR4jdGvDM89WMyq9UdDfWT6iuDYAjFZQfn7pump": "DOGGO",
- "6pvtv14ye2nvxqCR8fc8y7TTU6SkLGyaSVnVNS9V6777": "DARK",
- "HsZvkLneVfn3HVEdg649osbjicUEpVFdNZgYH9Mxpump": "DARKANI",
- "Dd2T3apN8Vc1GRr8oPkCpnkNu3ykvKDcFt1AEk8ypump": "SHADOW",
- "Ezn7q7Mrp8Asij8SQrT6BiuCU9RhRcEv4S8jDfiBpump": "DARKDROP",
- "8BtoThi2ZoXnF7QQK1Wjmh2JuBw9FjVvhnGMVZ2vpump": "DARK",
- "5YxXvio26Mv2RfZEYMPVcStKRVMG7TTjcWJjYjjGpump": "DARKHORSE",
- "7D7BRcBYepfi77vxySapmeqRNN1wsBBxnFPJGbH5pump": "DMAGA",
- "GjjDzSuRzbzf8bQbcZR1RgEpPmmHKyTMqksQJhx5pump": "DMG",
- "J13cJvKEhXDSBW7T7Q61xVgNVRThRviDmdmJM1X1pump": "DUSD",
- "4fwCUiZ8qaddK3WFLXazXRtpYpHc39iYLnEfF7KjmoEy": "DPINO",
- "FmQ7v2QUqXVVtAXkngBh3Mwx7s3mKT55nQ5Z673dURYS": "DARK",
- "23ENcgMStoFMYYj5qdauaca3v1ouvRdZXTdi55J1pump": "BINARY",
- "F1QmooYUjR3x7MktgeNWVfg4ELbK429baMQDcYZTVEiL": "VEIL",
- "GUiVKWZvtNnc273wBRLEwMBxCoPffPvhRC2ghPySwAFZ": "DARWIN",
- "FQ1tyso61AH1tzodyJfSwmzsD3GToybbRNoZxUBz21p8": "VVAIFU",
- "7GM8291Ze6AA9sA4Lr2B5nhLWWZJ6zhks9p6j8CMpump": "DASHPAY",
- "Duxeg8HrG89Dq95oyiydrnFd8irZhjApGZu8PYrEpump": "DATACLAW",
- "CwsQd329uL1ccxT3my2EJCEsciT1CUfk2BUmPF8Ppump": "DATAWITCH",
- "9GM8icX8MsyAJewmqQp8RQJqUfeJtTrrKr4gCRBBpump": "DATBOI",
- "5jFJCvNgg8ytGWBygoquaUC6bMZyr7C5jmGHECBzrxR5": "DVINCI",
- "DZSs9nHSr9BBunLNWd6PDstesJ4PBLMFVK1GbZ9urYNZ": "DAWAE",
- "7cb67ev3jvBKaAH1tnVM8FL8WfQ96sa2TYByEXajqx8N": "DAW",
- "CAJ4iqYG9dMueHaQyfBGkb5SJUw2awkMvKTansAupump": "DAWN",
- "GMzuntWYJLpNuCizrSR7ZXggiMdDzTNiEmSNHHunpump": "DREAMS",
- "33qfNgPi1DC3Ja2oAQS9dpvuVb1jFLheEmJpvA1Vpump": "DBS",
- "DeaVrje4tWsFNJ9Shs1CtjfXDbQsNeR1eSWtGxjJoFpS": "DEALR",
- "Ds52CDgqdWbTWsua1hgT3AuSSy4FNx2Ezge1br3jQ14a": "ISLAND",
- "BgwQjVNMWvt2d8CN51CsbniwRWyZ9H9HfHkEsvikeVuZ": "DEP",
- "3F57ME7sgqaGnajTd5XZeAzsgmE1nxyZvkAUsvRgpump": "ALGO",
- "DBRiDgJAMsM95moTzJs7M9LnkGErpbv9v6CUR1DXnUu5": "DBR",
- "9NQc7BnhfLbNwVFXrVsymEdqEFRuv5e1k7CuQW82pump": "$DEBT",
- "vLieQF5eDqUuuk8RzRaqgAHkXr7bSEBZaWk9Zfibonk": "DEBT",
- "DEBUTr2WcEsjkwKhqbRLqnuFKstX1MrEuvaz5xcoQTgn": "DEBUT",
- "7dgHoN8wBZCc5wbnQ2C47TDnBMAxG4Q5L3KjP67z8kNi": "MANA",
- "BiDB55p4G3n1fGhwKFpxsokBMqgctL4qnZpDH1bVQxMD": "DIO",
- "338uDSAxxn1ChHq6ZRUAxJCgpLtCBZV58KUT2bbJF4cD": "DEDE",
- "AzC1u8NPdpS6DVBs8Mv3P6egZ2AhN9KaGaY64xVMpump": "DEEBO",
- "E7ErFx5dRoAxnDphWRmE8DjfJBr2fvjvnX3cgaj6pump": "DEEP",
- "hTRDn7zE5tDHRnjj6Qms2WG1zEGv9ii6AiwfgbFpump": "DEEPAI",
- "3qVpCnqdaJtARzE2dYuCy5pm8X2NgF5hx9q9GosPpump": "DPCORE",
- "BpRMSjbQqm26f51HYKeBLfKEs43yXUhaKA8DXvCxpump": "FRIED",
- "4YTyNbYrZiKYkweEPAQySXV6NbvVe34qHemDRpxRiEve": "DFV",
- "93VXFhKsGXsraivwdwAwoVXHKd4U1TFL64oQYpVjpump": "DNET",
- "DwDtUqBZJtbRpdjsFw3N7YKB5epocSru25BGcVhfcYtg": "WORM",
- "CqQyAZjB9LGFTG95eiadGTkfhd9QA12ProeKsQmondo": "DEON",
- "68zA59nP4Luops7SMAJgWFoWraNmak2c8r2FEJrHpump": "DEERMAN",
- "6pKHwNCpzgZuC9o5FzvCZkYSUGfQddhUYtMyDbEVpump": "BABY",
- "DEEZgP19ZPovNeWRJZw7KuNbkLH6xjNjZ4HsUJnmZv7J": "NUTS",
- "HXwh9i8D1LKkVK8WfMjFPyiyVZ4Auh9aLD5ut4LCRqqR": "DEFI",
- "FfroP8rQZmaJtZ6sATd9yKvmFWb4dB1DqHWTbBtesoar": "DFTV",
- "DPTP4fUfWuwVTgCmttWBu6Sy5B9TeCTBjc2YKgpDpump": "DEFIANT",
- "AAASV2sCaykNGdEQzJ1mMVNfJMsgEtR7PJaqrCuk4bq6": "DEJAAA",
- "DFL1zNkaGPWm1BqAVqRjCZvHmwTFrEaJtbzJWgseoNJh": "DFL",
- "GoLDYyyiVeXnVf9qgoK712N5esm1cCbHEK9aNJFx47Sx": "GOLDY",
- "TUNAfXDZEdQizTMTh3uEvNvYqJmqFHZbEJt8joP4cyx": "TUNA",
- "B8RHrVBxSjBGKqAbn1tXo6CWjvt5jFkkqjbCZtuDpump": "DUSD",
- "CPG7gjcjcdZGHE5EJ6LoAL4xqZtNFeWEXXmtkYjAoVaF": "$DEGE",
- "Fd8TNp5GhhTk6Uq6utMvK13vfQdLN1yUUHCnapWvpump": "DGN",
- "A7n89LqW67HJKzJkdWZa2xojuK4N5GBKHz3dfjATCZPz": "DEGEN",
- "5NHd3MsP6dXi9r1saPkeB2DoZyXLvPiqv4n9J54Cpump": "DANNY",
- "6ztpBm31cmBNPwa396ocmDfaWyKKY95Bu8T664QfCe7f": "DEGEN",
- "AK9yVoXKK1Cjww7HDyjYNyW5FujD3FJ2xbjMUStspump": "$SITCOM",
- "oraiJP7H3LAt57DkFXNLDbLdBFNRRPvS8jg2j5AZkd9": "GNRT",
- "EKSKQP7iz5s9L8db6s9T2u9o7cczTCWEUscsXHxatime": "DEGENPING",
- "FdpEvMwXM99WsCr5zwrQ5BqgQTSLULpewpXjfs7ABAGS": "DEGEN",
- "Gu3LDkn7Vx3bmCzLafYNKcDxv2mH7YN44NJZFXnypump": "DEGENAI",
- "8AGrudQDbjNjnHzBsrndfVDBHgg6KBJ7RN6j3hbfq3Qh": "DEGEN",
- "3UzkMymHpqDijXYaGsz8Vbc1Vk4tKBED5TDT9v6Hbonk": "DEGEN",
- "4Nc2EhF8vqXcjHpbUevYZv9Bv4aKb4fWi7cju7c2pump": "DEGEN",
- "degod39zqQWzpG6h4b7SJLLTCFE6FeZnZD8BwHBFxaN": "DEGOD",
- "BU4eP1vCR99amXKsMXhctX8YpqUa7wbULQ26XaQbazkS": "DEGO",
- "CkADK7xbwyyU4TUs2ExUbJcASUqawVB7ZKSr1pexbonk": "DEL",
- "GBJpKgvZuEc3fzHZKoedJ14R8N5JwMd8MavfomNcpump": "BULLS",
- "BDWvvvKUS9c3C4Rz1w9tk5uD519CzD2f6n7zBk2Bbonk": "DELULU",
- "6KmwvVo8gDUVAnoAftMuyUTojfx6xtgm2xkHp2ixpump": "DELUSIONAL",
- "8bUbe1ujsM1G3JEbBWVVCXa2widmuPdKUB2rGKMYFw7R": "AGI",
- "9WiKyhfSX3wCPw1Xp6it94mA71XmBdSdxirX2TNqpump": "DMCH",
- "12J2LD3tuLfdiVKnWZMHRMrbnXDY9rM4yqVLUa5yondo": "DNNON",
- "313t1ZZcLBEmw4uWRjSei1xCDEK4B73KqawJ5xfCpump": "D.O.G.C",
- "9TY6DUg1VSssYH5tFE95qoq5hnAGFak4w3cn72sJNCoV": "DOGE",
- "KQijDbNJ6rPCqhtXrfH6gKa5cH3a39At8vHq34nnPbF": "DOGE",
- "B54Fyr1XrWNA5RsRRkovoVFwQwzwBfqaJPLoFR4pMoAX": "DOGE",
- "Dxmi5HRzJS5ov4siafxX7Ur7VVJQT64SPFcK3hsaSqtU": "DPNG",
- "DEpHYkW6nEm3Sxhb2rwftatrSAV3AP3ac6MgAWBbnsS8": "PHY",
- "J2LWsSXx4r3pYbJ1fwuX5Nqo7PPxjcGPpUb2zHNadWKa": "DPLN",
- "HRiLLm6hYiSdniFGjvcSvQ7XJrA8YSoktcqFbWjmpump": "DAKU",
- "4DBgRWs63QzBwj71Qxiiz49DUZJi2QgUha7cbadepump": "DERP",
- "14bLBcB1iHUBGioLSwjbWBsP26nZKU16Qg44p5Vderp": "DERPY",
- "8MhHH7nBxmukybUx3xqovgLDTetVzj3sogBXPueTpump": "DEVAI",
- "B8YVF2CA2hv2LnPdWpjNmqcS7g3tqhYkYm3wugcvHELP": "DEVELOPER",
- "7gbEP2TAy5wM3TmMp5utCrRvdJ3FFqYjgN5KDpXiWPmo": "DEVIN",
- "CeoReCwAmt8iqjQoKQGEMqKERDWGxxDUED9zVYg3pump": "DEVIOUS",
- "9nD29a6TMDFHqAXS3iJ6nwLByLBS1gx2664ieQf7Zo7H": "FUELX",
- "DEVgebuRAfMgnNyZhdaw5w9DMhG654FcLzAfjFx9HsBg": "DEVSCAN",
- "DVr62PSjVCrEwmWVRdKQABqJumb1jmJGKa8BkUG6pump": "TOMMYJINGL",
- "2jZChcoRaYfWVXjEefJRDcpoRGtSdNZw8i2TtkhSpump": "DEXAI",
- "GsNzxJfFn6zQdJGeYsupJWzUAm57Ba7335mfhWvFiE9Z": "DXL",
- "XLnpFRQ3rSWupCRjuQfx74mgVoT3ezVJKE1CogRZxhH": "XLAB",
- "GfPGfHnNbbKBvMGcupzixvgSvQAybBEe6DtdQ7sC1UWC": "DEX",
- "EfPoo4wWgxKVToit7yX5VtXXBrhao4G8L7vrbKy6pump": "DEXTER",
- "FkqvTmDNgxgcdS7fPbZoQhPVuaYJPwSsP8mm4p7oNgf6": "DTR",
- "zpfeF4zXpyXKSd6Hc6r7yRqWKZ289Bd3JVJW4SWKoLV": "DTR",
- "DTFc41ZXq8Mr84pLD6J68YgyhxNmvJ9qnvZQKCotPZPg": "DTF6900",
- "sctmB7GPi5L2Q5G9tUSzXvhZ4YiDMEGcRov9KfArQpx": "DFDVSOL",
- "Xs2yquAgsHByNzx68WJC55WHjHBvG9JsMB7CWjTLyPy": "DFDVX",
- "2kBzHjLgm9rwrbZikLk1dkx1Bt56Spc4cjdYH8Hh89Em": "DHANDS",
- "5wJPNcDnxD2W24A7Xo5KdPsZo3aGGhV6LeTorbs8pump": "HODL",
- "BmKNgdoCFAhjEszjfhrPmt8Kdq3TdWbPtdQoSKUdogHz": "DMTC",
- "4c1HzBShCHc1EckQTVXZZ5feDCgkDweaw3t3JQQqpump": "DICAPRIO",
- "Dice3uJ6AY63bKRHk5Mn24qdNLhBZJFJbaeDsTQrzBPE": "$DICE",
- "8EHC2gfTLDb2eGQfjm17mVNLWPGRc9YVD75bepZ2nZJa": "$DICKI",
- "8E5pw1g1nQpmgVyeS1vZx8LokAZvuZgL6G1Uhr4iVbAB": "DIDID",
- "7jC1eiCo7pnrj2fL4k3RvWGTjrSSLiJBxYMm4fiWCASK": "DCASK",
- "AUdUEc98MGfEHJiJfCgMaW8gKdcfNDio8BFzGKBwjztC": "DIGI",
- "EwFTbdtH1FZQ2ZtDTgtYfzU2fBsxuGQC3nRHAFHpump": "DAT",
- "6Xm7YzZt6JMhGofc6W41ybByfpsnHD5er5bdkK8tpump": "COLLECTIBLE",
- "EhwhYhMJp434kqQeFRRBCwCVPkgdjrYFcBXGozxVpump": "GOLD",
- "2RF38YBj5xMSzap94CrsQKDTZ5FTd8fwrdQSUzfrpump": "METALS",
- "5LS3ips7jWxfuVHzoMzKzp3cCwjH9zmrtYXmYBVGpump": "OIL",
- "EcEP6shgosHfg4m5b7wWTHHJZFWzoF1iqcdZMBzwpump": "OPTIMUS",
- "2uaTpSujZBYwBZNXusmW7PqM8Vi4qwbyotnfWhaN9oT9": "SLOP",
- "Hme1fwfqVYmfUaACE5AtkfqfRh34r3JyT5GYqyaTpump": "DIH",
- "61VtkXr9mRXtrFYe2T9arWYX52sbJnkAUQgfjGuCzox2": "DILLY",
- "14jazxRjHyaYsGoFk1u3CZSmgswYginbtTK8Z9PAboop": "DINGO",
- "6VYF5jXq6rfq4QRgGMG6co7b1Ev1Lj7KSbHBxfQ9e1L3": "DINGO",
- "6Y7LbYB3tfGBG6CSkyssoxdtHb77AEMTRVXe8JUJRwZ7": "DINO",
- "FdqkvhQNzrj2iEWBTnKvLaegWWjCxNgVkXC5bJ7guPKF": "DINO",
- "33eWALS9GkzSMS3EsKSdYCsrUiMdQDgX2QzGx4vA9wE8": "DINO",
- "6wCYEZEBFQC7CHndo7p7KejyM4oGgi5E1Ya1e9eQpump": "DINO",
- "BkuhUp224bBip4BS5mLMLG781dxDzFJGc3QPQfDDpump": "DISCIPLINE",
- "FbmmdcCYHL7WETG89xtWmNFMzQAaQ8Zs9NXVbimibonk": "DONT",
- "mJf1xT3suXtkXBCfZcE9oUUuyxkvSgqYBWiX7v1ondo": "DISON",
- "EPuZ1X6pPzac3ELPsT59LStmgaSr4kBJvaAbL15Fpump": "DISTORTED",
- "Ddm4DTxNZxABUYm2A87TFLY6GDG2ktM2eJhGZS3EbzHM": "DISTRIBUTE",
- "2AEU9yWk3dEGnVwRaKv4div5TarC4dn7axFLyz6zG4Pf": "DIS",
- "E1kvzJNxShvvWTrudokpzuc789vRiDXfXG3duCuY6ooE": "DITH",
- "7GB6po6UVqRq8wcTM3sXdM3URoDntcBhSBVhWwVTBAGS": "DIVIDENDS",
- "GcWVDkoaBWZYW7bBgqCHDiqAmfnwwPxvbusA3s77pump": "DP",
- "6uRY9e8gMaogSQiQmzAWJbbEvVo2zyZMyypc9AGXpump": "DIVINER",
- "DVYcTNFVGxePLgK8rUjViJvurRmTnD1FZUBR7puADymT": "DVY",
- "A5gVj5j16U4vCTMXQYYrhkmWgx6gej4nAeZRNQMLUAfy": "DJCAT",
- "DLMmRN9rbZspAAC3a1HgDHMC893Y2Ca9GjoNh9StwnYG": "DLMM",
- "DiSetnR7k57wmfvywJhUVjPwWfg54SdQKxQdJEBYW23B": "DNA",
- "AvuNqYe1Rj6eEzan78NYJ1nD3Ldt6CT8wpwGNrE2pump": "DND",
- "34EBTRNxjqZo3CgpQD3aaW3CC69DkP6BQUEx1Dd2pump": "DND10",
- "GzQzkt2B4Jr6whWVBF7XqkzWvoUy1jEd5z9tczzGg1rH": "DOBI",
- "5vb8AXytbQenTds4xKinp1FEoWAK7xoiNZw6hCh4pump": "DOCTOR",
- "2thfFEH6nR7Qbqd315Dt9BjSJRau9YQ4mmBhkAuepump": "DOCUSOL",
- "DoDoYogRFcc7XRwdJfMQKLvccYJKAvqPnqVpFZq6kjYs": "DODO",
- "GW7MWKG1ucAr6KDAUG7aeEujTGi9MEtdfqEZuGhmTaks": "DOEG",
- "Dogg6xWSgkF8KbsHkTWD3Et4J9a8VBLZjrASURXGiLe1": "DOGAI",
- "BNsEiRYcktWVft8V1sgK9Achk1cLQ4fdZLAfHzWqbonk": "DOGCOIN",
- "SsKFgDPEqyzAM8nWPiiX7MGY7iNDTEX6DxRdxmkpump": "@DOGE",
- "DpBzjtgGLF7QA9Ug3eUVGbnqa6j3jvYBn1XuQuktvfhm": "DOGE-1",
- "4xB2NGznSwQXAAjRsyAputhonM2uDD1FYwnGo92pdoge": "BAKA",
- "9UYAYvVS2cZ3BndbsoG1ScJbjfwyEPGxjE79hh5ipump": "$DOGEAI",
- "CkSFj9MNEfWffXPuJxfcWRWdqHYUMAcvuUdJ7muSLCKJ": "DOGB",
- "ChHAfQsUznqUpvFSNQsu42KsRr1t3ct56fBigVSHpump": "DOGECAST",
- "B4cYZYVYeHgLc3W1pCduCYkoS75G6roPaPdPoBCFweNJ": "COLANA",
- "EcYK2XNG4wWr2vDg2M2Hrts6SrU2QB4NzXLBf888pump": "DOGEFATHER",
- "A4RfnhcD1hk2QiVUx3TTtR7Af2RkgjvyJMcnogj9bonk": "DORK",
- "5bXVGNnGhCFAK9KPh1S9whFkhVxZy1mREWFbqB499xUP": "DOGE",
- "DCHLn5uLCDjPcmyxqeV3EFA1hAT518RR3u7gQe8iUiYQ": "DHC",
- "BjotV424H4UBvrAiGFGjQGztLxoafxM4HSdCXZR6pump": "DJI",
- "E6UU5M1z4CvSAAF99d9wRoXsasWMEXsvHrz3JQRXtm2X": "DGLN",
- "7ZCm8WBN9aLa3o47SoYctU6iLdj7wkGG5SV2hE5CgtD5": "ELON",
- "7Mxvi7bi5bnjELB4QNzQ4VrQEPeBgPbWwbfwE1ydBAGS": "SHIBU",
- "DLScRnWofxiYGqnvZWGy9Gt98MPqKdznaK4TRukxpump": "🐕",
- "8LFpoJWGS65GMDL7jPKPPgvns3g6vEDg15BmcUSsezuR": "DOGENARII",
- "Hk82ay38uGpYgqjdXXCiATavVQwAMaBNyxsUWbapmKuL": "$DOGE",
- "BvSyXBvy76mUgzLSbvvT4NQw5rSM4P5zAsdnvqUJpump": "SDOGE",
- "7xZCdhj7rGhnKndRpU3NHgZhbFMkPLP2ErDr1AS8Chsx": "DOGEVERSE",
- "9t77JBusmE5yEad6idpT1rWf7NQRPoHvV6DFaS7dsWy2": "DOGEX",
- "7x1xuoKGKxQuFcw2KjGPFtTLET6GC6LAygTRtPvYbjug": "ZILLA",
- "HVpsW3uvqf5vq1onTQZ4VMRmkY5sioHyPSEidyj4pump": "DOGGO",
- "2At7LMSFupTLnYb32w3rHGahhpqN7oc8jGQjhzoHbonk": "DOGGO",
- "dog1viwbb2vWDpER5FrJ4YFG6gq6XuyFohUe9TXN65u": "DOG",
- "4EyZeBHzExbXJTM6uVDiXyGVZVnf9Vi5rdBaBCFvBAGS": "DOGHOUSE",
- "2C9ynB9HCqwZLdKjg3TDppTwYdShwwUdwtmymFe6pump": "DIB",
- "EWYtkRuavbDKTsHqfSUSyo5diffxduGcsMufjpWfpump": "DIB",
- "7EoxBarbcbdmibuTZ4MgWzuBNQkXqKuonjfD7Eyepump": "DIH",
- "3rnDTgmTXaYuPdWZdzewJHrLQ8mcvqiLkFMDpE4Mpump": "DIH",
- "E3HaoVGnezn7M8D8zvBnim2zj45otSMtk1drakNMpump": "DIP",
- "3G8js2FjDtMbVDzh5ACaTLGHGDwBhaM5LBNuHKMeZ7Bd": "FIRE",
- "F6Vyxf5c1aMEQDqTHiCzY367wwwtHuMCk7W64ekopump": "PUP",
- "3XxvmED354933DwSPJuzB7SE9uiWpD1ErydDuhmbFRMk": "DIP",
- "55KrNjWHrkgxCzTLvcgaKYDxaopuxZK8vETi1CJNpump": "INVEST",
- "8bk3hKqrq1NgLKck937Fj6PoY9jAJgGpUKQ28qutgqha": "DOGL",
- "7LsFasVybz9nn6kRrHPA2w62K7UaWfg2SAUQAaG6pump": "DOGMOM",
- "53ctv3wwFXQbXruKWsbQcCe7sefowyu96pXK6FRLTjfv": "WISDM",
- "7ZRgHFqwdzvqhfmg19rSQBD6CZe5iEDkuZoaNUhpump": "MONKEY",
- "79dGFnR8XUusyDiK3n8yZ6FXhJjWLFgzdsi2SkUpump": "LIA",
- "99XLnpFF9UAJcB8bY1a9mmnVebSgLiyPiPjx8GY2pump": "DOGSHEET",
- "8AKBy6SkaerTMWZAad47yQxZnvrEk59DvhcHLHUsbonk": "DOGSHIT",
- "BXebtR4k2WiaZ1HJmxcZkoCdxSBx1g1xnEpVra9Ppump": "DOGSHIT2",
- "2FKMWYwr17j7AHexcgcQbn5gwZTsYR86qBPrU1BHpump": "DOE",
- "FhhXCnCbxBQ4nX4a4PBTuYG3gbETWixoNejQkPKJbonk": "DSTOCK",
- "CjqxraDuTMEcfhdqY8qEaMY43icdBrkt3EXciNVpump": "LEMON",
- "6UfynQAUASwqxSSEENzL7vMR1wmpQS6LXrNn8f3xpump": "DOGUE",
- "EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm": "WIF",
- "5BKTP1cWao5dhr8tkKcfPW9mWkKtuheMEAU6nih2jSX": "NOHAT",
- "G2FVt4LrYgZ9Grmy4Pb7FA7SKdLRZ38mAxTiLjex5Wsa": "NINJA",
- "2ioyweEeV4xJCkFJvh868X9iP3L6Q31MVCawfbJLRTHq": "WIFOUT",
- "jD8gVEjhkJos8caTEuVApbBcbZfCeRovxMCGwe6rtNM": "PANTS",
- "ELdqGtj2MhejZzudGfz7b798si2Av5Asuw9ryEQSpump": "$SCARF",
- "H33XL6HHDReCVRgSApZpsXM7Hy7JGyLztRJaGxjapump": "APPLE",
- "DfAwMXCmAyxt19Q1QxjHyS2ggskVwCnFaYSqgTF9pump": "SHDZ",
- "HLJzUzWU7eFKDCvuoJ6cQCYxkinE1cXCZjxWJWwWpump": "VINE",
- "3vmfEaTR9M2Pp5JcFNC8c8u6U4eFUBdq6FQjgPpcnfKS": "DOAI",
- "4YK1njyeCkBuXG6phNtidJWKCbBhB659iwGkUJx98P5Z": "DOLAN",
- "5AnPDx9GposBi9jSW2dFfE5QQD3FmXbudoquMNDxpump": "DOLLAR",
- "6YkkKzsCLEQoUMnWMumvn7eYeUPRhXBcjPDJwwbLpump": "DC",
- "AXQyzYRdk6ebp3VdwSNNNFR5Ssm5rMVTP84EEg98pump": "DCA",
- "9fWeqjzb7xG93T9FPaWggTecvyZZDTXc7VgzNWkisqm4": "DMOON",
- "79yTpy8uwmAkrdgZdq6ZSBTvxKsgPrNqTLvYQBh1pump": "BULLY",
- "ZFwVfRtyQw4ark6ci6SNdvgMvTk4iDmb8RZU1SqBAGS": "DOLPHIN",
- "FaUKsgcuqAd9sCaFz3if7ia1DasaxVoNPTXWFs2GScWN": "DC",
- "FU1q8vJpZNUrmqsciSjp8bAKKidGsLmouB8CBdf8TKQv": "TREMP",
- "xABfKiG2KCHi6keTeLycW1iK7B52wJmchSWXu3YrsDp": "DONK",
- "Be63Mpktk95oaSnYaWN5siPBoZDohpNGxc4WNLGupump": "DONKEE",
- "5Rs53fY3q4t4mLk9zBQ45cVNgF1RH7NqRNXiP6Pa5rYH": "DOKY",
- "5Psvm4XSKDzFyXykWeYxWUPFgJDfT4EWQMa6mabCbonk": "DONK",
- "B4G5shxukCDRMLsZue6NDAVMbSzViPn9SFieZG1Ucook": "DBC",
- "BUAv6q4v5E2Pt5ms15uzxhFF1L6rXsG5i4NmSim9pump": "DBTC",
- "87sBZeQCE3A2dkUNs1tPoYHryiiyt4BaBLqorzSQpump": "DONTDIE",
- "RrUiMy3j9bzhgBJpXCqpF33vfrGD5Y9qAfbBVbRMkQv": "BITCOIN",
- "bDz6NVehx5mr8E1e5d2c8ZAqjDe7DQWZeEKPpyvdogs": "DOGS",
- "3iCJnnDYFT4RrPs7vMzw21sfVfy4br1xWmJioz7FGJUR": "DOODI",
- "DvjbEsdca43oQcw2h3HW1CT7N3x5vRcr3QrvTUHnXvgV": "DOOD",
- "JDwzFSxcUvLubUb9xAuuZNvh4bbcEJcuM9TezpmRHVWF": "DOODOO",
- "F6TsRcjtLBzkdtZYqjTPVq9WtnwHMMc1WcQguEgCpump": "DOOGLE",
- "8Fvp3K1KxbDALnyVdy8Pvy8Xw96XVWjpauXLi7pXmygj": "DOOM",
- "7RhcnEJ4Nz5BNkUg5V5vWZaGGiFgnTjEPvLFYLGfbonk": "DOOM",
- "83P1gCFBZfGRCwJuBt9juxJKEsZwejJoG66eTZ6ondo": "DASHON",
- "8Kqmghm1mkXbKYqt2wGnHxwnRdEjD9nayNKD3EanWkcD": "DOPE",
- "3krWsXrweUbpsDJ9NKiwzNJSxLQKdPJNGzeEU5MZKkrb": "DLORD",
- "8uwcmeA46XfLUc4MJ1WFQeV81rDTHTVer1B5Rc6M4iyn": "DORKL",
- "7voKerVHPvbXde3bEpyNcdodVEufq17tW6eZLUUkpump": "Y2K",
- "3KDgfZkd3jZ8S2ZwynouuXAjUXGTgKcp1SM5kZ29z76Y": "MOOV",
- "6m19zvNWYbXS9Y1LhFc1LFXqecE2eErRrR5uNrgbV6Y1": "DOTZ",
- "J6pQQ3FAcJQeWPPGppWRb4nM8jU3wLyYbRrLh7feMfvd": "2Z",
- "Gekfj7SL2fVpTDxJZmeC46cTYxinjB6gkAnb6EGT6mnn": "DZSOL",
- "AQiE2ghyFbBsbsfHiTEbKWcCLTDgyGzceKEPWftZpump": "DOUG",
- "Dsad47jgGNoJ8p4LJQ8x4yCFRMHBL7kd1Js3TJj7X52C": "$DOH",
- "DQnkBM4eYYMnVE8Qy2K3BB7uts1fh2EwBVktEz6jpump": "DJI6930",
- "6UzcYYWb2myAvN86uQ9XAKtm7yQkddacGxktT5RkGood": "DOWNBAD",
- "8h3jsXbvBRPKGGRPhoYRHr7ca8qH3tBeaE2S93X1pump": "DRA",
- "GiBrdw1tF8nuJxWuhTp83ULEMY9uJkYUHQUBzwfEnw5R": "DRAGON",
- "GoCr92MAhiE1kxXyGx7yPdS9qmVxhcJaKN7aNZumgcz6": "DIAMOND",
- "CwcmxzV8KrhJXdzyHs43shCuqiVTMQKZ5MnwmRwrpkin": "BLADE",
- "5uEduS1nkyE2QW1oEZei2pnCN3oym4ziaZ143A7Jbonk": "DREAM",
- "B9zze29or7CJs1nBrigSCWSibfxvkmieFXcGg5cxbonk": "DREAM",
- "HQPWKLGfLDysR3y18jEKTfRUepGJcYM2xCEYhr4ffcVk": "DREDIT",
- "72xMD9BZEEtT7o2C8tXaeYA5QkV53WJ5W83kZKubuCap": "DRIFTY",
- "DriFtupJYLTosbwoN8koMbEYSx54aFAVLddWsbksjwg7": "DRIFT",
- "Dso1bDeDjCQxTrWHqUUi63oBvV7Mdm6WaobLbQ7gnPQ": "DSOL",
- "AZjYk1DqGnLWZzGyyNzYTC5xqUyNRHLhiHXhZdGKUhiu": "DROID",
- "BrYANThKaAbjZZH5XWLrw26NzMbfUNmBwbZiMe4Fj5Mk": "BRYAN",
- "MLoYxeB1Xm4BZyuWLaM3K69LvMSm4TSPXWedF9Epump": "DRU",
- "457PbiajA8Tsh7FqS2Y68ncdXcGobkeLT7GP4mYQpump": "DCC",
- "7woCERDM7WV4XaBLfdGwvHBX3EJHQqp8XjArrgSFKkpL": "DUBCAT",
- "EizEFyqCs2H9134697crr61cfKbepew4xWHU9HPaTUpq": "DUBS",
- "DUCK4JNpgd6SziPDLKP7fogV5KQsAg6Hdx5MCwwYAYuF": "DUCKAI",
- "BavuJ8bntC79A8aHTxQi1EUhcCnqvEU8KSBE4sVCAaHc": "DOUG",
- "97TgtAnya3WC6fDRhzeeV7B5ngLnemP6YFjxnxYxY8ng": "DUCKY",
- "DE8NNksD5m3Kd4ohJAzTwJHLss9zbXdNUegEoL4QxD4C": "DUCKY",
- "HXjiARvkzib4NabiMGS6GPsb5xTGyDpuympVHzP3pump": "DUDU",
- "GP4kcMkX3j3aDSAjoYUPqSSBRYS91cmL6ULYhFzpump": "DM",
- "25HwajZbusQvso1XWA1T41Cd5LVVxHsv91P3Ahq3pcTK": "DUGE",
- "HLptm5e6rTgh4EKgDpYFrnRHbjpkMyVdEeREEa2G7rf9": "DUKO",
- "A2khRbhRJNrAEHj95htivC4cR4VbJwfssDH5FPPbP4m9": "DUK",
- "556BVtBSN6kWVXm5q9KW3FLXoFjmwcMi8C4ztKrH4Xk4": "GME",
- "BMhHXK6XQSGLkX3KjoUcppmBsssUKAqUYwQ68tMzpump": "DM",
- "9re9eKMd39Aaanm8wgFKmLXNVX3ukS5gK4J5aCJepump": "DUNA",
- "Xs1CqRVt2mGVfMSHf7M6cDhkjpw8HDF14XbQNzDnGg4": "DUOLX",
- "fRfKGCriduzDwSudCwpL7ySCEiboNuryhZDVJtr1a1C": "DUPE",
- "2K2EcwAKDjU6Dg17WRwKshhr4Qu29irvRt3GU3uphrKg": "DUPE",
- "DUSTawucrTsGU8hcqRdHDCbuYhCPADMLM2VcCb8VnFnQ": "DUST",
- "eiu9KULXfswbCoZSQQLpTPnWRkvp1Fq3i8gRnsvpFPW": "DWAIN",
- "hqJXutLF6f7DxStrWCrnZDfXzbNTZmvi3KheVi6ondo": "QBTSON",
- "4Hx6Bj56eGyw8EJrrheM6LBQAvVYRikYCWsALeTrwyRU": "DYDX",
- "DTUW2CFo71KnTNSFYX95jQ8P8aJVQVr8MEF1AGMm5WGm": "DYL",
- "2MCmXsjSXHoQYR6ckg6Af4mhQKDMJMGy6JKh8C4Qpump": "DYORHUB",
- "BjjvKX5k7gQoGRmvQAA5WMr7EkQ2cirGTSGxAznDpump": "EARL",
- "ErVrf7WrMS8Rw4b6ZkYSVR5TvMjKRMjSLH8cwT7jmbgp": "EARLY",
- "FradHppu1s67CegxxSARmQmyJ26yCF8soUZaSE9qpump": "EARNFI",
- "BpYiU1dBXU1fdB64jbR93wHEw3Y47QeRLZvUyLQondo": "ETNON",
- "8cVZCdP973kupdt1TktpD4jq3k7Jpr3FiaBAxN5Kpump": "ETF",
- "XsDYSbgLh3T7oh59UmRX1F5WjDgJD3nmzACaG5LR1MB": "EBAYX",
- "FKMdhDBjirErUMQbffsZiuvjptSwNnFW7kf6fvpTpump": "ECHO",
- "BqPqrrQuoQXFGGEAEMnPmDgZ6RWQCajWnY3V6Yp4DZWP": "ES",
- "68dLqMSU3bkooGwH5J244aoXXwTgFohwVnWUeEApump": "ECLIPTIC",
- "APBcWeYBwkBPMtyEj1QGy1AFzEqnYcQcVYCQofjwpump": "ECO",
- "6XYXRpLfs8J2MQESojWa3hDBqdExAUNnMciTdKzppump": "ECONOMY",
- "6wQDzAZT17HYABu7rNXBDUSgNzDeGUUUzY2cS8wpEGAc": "ECOR",
- "kH6hPcpdJqeMAATYU7W4rzqZuzYTkYr6QqGYTLkpump": "EDAS",
- "2Zvo6bnwJtyXhsPgbcfajTrEtB7NwrJhK8mMmtEXvHHc": "EDSE",
- "5g6wVay8NYQ5Tspo4irj9YqSFfQoPDW7apkX352N29PP": "EDEL",
- "5sbZ3E6x84GXtWmBG2vX5pCTLuvCPiwn5C2Yrs3eden": "EDEN",
- "edge86g9cVz87xcpKpy3J77vbp4wYd9idEV562CCntt": "EDGESOL",
- "7a8JSTTMnynE689y1AvxHTywdQVFdpfdE61rPvgzpump": "EAI",
- "65C5dduDBr9LcAmqrQTafStAKPj3ksfk4iTTBKKGpump": "EDWARD",
- "GPrg1CgbBvAJS2SCuf9gF7NmQYsWudfyfWy5SUzypump": "EDWIN",
- "EFFECT1A1R3Dz8Hg4q5SXKjkiPc6KDRUWQ7Czjvy4H7E": "EFFECT",
- "GqmEdRD3zGUZdYPeuDeXxCc8Cj1DBmGSYK97TCwSpump": "E/ACC",
- "4ynyx6BzY2XGFgjjun9Cruj1bSRo8FLsAqNnPsW6jDsu": "EGG",
- "CTEa6FdASurYCQCZkyzkzdwFC4JVRvtpNYrCQQEDePed": "$EGG",
- "EXA537HSBVpsFijENbt6Muuy9AADUN8dUmYKD4oKbjJE": "EGG",
- "egoS1kE1g4JuExTcvG6bB6cg5LWpACQ469uk6DTMuJq": "EGO",
- "5t4EVfkb5QU8NZXmTzcSK2bQsNWUr2HL64rRb8i6wpat": "SPHYNX",
- "Fc7tEqyfHPoWQXdiAqx62d7WeuH7Zq1DHwa2ihDpump": "CODE",
- "89S9RdgynPq5odSRmcCDAzg26iYuRw4wqUmzMbjUpump": "EKKO",
- "3KroURETdWLyFReapbdh6nTWQgS7Y6rorLY8jb1pJXoM": "MOOSK",
- "FgWto1nfArQTpg3o74sYkti753caPfHNXHG8CkedDpMg": "DORITO",
- "2HmJ717Smn26MRn4PzmbGf29Z5d2nU6Jqre7HyELNsX3": "XEP",
- "9mV4WUukVsva5wYcYW4veo34CNDiF44sh3Ji65JNdvh5": "TRUNK",
- "F47vvwFYuLioQsqEVAjqdY6Yihc8wVRiUcfHGcBR9XUs": "ELGATO",
- "G7BJzg55Afx6Tn6J9CJfA444jMf6QJbVjgQAevNTpump": "GATO",
- "eGGxZwNSfuNKRqQLKaz2hc4QkA2mau7skyxPdj7ondo": "LLYON",
- "Xsnuv4omNoHozR6EEW5mXkw8Nrny5rB3jVfLqi6gKMH": "LLYX",
- "jriiULJQwgqdU48hTv1eKqK4ipCiCWBnP9CZbonpump": "ELXAI",
- "5cbq1HriesW4zHpFEk9Gc8UT4ccmfHcBTDCa2XcBduTo": "ELIX",
- "5voS9evDjxF589WuEub5i4ti7FWQmZCsAsyD5ucbuRqM": "ELIZA",
- "6XNxPVyTAWGFEBauPMeVevq5qpszsagzuZzA5SSJpump": "ELGNT",
- "CZQe93LL4f8wuHmTzLABELgZHRwkPZAbHwN9BKerpump": "ELIZABAO",
- "EF23Avq2cTPnMVTfHacZ3SG5Z8misHmFA2gbt2rKqiYH": "WHOREN",
- "5LGyBHMMPwzMunxhcBMn6ZWAuqoHUQmcFiboTJidFURP": "DEFAI",
- "DuMbhu7mvQvqQHGcnikDgb4XegXJRyhUBfdU22uELiZA": "ELIZAOS",
- "CZRsbB6BrHsAmGKeoxyfwzCyhttXvhfEukXCWnseBAGS": "AGENTTOWN",
- "CF5VehjuZvxZZQFP5tybGra6ts574FAwt6Z7GuX9pump": "ELLA",
- "7pL98QbnrMZCe5FEKajSdTTgLn6Thf5CFaozLkayBAGS": "ELLIE",
- "ACWJRei2VGU4tru1oxKHnfoJ3iachwpTeXfEPUNg5Tv": "ELON",
- "BkYAUVMar1gLwuFLv2n5cmB6HhcNtvd86kU3gqAypump": "ELON4AFD",
- "2akXpuyFXAVN5YofZpZMfBp2Vxognpmv9NooBMuHpump": "ELON",
- "GKpETcy8wYHPCB228rvNrqdDR23yyn7Yux6B2rdQRYKw": "ELONRWA",
- "CWX6t6pGJ1zsnuywnyd2ZMZJ7inB2sWuPdsteoT6pump": "ETF500",
- "CCgH8T82ABC7Krg4bR4Jj2yotiDQdzk3yg6GLLUApump": "LOLO",
- "5CvySD4GB7mrp3X5UXHWqQeKn96gxo7rPC71nKx8pump": "ELURC",
- "3RZqq6kMpvziK7Z3m4EVs6DConpnPEnZeb9PmrtEpump": "ELVIS",
- "HmjJLAXm4Q4cWEcFx7sjDtuGujLJeeRAm9MWLhuHpump": "EMEOW",
- "8Qrc2pf9p24NyJVG1FagnqJXwKw6h5L5McxnMfJoUxev": "EMMY",
- "GMkWVrn6A4anxwBqsN5ofk3SjyabYTtQUKpk8c3iKinG": "$IMPERIUM",
- "ExocdWVMKbZBsMo21M6c6SCj7n4k4s7vmUVz3mGvpump": "∅",
- "9XWWHExgN4yvyLRskzzfcr5AcBaqQ6UtwcDSVpUBsoar": "$CPT",
- "B9iPvm8YybydhvMiKAuJuygEKuzspgxdavhFNzzUpump": "EMULITES",
- "3zJ7RxtzPahndBTEn5PGUyo9xBMv6MJP9J4TPqdFpump": "ESIM",
- "9So37icWcKmuMGFPPR36a82Q1E5gZJ6HFSz7Eynfpump": "EFR",
- "9f52wiW2zrt2497HroMHtZtuj7VzWu4AsEusmW3pump": "$NRG",
- "HjsZ73QxNbXoUnyXXffoXn6kHUKQqdy6GXd4J1N4shot": "ENERGY",
- "FqKdy3CtWSKKiJa8aaUbSbSmVhBKz3EiM52Et242pump": "ENERGY",
- "ENERGYi1ApwBAtGLKaeLZ4hRGMuPu1EG8PQTV4EDqFsW": "ENERGY",
- "4XQvdipJBdrb5hUgUrbZPPFmp6BCav41n55dc7KDYW3m": "ENG",
- "ADMiFUmFUz3tzLozh7yTy2zWe1soM61aE995TZqLpump": "ENGRAVE",
- "CuFFw6irQnSV48HwdM4mKGauSwEWqTEztL14kShLpump": "ENKRION",
- "Kruj63Qx9EQX9QzukLCBgx5g9AGW69gPDsSK25FRZAi": "KRAI",
- "4Jsv4fnNp4gwtZ6omrDhEKbmFtpmLAt6nqTqt44wpump": "E",
- "BncvtBGs4JqgYZwUoq3EN9q9HUFqJKTfWpvCsHCondo": "ENLVON",
- "Bp26APthMuM46gMFTo5KYpo7b92GN2xSCor7f9oondo": "ENPHON",
- "5s4BYUXLuvs9ZcVDTxkTpKhThWFSpaU8GG55q2iySe2N": "ENRX",
- "HYnsveQmKoG3qPhWypcgx938widsvJ9BECd9xzmKpump": "ENTRO",
- "ENTxR2RP8NtvhXzMNFCxE1HazzdV9x7SuZqGyAb4jdED": "ENT",
- "eZBKg3P5nBxnDtC3AAWbM33iDp2p1HNtizyS5jupump": "ENTROPY",
- "HyDAnhcj7Er5qVHireifnezrSxhYaauFrDNa82nTpump": "EONIC",
- "EPepv2vbKu53YCkwx1kUAQ6fnyB4FR3kMBvX4aofQAkw": "EPEP",
- "LABSh5DTebUcUbEoLzXKCiXFJLecDFiDWiBGUU1GpxR": "LABS",
- "CvB1ztJvpYQPvdPBePtRzjL4aQidjydtUz61NWgcgQtP": "EPCT",
- "6ep1sNB9UWni3nBZUX84USsRBhKRzMAxEmcia479cWTh": "EPIKO",
- "CSKxPR8FxHXQUE2Lkb8zPFbkCH3315r4d43EM5EWbonk": "EPOCH",
- "aheEdmuryJU8ymy8LjYheZH5i2BW1UMsfuWQKD2ondo": "EQIXON",
- "HAUWqZTnQNhSqC3AG4GYtuoqTZMi3ywvgqWMyKC7pump": "ERALAB",
- "ASRNzwDpYWseimGQh3GootWLphpuMe3cUnpoH4mFbonk": "二哈",
- "6MvV5hjy11Szm7HmLciZepMJj3ez9xgLWeFKozFxV1sS": "$ERNIE",
- "FjbRf3EcoG13CKrpif9c2BuJuyy3T7r6dsp9LKMvpump": "MONKEY",
- "28G7z3VyHDFNhrnvSTf1GssKoGrtCrdiguASQy2BsHiF": "ESX",
- "Eh6XEPhSwoLv5wFApukmnaVSHQ6sAnoD9BmgmwQoN2sN": "SUSDE",
- "DEkqHyPN7GMRJ5cArtQFAWefqbZb33Hyf6s5iCwjEonT": "USDE",
- "EsUEnK3Z26CTCGvFFZb2wLVgUSkYWdKyhZZeBq9P6rz9": "ETHM",
- "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs": "ETH",
- "GiLTSeSFnNse7xQVYeKdMyckGw66AoRmyggGg1NNd4yr": "GILTS",
- "KTBeXe7VMPMLxBsqDQu4KA9PdSajF3Hkw1y9qRsKqfL": "KTB",
- "BRNTNaZeTJANz9PeuD8drNbBHwGgg7ZTjiQYrFgWQ48p": "TESOURO",
- "HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr": "EURC",
- "HQMYCZTDq9g3oZejDRUeQsFtLKgyfvBpD3yHaTnain3L": "EUSD",
- "EkiZFKi1xYwdWukkhoUmDUWDU6M8bujakCC7P3Nebonk": "EVA",
- "4gfNpwo8LQtcgGrNmgWhuwfFhttgZ8Qb6QXN4Yz8BAGS": "EVA",
- "GFUgXbMeDnLkhZaJS3nYFqunqkFNMRo9ukhyajeXpump": "EVAN",
- "GMt7BjkLUPFA9vjvbAbb94jYTj9gHqEEnUknifuXpump": "EVE",
- "CgzdCjj5YNH51uFfQftFbuJKMrwgdWheVjwqjU84MV8y": "EVERMOON",
- "EaC6EBUBtNiqZoDEnE3qJ7SDPn6zUzqH6SLzfWWqEVRY": "EVERY",
- "8MWLo9PmNiunLFhCZsXBsHqmvKrxTjt3qffFJF81pump": "EVCN",
- "CJ1azXTKcixgXVKGGocVkcJAQKytRHjcbMVWoRQcpump": "EVOLVE",
- "2jkMKiuKmcuQUa9pdRqSByhGGSwDwLuKuCZUppR1pump": "EXARION",
- "7xhB6DFcoRFtY1pHxxkMRbN1MwuNYjsqx4zWqzu6pump": "EXCETOR",
- "ARTtpGGVYbVH5LwPNgD7Kta5U4fMNAPNoJcge7iadTL6": "ART",
- "7RT5zwZG1hhfparpKgh8WvSnPxJB8FQ529VSyaNKpump": "RETAIL",
- "CG73o5Zh2oGKjG9urvpXQR5S3jiSSzkkBf9GomNTpump": "EXO",
- "FqveHfaf96iTjA3KgX1W5LWPnLFYv8EfUf6TQSWPpump": "EXO",
- "3DBudkWQNbXGAjzEAtpjMKorb76sjozcHCzc8ZtkHDAQ": "EXOD",
- "CJRoTbu98waCCuLFfLuJ2kXawLk889fqW4UAAbwondo": "EXODON",
- "EXoMAHnw2Gw5fXJTektedLJDVn9vn8tLTEQX7gHccQKR": "EXO",
- "XsFj75v4Tw8TWSDaDoVTHF8RAjEEkmUeKgoRjB9DHsf": "EXPEX",
- "H7VfCzzPJvnqfs1b8uA9uUuVjXiYfzAUDw5gmyV9pump": "EXPERT",
- "E9SmMCvtLfitMwkLzkduwgN8ZYcfepiELLQ8d1SApump": "E=MC²",
- "GD8nFZrqEaXkNzPJAmA4ULjMmftoVfBfoGduWGEFpump": "E91",
- "qCYD74QnXzd9pzv6pGHQKJVwoibL6sNcPQDnpDiondo": "XOMON",
- "XsaHND8sHyfMfsWPj6kSdd5VwvCayZvjYgKmmcNL5qh": "XOMX",
- "6MAWnfagDCzqmHQh88FVt9F1zzLqXpwGJpaL7zUTpump": "EYE",
- "7x4FgiFfeqzs1tiUNvJzpt47GtLXAJ8Jfn8G1Hyyu6JH": "SMILEK",
- "66ce7iZ5uqnVbh4Rt5wChHWyVfUvv1LJrBo8o214pump": "EZ",
- "GSwzg99Dyinar5oFsKT7WW5E4XJDw4ac6tPwM2bUM1WK": "FACELESS",
- "FuVJN8aHZrBJESbX5aq8tvNEWaBucxtq1e82ja1hpump": "JOY",
- "FaDErpochTz2uCFo3ZSGxEfrXaHoK1kzjTRYFaegG4Lu": "FWT",
- "BP8RUdhLKBL2vgVXc3n7oTSZKWaQVbD8S6QcPaMVBAPo": "FAFO",
- "6jEp4iQeLYJuxF4vUeiESsVJH1L16HhjAnuyQrz7pump": "FA=FO",
- "5gsDMgG3p1xZR7qvbS88EjNSDesBdJjYH7PGemUgpump": "FAHHHH",
- "s1bYcu6WSfRznQbEn4tnXaNVHRpWPzVz8mPCvHrpump": "FAIR",
- "Fairr196TRbroavk2QhRb3RRDH1ZpdWC3yJDTDDestar": "FAIR",
- "A4axyAWizMWvgk7tfPC9yrVBYCpdM2Aoh5RaU7RKpump": "FAITHCOIN",
- "6mgqeeGHE5GrVk9fYdeJSjKTFZV1TVNAQTMYdHjfpump": "PINHEADS",
- "LVCQ1YmeK6DECKqcwmscyDRxUYJpiGth9ppGKtopump": "KNIGHT",
- "3XHafP5M87BvqtwCYBRGvdKLQfrFtCh4wXzBQ5BKFLAG": "FLAG",
- "Afo4NumBNHDXc7m7p6qjZ1pF3LbqYfG5k1CNrGve8rVu": "FALX",
- "7njsg9BA1xvXX9DNpe5fERHK4zb7MbCHKZ6zsx5k3adr": "FAM",
- "FoXyMu5xwXre7zEoSvzViRk3nGawHUp9kUh97y2NDhcq": "FOXY",
- "J5CpjMaYHYdZu2WBUPT79mALDJM14FKCiVVPwUDcpump": "FAPCOIN",
- "GvhKJQGSLsPN49AM4cHS6YSDZysPmP5zq3E3Shwubonk": "FAPCOIN",
- "8vGr1eX9vfpootWiUPYa5kYoGx9bTuRy2Xc4dNMrpump": "FAPCOIN",
- "BDciduUgepb9DehoJ1CDK1gqNkUUKusQP7PwHr9cTwX2": "FAPTAX",
- "FcpeGHBBpMrgdaiPT6LJNSxBE8Y5u8BDb62CrFVyWNDD": "FARM",
- "Gvu9p88rVTRTdzz2UzMYkKRobfTWDyBHJGH5G29boop": "FARM2",
- "y1AZt42vceCmStjW4zetK3VoNarC1VxJ5iDjpiupump": "$FARTBOY",
- "B5X3YLev9bUkLuBJsjA9vMkpRxSLDgStDwofBLvRBAGS": "FARTBOY",
- "3dk9CNre8tmv6bbNXd5F6dgkNnEzsyQ7sPhVT8kKpump": "FARTCAT",
- "9BB6NFEcjBCtnNLFko2FqVQBq8HHM13kCyYcdQbgpump": "FARTCOIN",
- "EJUbsyWDuJvnHSWQYXMnqcqD4XefA9WM4ftjZtSmpump": "FARTCASH",
- "2ZqgkCpvXjzB4NstzBUPSrsYrrbziUv5mC9CsxSQZryG": "BUTTPLUG",
- "59Vaf6t5viekuPJ1ehPL3hRC8DXxPGLTFfM2t8tgpump": "FARTDADDY",
- "9jBxPfYJmaDuvpWT3b2J194NYrBWksxhNMZxvi31pump": "FARTDOG",
- "493AddQQYfn1i8fUN7QtMupfXuGHehzzTKVVQXZD25Y7": "FARTFUL",
- "Cjrrc595e9R47EZ3gkbUmL6ZZpLSxiXg16v2Y3Aapump": "FARTGIRL",
- "HS9MCtW3Q2R3GV2fjPTkSL66tGfNQaSMvjuSz4Hx5wCP": "FARTGOAT",
- "3siTgKmX1oWFvKzKtfbNKQ8MFq9kRnA8wQodhbwYpump": "SOLANA",
- "EzVkdRYRACWKQeY7fHg4BBL7gx8WC5DvNxWm4ZA2pump": "FARTGUY",
- "2RA1v8NdkEQcF5N5zHUqLuAHxjnDMQFjwEE8fwKNpump": "FARTHOUSE",
- "5S82DHVy5s5TcdaACov9an2qHcP9Z68ZGuNsRDPGpump": "FARTHUB",
- "CDDybYjY6y7RBKXXaCKHRhUhb31y3rjGB7idTdeFpump": "FU",
- "FyrBf5xKg5EwKZ9pHvSpJeLLuCWBicTpm3VvZcsibonk": "FARTLESS",
- "E2Kddk65HwvevojHnZgQaDE8Pbd3e4FZrVuEz31Npump": "FARTPIG",
- "FSTRgYfDaudjDwFg5A9LQpDMq5vxqhskHq4rkjUMwERE": "FSTR",
- "9zFU5vR7YNBzZU8HwJLUKjoDEonpgvHUdLbMgBa7pump": "FARTWORM",
- "7bXRKw7pkr4SNgeSyJyVQNaMDYvnCgCr2NwRcWJNsAaM": "FASH",
- "HQAuXaZMgRg3y29Yc6N8BezZWZnP6Tk8FJdKmxinpump": "FTW",
- "DXCoKQ7iLpux398fNHewQn6djfGobzFuPiR5o8hrVHAb": "FATALITY",
- "AHdVQs56QpEEkRx6m8yiYYEiqM2sKjQxVd6mGH12pump": "$FATCAT",
- "4y9E3tJpGNzRr1592oWTPECgyp2VDSc1Bf3DqAm5FZsK": "FATGF",
- "3k25pZPecCgbkdPt7Q8k2NhRc6LtM5hg3HHfdz6iPnxA": "FAV",
- "54FTD2p5YW8iTrubQKiQ2DDa9UdKiTYNN32D7mAdpump": "SWAY",
- "9NiHcbT8EohKJid1RdU3232tATmM1CvYemTeCP5iwro": "FCOD",
- "DRaT4y4f55shDuBnpr53EZs8jKnDWAnrJifjGLkAoYxa": "FOMO",
- "5j2shkkzascw33QpW6RRqfRkacLkn7QwwV1e7jX36nyn": "FECES",
- "a4WcyMS183n6anrtQ5r9i4YVX2VuT7b2h3NywnEBAGS": "GAZA",
- "J2eaKn35rp82T6RFEsNK9CLRHEKV9BLXjedFM3q6pump": "FTP",
- "7QnHsqzjRDFSq4YwJRH5RiHh9SCNbH9k3UfubsmRyYWX": "FW",
- "aL1UNC3fZpUSQHsQAe5id9A1Ga3UNCZsnxjgUiaFLiQ": "FLIQ",
- "GMbAink1cNVWGa8uH9k6t6Y44sn6doD3BVH2usCP7EZV": "GOOD",
- "FnixeBNA3YXU3JUK9gTeHjDv9t36YGUyuf5Q9od7tTVV": "FEENIX",
- "AqwCfpkG68KgpXXKT5PgnuUi6YJCAcHRtEQKXN9LBAGS": "FEENIX",
- "7CPBU6CL7GpjzM2DRr7HVoy7TGJxvHkPHWxfvEZypump": "FEETCOIN",
- "Fjk4u44UQFo3Wb2vhPXE9FSjngP8uNJJd6Jzd5JJhD6x": "FEFE",
- "BychPBYgrmUeRE38qKqs6Tx4Zo5Rh96Mcp9Lu8PUXFVv": "FELICETTE",
- "7DptUgc1aRY6geK4WnauRKTTfVFWmLsBWP275sD2Bg9r": "$PEOW",
- "6NKqYaVGC7H5cyKekgPMeHrb1REEXGEeBcpxqWc2g8nc": "FELY",
- "65Z76ENVtuTVohmGeSMVAPW7ArRoUByZspCN3Yb7k7p": "FENTANYL",
- "H3EY9q3rVxnUe56gF2YX6SJ5q8YAUbyNADyc2xPLpump": "FERG",
- "DZq1fdJfGjv27Cev8hNFZXJwhApB3xHpo3KMTTRvpump": "FERGANI",
- "6FLqdVizDf1ESwCanSzAtysS8pQeqzDDmdieADgBpump": "FEC",
- "HUtnmegDSBQ823ceAaDX6GemXZ4UUgy2eNLnY5Tepump": "FETCHR",
- "J3u73qgyeuaeunH1uwsT6QLFa24YNeZSjSEdCjAebonk": "RAGEGUY",
- "BJhPr9SM7uZTZXHeSLYmUk7CjGQq1esFkVxPF5tondo": "FSOLON",
- "KMnDBXcPXoz6oMJW5XG4tXdwSWpmWEP2RQM1Uujpump": "FIGHT",
- "8f62NyJGo7He5uWeveTA2JJQf4xzf8aqxkmzxRQ3mxfU": "FIGHT",
- "aLDdFsr3VTUQaHFK6yNvQxztvxQ8nxW4AMuSGC7ondo": "FIGON",
- "XssfYT48PeXG2EmNdEaVtQcveNhxYnM42KTqdjmiBS9": "FIGX",
- "ZmHxc6Gt27RJKxD2ay6UL4n9yQ7mKAq4XZQUeVhondo": "FIGRON",
- "8SkfuQkYNTskoQUbbjr2JbZQeqQV9egnJXgfMXf5bonk": "FIH",
- "A9e6JzPQstmz94pMnzxgyV14QUqoULSXuf5FPsq8UiRa": "FIJI",
- "AKE5B588aZgt8WVioWRUVSp7XxdSJsz9GRDErC4ua3Fv": "FILTER",
- "AU1rxhY276GepM4bm7VaYrgVPJW7tg4z2MtR2jfPpump": "WIZARD",
- "758yZPp2QEmrMgMACiUS2K2sTLsfSw9NprWoGxdxbonk": "FF",
- "CLFR99t87xxRQtEtkWkrGj82BiJ2228h7JPgkLWiZ45o": "FINDME",
- "8bmDcRBjBfcoAtU9xFg8gSdUzvjK85cBmdgbMN9kuBLV": "FINNA",
- "Xp8dC5i7EcAeZo873ijwvipt3pUbgvgi5sHsg9sBAGS": "FINNPUTER",
- "5XFeFezwgZvSdG2N69FPBuz98uFpfBCkFcXQXSiGpump": "FIREBALL",
- "BHKVuBNfsK3Pre1bmfG76NbVt8xrx3Z5DdFtrsoVpump": "FCKN",
- "9NyeEdqoQbvZXdyam2eTwXGNB3JgkcUtTexSW5yJpump": "FIREHORSE",
- "7Eofgc3D5G3CJf2s6NXxCaFKN7ZE9eEauGPBL11dTqDa": "FIRE",
- "BD7jNnt6uYDp9rVRBTjJhkweGxYQppRe8CXLnAJspump": "SNARC",
- "AhdriVFckrSmt6xfXVdNcKA545bKvKgJQuk1LAnApump": "TILLY",
- "8nzCP3xmkpKAq2un87d6Jgg4r3JnvgUSkFemfLbFpump": "ROBOCOIN",
- "RdTSEwJwHA8vh6BALTu9hYVYv4FgWDS5JsK9hnApump": "TPU",
- "CNvitvFnSM5ed6K28RUNSaAjqqz5tX1rA5HgaBN9pump": "FRED",
- "APMrwq6jxn3yvHJ7BWsitpMjZV14MCzgno8pEHzgpump": "FRED",
- "9zNQRsGLjNKwCUU5Gq5LR8beUCPzQMVMqKAi3SSZh54u": "FDUSD",
- "BE9WCtE9p36RX4kmsN5VDd8MSc5QwJQcARbSL3R8pump": "TOSHI",
- "9AgTccePC4WyQQwJu9GYqAVUKyUyh1prgzkacMaCpump": "NEKO",
- "8T7RjdERSeQNqUhthUgEEUr33g6xdVVxND5YmgjSpump": "KEKELS",
- "6T44rfi9BDUdZbEvVddZWVfsGrpC6N1sSSKYnCsLpump": "SIRIUS",
- "ivBnfPTyuHDNWmMSnbavckhJK6SHZW8h77nZKsEondo": "FTGCON",
- "BVdL3WUxtxUD4vXRWwqChJLbGxvfzZjBGPp63Wtondo": "CIBRON",
- "Bz7Nx1F3Mti1BVS7ZAVDLSKGEaejufxvX2DPdjpf8PqT": "CHIPPY",
- "HM1qfMccuwNsjPTLUY4bHiYF3bSYzn65hZ5vH1P2MiLL": "FSHWHL",
- "Fishy64jCaa3ooqXw7BHtKvYD8BTkSyAPh6RNE3xZpcN": "$FISHY",
- "CHiNsA2B6ZbmKnEmHPCbbX9aXJyoJzAtcLpHEDd6Qyq3": "CHIN",
- "9kvTPjemayUL7XKPyjhqavbcLtY5VP2ha1G5vPuppump": "FITCOIN",
- "Cr2mM4szbt8286XMn7iTpY5A8S17LbGAu1UyodkyEwn4": "FITCOIN",
- "Hvcmd51zk2vVkeAkYbNgSKsAX17hof2vLsihG9J2pump": "FITCOIN",
- "EgrWay6HeQV7VeZ6CiKuLaMJDESZa1woKuznhyTEpump": "FITGIRL",
- "G1FhY1k9S4Q8P7zpuaQAnzZ1YGwwyiVRQF7EHncMpump": "FIXI",
- "GWkA9fwAtJDb8BfBAabRY3w7x4jQrboLZd9iWH1v7yuB": "FKETH",
- "BivtZFQ5mVdjMM3DQ8vxzvhKKiVs27fz1YUF8bRFdKKc": "FLAME",
- "3vADYnNebwAzPGphyYAoPtCXw1H6t5yFFbCCy4JBpump": "FLARE",
- "NUZ3FDWTtN5SP72BsefbsqpnbAY5oe21LE8bCSkqsEK": "FLP.1",
- "H9BkzwHKyBAnKmaxuLPKKRZGu8whbigdhhqQVkRapump": "FLASH",
- "FAFxVxnkzZHMCodkWyoccgUNgVScqMw2mhhQBYDFjFAF": "FAF",
- "FRCncx8MiY2QAVj44kcsR8yD1QoF1WNuokKGhNj3jPeg": "FLAT",
- "3HYx6a9whu5a4dnzE62WNXg46MrEmu9LFxutR2YBpump": "FLAVIA",
- "DezaX4JqtoZ9TdUZ5eGbPtQtpzkQFDERuWUMFgnypump": "FLIPCOIN",
- "JCBKQBPvnjr7emdQGCNM8wtE8AZjyvJgh7JMvkfYxypm": "FLIPR",
- "DWjVPqEX4fPFQ47Xb7EegpGhgWzRviYfPoEWPnxz2CRd": "TIM",
- "9XkR8j3ygnygzAcQaURpyE9e5kDb1gqAbJZxAwzZpump": "FLOCKY",
- "EcdKnP5PsjzWBzk4Bmqzp8VYi5L7NAGEPM6wK5K7iW2q": "FLOKIS",
- "FY4rNz7AqKEnEwyurmGVpoEBnSq7XqNn4YuXruvJhAXF": "FLOKI",
- "3jzdrXXKxwkBk82u2eCWASZLCKoZs1LQTg87HBEAmBJw": "FLOOF",
- "X3rigWZSJhEE5DCQVWhnEChpWkJyHfidwXUSQPBpump": "FLOOF",
- "75DvRjTDpaEbrdUHVomdjfsiXbBi5FwNyctyUgfLooS": "FLS",
- "CQNZNo4bNVhsnwz8EfaYkq43xFjrQqXjPrYUo4V8LxU5": "FLOPI",
- "EPbztGmoacJ2ns3pYx2FX4xRo3qD1MsnJCy2Rsdopump": "FLOPPA",
- "F6Aj973E5vGHyGnVsKC39rAFwnFukF11JmpPQ7xPUFF8": "FLOPPA",
- "CnGb7hJsGdsFyQP2uXNWrUgT5K1tovBA3mNnUZcTpump": "FLORK",
- "HDzTPAndwe5XRvReLzLdUNaNCkbVv141ELZ2AGKGCpAA": "FLOW402",
- "HEHT1eKNsTnuMAQaSM4ac8r3ynckmquxA3hUun5Npump": "FLOW",
- "AVyjco9j8vv7ZPkhCpEoPJ3bLEuw7G1wrrNt8DrApump": "FLOWER",
- "26QT2xABFLvK7LyAjF69xojVCnJwexBGj7WfJaRbpump": "FLOWEY",
- "AjPzK6Sf1G27jFkFe4HViSNqMxa3JLE4D1fm6Pzouq2q": "FLOW",
- "Eh1fXbAipe4k7CYR9UMb2bbWmBcpU3HcyX3LWuRVFBLz": "FM",
- "GYKBbafCYFwd9gYrZuVQ4yYwdHgbxJ1HRQh8jN6Apump": "FLOW",
- "6CEjCg7Jo5RV9kFSgKx66rpW19nrsCmccD2bxfwpump": "FLUFFI",
- "CoRkC3r6MqYuTeMRc7D8JJF7UiUyFWurXGpYy1xQATNq": "FLUFF",
- "Ez2zVjw85tZan1ycnJ5PywNNxR6Gm4jbXQtZKyQNu3Lv": "FUSDC",
- "FLUXBmPhT3Fd1EDVFdg46YREqHBeNypn1h4EbnTzWERX": "FLUXB",
- "BCXpjsHYmgVpRKdv4EQv1RARhYagnnwPkJjYbvM6bonk": "FKH",
- "FXDXLCWYMXmhhMypVxGHCC2sHA8n9d2fHhePViAYpump": "FMC",
- "3BHhMXMyyGGzLcTk6u5iJwTcV7eEGG9bWJrTKUttpump": "FML",
- "5qsZAnWuR7vMJbiznrJEY2ddVqZXjNYmFvR3eXSxpump": "FOCAI",
- "6bdTRHhdZenJQYLTxaYc8kH74GBNP9DoGhPnCjfypump": "FOG",
- "CxiR3c9AGqMtE7bg82sLnzpLinXN3kXfcoYeYtGApFoG": "FOG",
- "Cx9oLynYgC3RrgXzin7U417hNY9D6YB1eMGw4ZMbWJgw": "FOMO",
- "ZxBon4vcf3DVcrt63fJU52ywYm9BKZC6YuXDhb3fomo": "FOMO",
- "BQpGv6LVWG1JRm1NdjerNSFdChMdAULJr3x9t2Swpump": "FOMO3D.FUN",
- "B4gipVUHKJ7keVN3MWEYDQCHjkdoXGsbmZoTSJDZpump": "RADIO",
- "A3GCAAwFxAUgx97j9uw8Vkf8MaFqUut2tsyAXq9Cpump": "$FOND",
- "FTkJ6EjsTLpmQUU9cgbtHjhXuBHrwY6UGRsrgWKtpump": "FFG",
- "EcK2evV2cDECVsmvY2FxU51eu3fp4w48zrZxuA92AAAN": "FOOD",
- "E1hxSfVi6pQhT6tcyq3FT4sEhU9jWdxD6MEtJpGDpump": "FOOTBALL",
- "8cn4JeRLiHTtfX6maZAsipGGyyZPdEcos3s2X3Hw3BS6": "FUN",
- "EUdQbKfHucJe99GVt3HQMUZCQtWtvXFyjvrqDWctpump": "FOOTCOIN",
- "5hT2o25X9tGXipwhLckaUdgnxrZ6Y8eiUwdhpLeondo": "FON",
- "BoAQaykj3LtkM2Brevc7cQcRAzpqcsP47nJ2rkyopump": "FOREST",
- "5cQtbxhPTVQJVKKiQazpmQpSZzEJaZ86F55sFpYvpump": "ALONE",
- "8AdsF2QXFA8QkFuQ9TrQW6nEyM4E6yT4AwqgZ5cTpump": "ALONE",
- "aSCcjVmMJttZQNYtzhFXmqmUiTm8xkJBggn4sj8pump": "FOREXLENS",
- "foRgE7d5FRtvQ2jf9yhV9Cnd1LMB3rxk6dpE7HYdzGk": "FORGE",
- "GqcYoMUr1x4N3kU7ViFd3T3EUx3C2cWKRdWFjYxSkKuh": "$PURGE",
- "66LPmREAYBqPeyidL7LMW7RaJjKbfADbuUMsqatkpump": "FORK",
- "Z6RHtkv5xrhpHwswaHSP6W1GQkhgqH3fAcA4NHforma": "FORMA",
- "HZ32SiTtw3kYyaHTtTfpHVF8EyXFcy7MBQXeFpnNvQ9c": "FROG",
- "DtgCVZ877swr93rHXhbfshcthnSK2Ds4dz3XC8GYpump": "FP",
- "7GzQgf6DPo6ZANjnbhe9tNCpkGTv3zqHbsDx74jyQf9": "FWDI",
- "3hRfeCUc3NuSEuZfsLBpi2X6AUcF3jRKbCdPrpKpmoon": "ONE",
- "2ZiSPGncrkwWa6GBZB4EDtsfq7HEWwkwsPFzEXieXjNL": "FDRY",
- "3roGjzv4TeaWFN8VN6hfUKAsmoVUrYmmB2Dz3NYF1GAA": "FINU",
- "CgGWS19zR5xTzgCEcW5Svsuon4hBZwzBwUFimoJStCf2": "FOXSY",
- "FRAGMEWj2z65qM62zqKhNtwNFskdfKs4ekDUDX3b4VD5": "FRAG",
- "F9mv7XXbrXZb1sP2JUoswbCB3WHQM4QGMFDTVfnRZMnP": "FRA",
- "AYhFJk9ZyKN5aCRwrG78iTvuxnrrLp5q4fGfyBM7pump": "$FRANK",
- "CYAwMGyuNSDu7NpuccNwcxMNS5Bu9akxU2Jooyiondo": "FFOGON",
- "CZ3FxxSto7tsjkSkqMek1C5p3RCFFmkwKqW57nbondo": "FLHYON",
- "D8KT4Jd8qiKKTfkM8ejSKCpWGR1o3GFvnQGp5ERondo": "INCEON",
- "CYqLHM92EhmF83iNgfN4A1j2ckjsHigRvXu7xHCondo": "FGDLON",
- "5Tu84fKBpe9vfXeotjvfvWdWbAjy3hqsExvuHgFqFxA1": "BENJI",
- "CZ9GBn1okotqKNUUqoxk4PF2JVi59bw5GWvVo6Dondo": "FLQLON",
- "6LX8BhMQ4Sy2otmAWj7Y5sKd9YTVVUgfMsBzT6B9W7ct": "FRAX",
- "GzX1ireZDU865FiMaKrdVB1H6AE8LAqWYCg6chrMrfBw": "FRXUSD",
- "5arEQv5tGJj8UbhnPrc1WL5KMmijCe4FuexCaEXUBAGS": "FRED",
- "GYyyeA8Pzp1Biyzp26fvFXaB3Qm43o8e5CfXseVjpump": "FREEBIRD",
- "FrEeWJreTHUyPgdJ3DWrdRg6X8qogF5zG5qdxMCgXtTy": "FREE",
- "moonskJwNmZiwkqH79S7b1UezGTaWQGEUbFkVqH3Vwq": "MOON",
- "CY8ttw5rYCT6fFBJwqXofefqa7Ji9E8zfLmhRLmondo": "FCXON",
- "BpAiFPCqjvnz7ETKjxr6ZpEKKnGGBE7rNZUU7A7eBAGS": "VERDIS",
- "AyxrBmqbzf169oe14XcSDMbgpUV1ntP6thcScYpYpump": "EAGLE",
- "F9GqoJRPzQnGzvP7cQzLHB7C22DToHQYWfsPvhKwqrpC": "FREGO",
- "AzVCECC5zr21ikYQne4Xtoh3SVg848duPHUHb3M7bonk": "FREYA",
- "EsP4kJfKUDLfX274WoBSiiEy74Sh4tZKUCDjfULHpump": "FRIC",
- "D4Yc5xRjRYcjxtnYG4Ay3mKLYMMF91RBnbuoKk7cpump": "FROG",
- "sm6LoSiRQLM28rMgcd8GtR5XBkZFMEYXgEUgwCxpump": "FROG",
- "6NspJqVFceCiU5D1YgVq7waYoC394Vhqxwg7cSJdFtVE": "FROG",
- "peen77qWZw4XQkvxW1QF6MUJyKNLbqvMzqhkKpB1aVo": "PEEN",
- "5yxNbU8DgYJZNi3mPD9rs4XLh9ckXrhPjJ5VCujUWg5H": "FRONK",
- "FRNTPi9V3Sw9b9U8d5Q3WY7tNANT6Q394d7dYtv7Jdog": "FRNT",
- "2pngLT6YDApMFLV6uzhffDLR4aLJXTD3AenpkJNrrZZB": "FROSTY",
- "AXzueZQiCjJStGPuGTYt1jyJdG7pcSwjVorWmpN9vm1i": "FROX",
- "GmTH6V13rHVXeNdmDfh7VQeS2Lj9YWRKT5XjDEA2pump": "FRUG",
- "GP7m3USdHDSrNoUzsZqZTboKaJiabFQShzgV2RkFnZyh": "FSJAL",
- "8Gzb4Le3rUkDepM6xtaj7X6cN1xxbrHNXqtMb8Pipump": "FTF100",
- "AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3": "FTT",
- "4P6gQYnZ2AvwmAr37GCeUq1vyk1PQJmXnuA1QFRKGHkz": "FUACK",
- "GyK8nknBB92EEEq2LEyUbEcDwjZ86eF98m4Kbrmgpump": "FUDNA",
- "Hm5icDFBPVyVnqxX7VADnykZw7j55UP6ZSuMnyrFttGU": "FLAME",
- "76Jkgbh2v5pdqBvSKStyxL7Q135dDcuh4eatCFvpump": "FUG",
- "4M79Qjv2Jfjmcq19M41V8QFYohBv2KrgEn9dJhVtpump": "FUJI",
- "2KchKijPuwnwC92LPWVjFjRwB3WxKtzx9bbXZ7kRpump": "FUKU",
- "n669kahBTdMjYFgXEfQcc25ZbWur1Jz29csDzPJpump": "FUKUROU",
- "AshG5mHt4y4etsjhKFb2wA2rq1XZxKks1EPzcuXwpump": "FULLSEND",
- "G849nDx4r1vwjibbmpjkZ6pbDWwaMouhkWLq1o8Z5FUN": "FUN",
- "JjGQAsJBRQLYmBj41bgZggVLawaa4qoSF77NJsRpump": "FUND",
- "3u4XvCjmTmQmcvjoxo1z8y3wnRdtnCuv6N9WkiE6FJvH": "FUNGI",
- "FW1r2jQtFjc1dFUUYYZDkeQ62R6fWo4ucty8vpP7bonk": "FUNLESS",
- "Eqpvgps4py3nDkgvRnVGv7JsSwBF3oa3i1Zvaszqpump": "FUR",
- "866Sh46xjH7cW7aW18tBUmGm3xh6EzGTk1Li7YbbmqJr": "FURM",
- "DQc6FTgu2HiB1PMUkHj8SATCtxsCeeMz5hiaqwk1pump": "FUR",
- "3naMj3jj6877gfXy6VC4fhaUPkwZ5Y7y8UWi5QeXbonk": "FSR",
- "Cbjr1Nvcay3QWDriyRKtokJ7V4PMknesGxeK8z7Zmeta": "FUTARDIO",
- "Ao5rKFRQ54W3DKSAtqfhBRPNHewwWRLNLao2JL9ondo": "FUTUON",
- "82mSw24TxU8Q7kRkXMj4Ey3jaHKLYgWxoRdEA256pump": "FSX",
- "9v9gJt4EymZh9iHLpGGGgX5eXQFMsmg7GKR9Z2xfVeix": "FUUU",
- "A8C3xuqscfmyLrte3VmTqrAq8kgMASius9AFNANwpump": "FWOG",
- "92cRC6kV5D7TiHX1j56AbkPbffo9jwcXxSDQZ8Mopump": "FXN",
- "7YHPdtmjuEmgEA9bTWAWNSULacbjADxEKENL3XWL1RXC": "NOOSUM",
- "9uTekAxmx4rqBcR3iGkKmaBwVWMmi7TXEU41frBdBAGS": "GABLE",
- "2EH5Y18tw366g3VQvXKXKhr4zhYD6sC8X2Ktw3ocpump": "GABRIEL",
- "76VxJbMFoCXBcn2rqPQX2UsUfpupq2gVwGSq5LyYMhr2": "GMRX",
- "53dig5bMmYBGNxDXAGFNjA59mqry3piqTpbFzYKEpump": "GAIM",
- "FFgfStKwuF3DSxEeogA69FNkPrkb7XDA5Tw29TBEpump": "$GNZ",
- "96ugdN1zEe1RShH1xWsMLBbopDvS96WXfvxwRELqUwqk": "GAK",
- "eEUiUs4JWYZrp72djAGF1A8PhpR6rHphGeGN7GbVLp6": "GALA",
- "3ZELuj8iVdekxTR5a4SVG6VkgR7pHFYTLvyuLJDURSs4": "GNET",
- "AjdCzXwien2FmTx3GDZeA6YX34A6rzhQCCZXSa7tqXJ4": "G-BONK",
- "6Z17TYRxJtPvHSGh7s6wtcERgxHGv37sBq6B9Sd1pump": "0.000001",
- "9RzDmj24vh74z3d5mYvtyxmGjHUKNUYfvQGh8qxVpump": "GALAXE",
- "2HehXG149TXuVptQhbiWAWDjbbuCsXSAtLTB5wc2aajK": "GLXY",
- "CkWmEM2J79k6AjAwyQVHXteFucAL1zQrKLxLqJHondo": "GLXYON",
- "Xs3c2aZenyRQwXjki5MDxJEJ2km27ef2rWQMFWx7QKJ": "GLXYX",
- "9FyERA7vjSDXVEGDskjYjTfymQ7XTqJt6dbVDCWmpump": "GALI",
- "FRsWUe7PUjWgxitDxFhURsHZuemsZwXtqT5R6QvRbonk": "GALLO",
- "3wtnog8YQ4zoY13p8tqwgL9GWz2fxNyQQVJY2kSok7au": "BALL",
- "GKZbA2gDzw3MoxbfRsnrJTNi5uBDrnrz9bq1pNnx6kv": "GBOY",
- "8ULCkCTUa3XXrNXaDVzPcja2tdJtRdxRr8T4eZjVKqk": "GOME",
- "Cy52Ts2GwSzdkhCihB5i1Vu6sApzgqktNNFyHbsdgwm7": "GHX",
- "aznKt8v32CwYMEcTcB4bGTv8DXWStCpHrcCtyy7ondo": "GMEON",
- "Xsf9mBktVB9BSU5kf4nHxPq5hCBJ2j2ui3ecFGxPRGc": "GMEX",
- "Dz4bX3snTDxqdKyZwdUgKoDvSjyvmoA23E6j5odZpump": "GANY",
- "CKaKtYvz6dKPyMvYq9Rh3UBrnNqYZAyd7iF4hJtjUvks": "GARI",
- "8c71AvjQeKKeWRe8jtTGG1bJ2WiYXQdbjqFbUfhHgSVk": "GARY",
- "5SRer48NRfmhsut1n4ZwSAVUJAErNjdKcXTMVaxdpump": "GARY",
- "CUb1Jek3hTuQ38dTTDzQhR78PF4w3naMyG4UgemPpump": "GONESLER",
- "25E8X8fPnT9AdU1nA78snybnzVxkDvv5rK663Ngrpump": "GAS",
- "DokPYQ33k3T9S7EEesvwvuuAtoQb4pY8NWszukKwXWjv": "GASH",
- "7pskt3A1Zsjhngazam7vHWjWHnfgiRump916Xj7ABAGS": "GAS",
- "gateMurAxe4YFoUR6J63gXGKtkbTfdkMdLjZrCmThFP": "GTSOL",
- "gtBTCGWvSRYYoZpU9UZj6i3eUGUpgksXzzsbHk2K9So": "GTBTC",
- "ibRLJrmgVuZh3tdDpjGgU5CQCCxpxuer7B7ckjGdLsv": "IBRL",
- "9mQEkFVqmRJLMPUJT25qriKXi2sH8RiuMBrzLeLupump": "GAY",
- "svy5ErijNYy9hEVzxknCdwWdZ3NeXJTdpb9Ndnso17f": "GBOY",
- "791hZNiCJy1qGSGzAvqUU8X6gejiBJ2mBV8JjYoVnzBR": "GCR",
- "GVmtuUyLDuXNh2gJtHgarEtpqSiwn5965fNv37VeEhk1": "GDOG",
- "EbW1bx4NdjH4aTTUNAP9PRBYTu6qJE12d9vUhvHbpump": "GEEKED",
- "NUGuzrXB5JwxBAhTP8QHa8aiNBN8suoWiN7wiRppRty": "NUGGET",
- "5zbUuCeYLHVApzANWNSXkKwcEoZsbMghoh8z8HbWTJbJ": "GMAC",
- "ARiZfq6dK19uNqxWyRudhbM2MswLyYhVUHdndGkffdGc": "GEMINI",
- "NrTdGMA3ujUvWXkwXyZKnhoByb32KTjRh5Vo47yondo": "GEMION",
- "9UEN2kKhHxnaK14ZYFvog2hezajxAke9xCiS2hnppump": "GEMO",
- "68YY6KjfnmPuQubYkFTsmXGaF2FuwcxumWLFxb6cpump": "GEMXBT",
- "CftYJVf5mXhuHYjS9YQSK9z6q355RukjPZ6ZCsrw9sRA": "GENCIT",
- "aTBfDuLRqYHBiG82bHA7DzwjSDTFre2dRtGH3S5ondo": "GEON",
- "Dzox5Ytp6ZU54h3uutcp4MXw3ZnBxR21H5Zx4r4qpump": "GEN",
- "sxv1symoD4WXjpeXCs5USFEyt8hBhmCuuptLjA8uRNy": "GEM",
- "GFRxeCdpomjJaYQEuwPDAPghyBD3H9zqnWY2HJPjpump": "WEALTH",
- "7uerT1tMCury3t6HHhAMbBmq7t75dP9H4T9ug8AKpump": "GEN",
- "7EjWHZwtstT21dUniWpvVPRrw64cmX3UYFE5crJ8pump": "GENESIS",
- "SHDWyBxihqiCj6YekG2GUr7wqKLeLAMK1gHZck9pL6y": "SHDW",
- "3Jjt8QhbqNoYfSQYHWf8ZsTJwE2CyvmUrzgzJD5Jpump": "GENIE",
- "24kAN3xiQZba11BrgEsM9qfcqkD9xM7fBxnizkENpump": "GENIUS",
- "GENEtH5amGSi8kHAtQoezp1XEXwZJ8vcuePYnXdKrMYz": "GENE",
- "3an8rhdepsLCya22af7qDBKPbdomw8K4iCHXaA2Gpump": "QUANT",
- "7JA5eZdCzztSfQbJvS8aVVxMFfd81Rs9VvwnocV1mKHu": "GEOD",
- "6nR8wBnfsmXfcdDr1hovJKjvFQxNSidN6XFyfAFZpump": "CLASH",
- "v5g2uxKKpSAUXkCw8d51A2r9jvBJLDJD7jFPkTSpump": "GERALD",
- "52DfsNknorxogkjqecCTT3Vk2pUwZ3eMnsYKVm4z3yWy": "GER",
- "HqZrimiQXfHFd6WmBUrucLrnFHpApchao6LtUL3vpump": "GERM",
- "DLvWoNT1d5iSX2T1aUUBzRdGbSef2xW3MwJBKtewVW6h": "GERTA",
- "DpFkEmSqYBd2vq1yPHa2awRGwYT55ksAczpF9YepBAGS": "BAGGED",
- "6V4QLouv2HTbae34hBjLgW5Qc3kdquqFLBsDS3scR1CH": "GRODT",
- "5oUzkFsCFMJJ23Z6Ghev5m7FjE6TtrqZJXUS7V5Smoon": "RICH",
- "8116V1BW9zaXUM6pVhWVaAduKrLcEBi3RGXedKTrBAGS": "GSD",
- "4nm1ksSbynirCJoZcisGTzQ7c3XBEdxQUpN9EPpemoon": "GTG",
- "CgZSv89BL58ybWfWobANKEU8nV9jYfFw23G2DZEondo": "GEVON",
- "5cerJBJD7q3xfi24JVxSoP8AqeavuUatJtrfrXVokZR3": "GGEZ1",
- "HbxiDXQxBKMNJqDsTavQE7LVwrTR36wjV2EaYEqUw6qH": "GHOST",
- "4TBi66vi32S7J8X1A6eWfaLHYmUXu7CStcEmsJQdpump": "GHIBLI",
- "9WyRszmxLf1e9nWAVf4p7j7S2ektkLu74PTLVVKLpump": "KAPIBALA",
- "Exw8YLyWbZfF9KTVhemcJrkSr7abUQCa7mLowgj3x9EC": "GKN",
- "3QYgRBYG8qQxKq8wkwrv7xZZATn2wozeVW7C7Aw6fREV": "GHOSTFI",
- "BBKPiLM9KjdJW7oQSKt99RVWcZdhF6sEHRKnwqeBGHST": "GHOST",
- "Cc3voFEFTrGmnhnP8x77ncZ6pivG8Kk9ir1t8AhBBaby": "GIF",
- "511nS6sEQ1u6wFRSBRuG5ip1DeemqUofzy2V18UDpump": "GWIRE",
- "GpEKud3JpJDc5D3Gek8UVCb6vAiahGmDUZMQFnf5btai": "G",
- "6FtbGaqgZzti1TxJksBV4PSya5of9VqA9vJNDxPwbonk": "GIB",
- "GHpAbHZ8MCAXWLdKzxM1ZGhP2U4u1ni5vUcoRSghpump": "GIGA🧠",
- "BcDFqj8BoqLKytNqEC8QxFYVbD1mS9FThoVT4vQbonk": "GCAT",
- "63LfDmNb3MQ8mw9MtZ2To9bEA2M71kZUUGq5tiJxcqj9": "GIGA",
- "9iCCVaGu9oPcVczW7F1hNQmbz8q8LJwivQM8aXSPpump": "GIGADAD",
- "GigiN7pb33qVqEebrAdghhYsHm477wdC347MPgyCpJ7F": "GIGI",
- "7wdxpzhn8Bz21nTb9b7qM7HzmU6LEoV1QeFKqWeKpump": "$GIGAI",
- "9HBoGfJ8TotjjJQ6KwqMM8iiC7xsKYjVywfb53sxpump": "GIGAMAS",
- "BgWmyRbcyEKTChUoH2xbcsEdVnJezs3ckveMxADbpump": "POTUS",
- "6q387cQFB2bobtdJGAMVVW5NoVL94KKmHXmEPgwUpump": "STACY",
- "Bsow2wFkVzy1itJnhLke6VRTqoEkYQZp7kbwPtS87FyN": "GIGGLES",
- "3WPep4ufaToK1aS5s8BL9inzeUrt4DYaQCiic6ZkkC1U": "GIKO",
- "EAQWA7VgpMnj3A5bH83MMn1p6WqpEUZoe3d54UsU5uXc": "GILLIONS",
- "4SXJJw2GKVTeoxqjrcrFNb3S59632wXjVRSJN8kFpump": "GGK",
- "GinNabffZL4fUj9Vactxha74GDAW8kDPGaHqMtMzps2f": "GINNAN",
- "DmyYENoMKDFtbfUeBcMhAedi1amPSEvJC9Sy8R8VxQ8j": "GIRLE",
- "B2Lfe3mjgszhieS9QbZHHDNcSdMcjigqp8GtJrc2pump": "GSC",
- "9n1A8UtMXnnNdV1JJTc1sxhH47S4dVbcBgHqg96vdqQx": "PEARL",
- "Fh7mLxtPAysdvHcMcJ37A3vc6WvBVh7JVDwxmwk6pump": "GBACK",
- "3Xi3EhKjnKAk2KTChzybUSWcLW6eAgTHyotHH1U6sJE1": "GIV",
- "2CsJHNyj74zK6Jaiq2UayPAXFEjmL5UKhpeLNaH45Fud": "GIZMO",
- "6uYAMiY8KwDsW9ome5AvadsnNUKF19Evz4QxQ43Dpump": "GLDS",
- "73rzMJ8uEqjAf5vE1YPGrXbg7Cb2Yv85EoxpJh2mpump": "GLAM",
- "HJxLv6PnZJmLko7b5wqgCMyUT5fgz9NdBwe8htdMpump": "GLAZE",
- "D12fZ1v9WK3VhpLGejb99GT6MzwPjGWLhjN8upQmpump": "GLEGLE",
- "Bx6XZrN7pjbDA5wkiKagbbyHSr1jai45m8peSSmJpump": "GREMLINAI",
- "2u1tszSeqZ3qBWF3uNGPFc8TzMk2tdiwknnRMWGWjGWH": "USDG",
- "E4n5gooEoFaDPb1oSDmN2VXjWKekrTn3EFE7KjNKpump": "M2",
- "X7j77hTmjZJbepkXXBcsEapM8qNgdfihkFj6CZ5ondo": "COPXON",
- "XsybfiKkD4UmjkAGT2uR8X2sq9AWFtvGJM2KTffoALZ": "COPXX",
- "EvzskrQ3vUUkiMGG1DzfSDyG6H2WCMy3v9G8fzzondo": "URAON",
- "DsLQ18ooPjiHYuiuQ5Jz8PNCpVaKe3FhAYpvMxWondo": "PAVEON",
- "FkBF9u1upwEMUPxnXjcydxxVSxgr8f3k1YXbz7G7bmtA": "GLORP",
- "7wBBPnj2TA5XhB3ADm8D1odSKh9fDqAWMPaUqaMPH17e": "GLOWSOL",
- "1VHpwkbT3TZ7VjqwrAxvPbQCg2HkBNMrPW2WsQspump": "GLP1",
- "6DEa18xxCgx2SgBTJbFdEY6PTNZMWvG2nDv47LHspump": "GLUB",
- "CiuH3kcRXJhdikbZsjfpvFaMaGVSCmFodWcwizjhhXcY": "WGLUE",
- "mMykZc4tun2kFNgxbd7WiApAoGEaX8bxFuHjxzjnkrV": "GLUTEU",
- "445ksMigJLms4mw29DQkXs8aWBG4S8Z2kTBCtGhd5nGd": "GLMPS",
- "GMai1NvHreNe135cvxya1gHaUJZiT1NAvbJkF4hPHQJ9": "GM",
- "8wXtPeU6557ETkp9WHFY1n1EcU6NxDvbAggHGsMYiHsB": "GME",
- "A5LCTQ1vJECCQWSXJYs3rfCoexctbUgTCAEKDuNye8bZ": "GMEOW",
- "9WoZqQfTmhU9VLzixaBhWnKA1QTySkSPpK3aortAHrP5": "GMICHI",
- "Gcc7QfMgy9rKVdp8wdKqgUvzPWubHzDDfugiTgEvirt": "STATE",
- "3acxNNmfdKKZj9i35P4VDBFm74Ufdt8ojKWceVGynwC5": "GM",
- "3KzAE8dPyJRgZ36Eh81v7WPwi6dm7bDhdMb8EAus2RAf": "GOMINING",
- "BaDjVCpABEVCdt4LT7ivuzA4izBwJCqnDjrLa8XBtT38": "GNME",
- "2J5Dpp57RsjLBkJrEvyrAQpg8qWvgadUeJR4Ln7bpump": "GNOME",
- "2D7jZLpUUAMboqzHMeyaxZfLWpf4JZUoR4i82Zva7sxU": "GNOME",
- "GNHW5JetZmW85vAU35KyoDcYoSd3sNWtx5RPMTDJpump": "GOAT",
- "GoATEDLwYeDQXyzcFxAgeiQd5Amu4mewU4KmbjvUWGvH": "GOATED",
- "Goatm5cqggssKRUwbMnPhHXKtN5SDGEP57qjwTSHD1Xf": "AIAI",
- "FKZWwdAxhAhf6kiKM5Jwk1vDjJqxxM3jdanexwS66LxM": "GOATSE",
- "CzLSujWBLFsSjncfkh59rUFqvafWcY5tzedWJSuypump": "GOAT",
- "DtWz93pDUZe5cYqBFmZjXq1wzZqZPygCeox5d3ajpump": "POPGOAT",
- "CwdjgD54hgTQChspxHhirWLQWqy3EsxtndrcpLBqpump": "GOBI",
- "3xypwTgs9nWgjc6nUBiHmMb36t2PwL3SwCZkEQvW8FTX": "GOB",
- "4NtBkKssmv39VTrMJz212ZrXUWicJ1aepERpHnNCpump": "GOCHU",
- "GodL6KZ9uuUoQwELggtVzQkKmU1LfqmDokPibPeDKkhF": "GODL",
- "GEVqugYZESSzZaYU6SKdpW6znCCEtH7aoSTzPHbqpump": "GODS",
- "6CNkQVWLSRxZEa1eZ2PFjQyLCVZ48U9oGcggdS9cTJoK": "GFY",
- "E1jCTXdkMRoawoWoqfbhiNkkLbxcSHPssMo36U84pump": "GFM",
- "Byb1W95xDYBiF6gMJoTRgpD7Z14GFna2QLHoZfEWNbfQ": "GOGO",
- "2Wu1g2ft7qZHfTpfzP3wLdfPeV1is4EwQ3CXBfRYAciD": "GOHOME",
- "9sjyR4GrozeV8a9xM3ykKPGPXJYASy9AuufzefCyaCnP": "GOL",
- "DK9nBUMfdu4XprPRWeh8f6KnQiGWD8Z4xz3yzs9gpump": "GOLD",
- "GoLDppdjB1vDTPSGxyMJFqdnj134yH6Prg9eqsGDiw6A": "GOLD",
- "79eXoT1aR7qhBMGKXzVNdV4ZcLqHsupqj2WTFvDumpSZ": "GOLD",
- "H1PevUqmTe8WU9An9JCxt2LMR4WvesNjMF5R7GZ7qpRE": "$GOLD",
- "Eh36AX4m5CwyCHHcAy95oWRop2EMYVJbLQq7q77hsX9N": "XAU",
- "9QFfgxdSqH5zT7j6rZb1y6SZhw2aFtcQu2r6BuYpump": "GOLDCOIN",
- "H2eWtG57do5krGxpZdzs6sDddHLz5Nny7797YhR4pump": "GDIG",
- "GjqpHLGPUtmBbfGvEAEvVG6GJkfyAozNZb1uJLoppump": "GOLDEN",
- "HREdVBmGvUvdgvoGeHwYpEQNJRb1oqmScwV5z1dHpump": "GAPE",
- "7dGbPgUxKpB5qWiLRKcTQSC3om1fPzUpgGAFfwej9hXx": "GCR",
- "n88wHcVtfavStAM5VQyUFQ6ykdnfqZucysVgmqpdgiM": "GKAPPA",
- "ER8HgvjkEa4c3ToUTGZXAcNH3Vs3XKu3KGcncM8jeJUQ": "GOLDINU",
- "BchJRy2snmhJZf3rQ9LJ3ePs2BGfYgfvQNo31d2ondo": "GSON",
- "XsgaUyp4jd1fNBCxgtTKkW64xnnhQcvgaxzsbAq5ZD1": "GSX",
- "AEv6xLECJ2KKmwFGX85mHb9S2c2BQE7dqE5midyrXHBb": "GLDR",
- "Xsv9hRk1z5ystj9MhnA7Lq4vjSsLwzL2nxrwmwtD3re": "GLDX",
- "Dq3Fwkvo9zC87RmZ6ZKEYiztnAyr6qX9wmYjHJgiBAGS": "GOLEM",
- "7L11EwmNRz4A4oj6jErkFR2CjSbAPadgwAGz7vGobonk": "GOLIATH",
- "Bx74hpFiaiBbSonrjyqxjGfAA7gRxM2CeKiy31uN6biR": "GOMU",
- "DG3LB7Kr8Londuz1j2us4YUXyNqiiLioKdYjSB37HbN2": "GONDOLA",
- "G9b9Lt78x5JXhFLeDY4ZAfMkWWugnbsfKBR2qipJWXaT": "GOOBY",
- "e8NFqLCMJBfDTUUARoniADgQtSEFmZNBksPxYzepump": "GOOCH COIN",
- "4DNcAxMMhWffAy5WTiJyxoCnMMkeXzrcw2RXJrakr7ym": "GOODBOY",
- "goodX4LG92UAcRdFRUykfP2fAfzQAVttrToEPxtxSkp": "GOOD",
- "GGUSDyBUPFg5RrgWwqEqhXoha85iYGs6cL57SyK4G2Y7": "GGUSD",
- "4aL5GLRuzsnJjJWNdXK7TPTVpGhP6PyV4ZhyQiyxpump": "GM",
- "9RaBDMwL2hcmah5yzXjBLiiYxHiBbd2jSEH3q6KCpump": "GM",
- "FT8X8hqoEwNT8UifNL3ppPbpccf7mnuNLpJsszv7AFHW": "GOODRUDI",
- "CVNb8Bg7wCrtNTFniaJvxjyFW2cKcoRjKt71Af67pump": "GOOFY",
- "8cyS5xMeWSCAKSe5QpQ5XMfvxRCcSj3mbHtbtyrqk7RA": "GOON",
- "ENfpbQUM5xAnNP8ecyEQGFJ6KwbuPjMwv7ZjR29cDuAb": "GOONC",
- "EXz2e3qNMkTnwVhmYusAP9VtSXFMQ1eAmLS5treobonk": "GOON",
- "9dUKXKC5K6rWErKXbvCDhvnRaHR3zoFZYBqRLdFQpump": "GOONCOIN",
- "FP9axFNBC1V68BLTDqtWAP6vVVqP9daNr57wmx4Tpump": "GOONER",
- "44sVpouhWHXzADVsVUo863tvgmaw6LNQo25fYRs1pump": "GF",
- "B3seNmLjE4sv7W6HCjfzcKFnAWTfHDv9MBa43zEKpump": "GOOSEPUMPS",
- "71Jvq4Epe2FCJ7JFSF7jLXdNk1Wy4Bhqd9iL6bEFELvg": "GOR",
- "8Q8KPBL21FVatn2C1EaxAQSorAkHW2W2jDUXapVPZmhm": "OSCAR",
- "UbESBaztbkxJRWxPcfDeK8Fft15igTbrv3sed1bsegM": "GCATS",
- "3XFXWiPcVee69nFCRs7G3eZn67TrXuuLmCYCo8d7bonk": "GROF",
- "76EDL5qNcte2ZH29quTaFzagXjWAEY83CATEjyA6pump": "GORK",
- "gorkrgj6k4K449Qa4eF1NaWC5cNLQtMsVEikhpGn7fC": "GORK",
- "9Z1Npnb23ynnZa6ZzzwkGNYm9rmTuFmm6ePFVuLNdaos": "G16Z",
- "AAqZ6CECabwnYLm3FDqPrVQotXLPGQ3BJSfecYmXeJU5": "GOTM",
- "FoAnSCG6CcqTq2rsTi58yyYBNk1HgsbLzS6b1kTP2ACL": "GOTTI",
- "GRQfnwWyhd4qeJqUVCZo9ku61p3YN7MWCCk8vBXnpump": "RICH",
- "6AjB9gafah5aBBsogmxmLyeQkrRDejKzxETxJzRRKF1H": "GPUINU",
- "B8CTmq5ghNJg4ZFKq3rKLMEnZBotEwhrr1a9Bx4mpump": "GRAB",
- "m9GcsVgdjaL3KsdtSFHimnhtsUMpTHkjtwEG4Tzondo": "GRABON",
- "7SYuU1Z6EKfpYQQ9VeTXfLW5ofhigdn8Y7iQsqoepump": "FEROCITER",
- "5EKFigDd1fhbGxq8hVTzBMcGhJZ1rKxL5aZtPuYqpump": "GRAMPS",
- "8upjSpvjcdpuzhfR1zriwg5NXkwDruejqNE9WNbPRtyA": "GRAPE",
- "31k88G5Mq7ptbRDf3AM13HAq6wRQHXHikR8hik7wPygk": "GP",
- "Grass7B4RdKfBCjTKgSqnXkqjwiGvQyFbuSCUJr3XXjs": "GRASS",
- "GkeUTuaFB4oZADaqiCo3yauHNx9SxUNn8euHptEEbonk": "GRASSITO",
- "3hrGWXzgQzAikcG6rerG45tK7KLYw2dZ84owWJ14bonk": "GREEN",
- "49STvRfTDg1AbAnvYeB8to3Hj3E9UQb5TZp3wXstdaos": "GCI",
- "5drB44YYwNVE6RyxZyRRLbDyEAHgdhkJVgsgc7P6pump": "NORDO",
- "63Z3Q7JX3SBGDiiwqqnPTVvHcuUk6ixkzsYQbKzhpump": "SHARK",
- "AFbX8oGjGpmVFywbVouvhQSRmiW2aR1mohfahi4Y2AdB": "GST-SOL",
- "zZRRHGndBuUsbn4VM47RuagdYt57hBbskQ2Ba6K5775": "GREG",
- "X69GKB2fLN8tSUxNTMneGAQw79qDw9KcPQp3RoAk9cf": "$GREMLY",
- "BtDFyQ1mjL4RHiXrx4ARuzXUt196u1hWoF2rgWUHpump": "GH",
- "A21r5h19iHhQt6b7vzkgHNgMaSAR9YSazGeJedJepump": "GRIDDY",
- "DWGxNqh3oQYfZostoCXXdMRaB67WCDYckUjYvsMopump": "GRID",
- "KENJSUYLASHUMfHyy5o4Hp2FdNqZg1AsUPhfH2kYvEP": "GRIFFAIN",
- "7h5AzpYTAnh4Gyux8Gqko5Fvx4AYQBZdkzHZ2CsBudvJ": "CITADAIL",
- "Gc1aT3ay7FXL3qdAW7cNSXYPDsGavy7qiACuxwxondo": "GRNDON",
- "E8iWdPoeVDHJn1EHifeCAFWvKZyTN9WXrmccFEx1Hxa": "GRIX",
- "BQ3F72yt9FVRgYrqCVCG3YohyBesDZ9bTuhGdmQ7GNEF": "GROK",
- "Dp8fc49A73C1ycnTzRet8oEWNRSpUymqcCbYsse5pump": "GROKAN",
- "WAxxkziGPy6ThGBLg4MNKJce4eGrSKxCEfJ72ZLpump": "GROKCHAIN",
- "67ezHLk8PUkjJCXjmmgPbx85VowA52ghfRXa9A8Tpump": "GROKIUS",
- "AGBegePeNtnBy1xLGBDcBDjxaVHaDhvebSNMduLapump": "SOLANUM",
- "Cc3A1tC5uoM6vhj6oGiY5hywHMsairxij1siKL6fu45S": "GROKROOMS",
- "7Y6Rix8X2botuMaJ2mno4UqSWdQZqU4RezY6qp7zpump": "BOLT",
- "BTyjf4y7sLXgtahZCH6X7gGRnGgYqRFyBSDjL6u6pump": "GROUP7",
- "12vYRvkvnZnY9e3J2mzZgfuE5u5e134tqHCeMcMrpump": "EARS",
- "AjgSvYmJLhvt3FteiyTqQf8XBj1SVs6T6AmSUfkHpump": "GROYPER",
- "DUhWgHD3KgHHmsYdQdJHDv359bySNzigYcqJ45Gcpump": "GRRR",
- "7LtgzCmSpGocBajm84WghiWbu1NcvQxdqLQtUXFSXgvU": "GRUG",
- "BV2CATw6dAcxxAoZ73P14DTXzbKTUZR41X7EXpKWpump": "GRUG",
- "GRUmPYbiTpq9ZPy5LAqBMMze7kErf5dEX2i9qYfwoSmR": "GRUMPY",
- "AZsHEMXd36Bj1EMNXhowJajpUXzrKcK57wW4ZGXVa7yR": "GUAC",
- "APmLv2VarkC5yEjjutYkeK3byr9L2KwCgrVMWHWsgaG7": "GUANO",
- "A2X6xEhZUCPiHstrGehbNT9TrdEh9hEDfyYfNeNuAdDy": "GUARDIAN",
- "GoDCaGctsLDnkV8T6jBAfTeMj8DesxT71CkZekV5ZXcf": "GODEX",
- "5QUgMieD3YQr9sEZjMAHKs1cKJiEhnvRNZatvzvcbonk": "GUDTEK",
- "H7bTHGb5Cvo5fGe5jBDNDPUv8KykQnzyZA3qZ8sH7yxw": "GUMMY",
- "3jUf2RTyXp867piSB2dt8uUcNiLDW58asjGtXkRAkBbe": "GUN",
- "42d245pXpJDhAkX5QKTcLxPB6QxET6KbbsDas71Tpump": "GUS",
- "3FsEyF1yXogn2zYZK3naeyCymSLgkEv1kq2AhLffpump": "GUT",
- "CY2k3sedfk8x3ejAYFcYp4krzoPvpxk6y8ejRywUbonk": "ANON",
- "EfgEGG9PxLhyk1wqtqgGnwgfVC7JYic3vC9BCWLvpump": "GYAT",
- "Crn4x1Y2HUKko7ox2EZMT6N2t2ZyH7eKtwkBGVnhEq1g": "GYEN",
- "9SUCZg1RMpyMMYzRP9Z3JSZFghXGoXerEzjKQvbSpump": "H0L0",
- "FNqJtYs7rsP1H9GXWTtc5VnDoL2GhXEUKhYN46EEpump": "H2W6GM6JZ",
- "864YJRb3JAVARC4FNuDtPKFxdEsYRbB39Nwxkzudxy46": "HABIBI",
- "2Bwbeh361ywi1PpypDHabDb8VphNKCQt9ht2CRzFsYAE": "HABITAT",
- "x95HN3DWvbfCBtTjGm587z8suK3ec6cwQwgZNLbWKyp": "HACHI",
- "4amstKcbziHCqwev9esMtRGDTdjHSviiNXT7WtajgjUq": "HACHI",
- "6bzBfcyqmf8SqvtGN4SoLsT3knNhNycseuyZzKzjQnSa": "HACHI",
- "BWXrrYFhT7bMHmNBFoQFWdsSgA3yXoAnMhDK6Fn1eSEn": "HADES",
- "7sGdNQSvUGpahh6qyXB3g5gsdK9FAzZM299KyCXspump": "HTTPS",
- "AYyYgh3i43s1QSpvG4vwhJ6s3gewfN7uteFwYrswgMGw": "HAGGORD",
- "rizo34MUwbCBqpSTSfnEktdWB4CTByqqYh8zBxL3WAR": "RIZO",
- "haioZJAWTMaR4SFhZRwFBBejnGDPiwLTqrDiKpwH31h": "HAIO",
- "6uQQGTmjEDKP8Ag1ST3UoXkLjjzuU4Ax7mYcnu9Tpump": "CREATURE",
- "EjamcKN1PixSzm3GiFgUaqCFXBMy3F51JKmbUqNF99S": "哈基米",
- "J9SXKctbZVws65vjBHL91mqStzq5an1xZxdi6a4h853o": "HODL",
- "CvTMSEB9RzHPhB1CgE7PAkszomozDv3JJNz28sDbpump": "HAL",
- "4sp2EUDrQf46rZun6sYAWzjrXwUpx2T3njuoKmV766RJ": "$HAMI",
- "6xwmWkBheMwGLyuQjPN4WeHoK3QTGmWQtuknbFCSpump": "HAMMER",
- "GLXkHLX4jiVRAYBVwx2UAvKRBu2YDCQudNiR3k9q9THH": "WIF",
- "FY9HAYXgQu36xQDsaTLzwVHiR3HTqVrAGAq5ArLmpump": "HAMZ",
- "GTFWEVQy5BwQsZJWS4Y6KaZ3or6Yhysh2EEUp8bgpump": "HANBAO",
- "LkW6Lk37bdvX4j3pmwRKDEu8LgZuBuRY1V8cgRyESrR": "HAND",
- "3AvXA85wtW4UdAk1mnJsncGKvfEngsTypC9nybZJbonk": "HANDGUY",
- "231Qq1ZzBRXeSmwa1HJCFrm7v5cNUhyYuz8va42vtdQY": "HANK",
- "6VNKqgz9hk7zRShTFdg5AnkfKwZUcojzwAkzxSH3bnUm": "HAPI",
- "aBvs3Zv9JYmvUCKqRJvGctDQSCt6R7NAMELid3FeqsQ": "HAPPI",
- "HAPPYwgFcjEJDzRtfWE6tiHE9zGdzpNky2FvjPHsvvGZ": "HAPPY",
- "4TNLqKKQrMDqveiyKQjwX5QUuDrgJdzQC53tX68rpump": "HAPPYDOG",
- "Fch1oixTPri8zxBnmdCEADoJW2toyFHxqDZacQkwdvSP": "HARAMBE",
- "CNL2opdqaQDY7yudm5V4MAaTwuuY32LTKqNP93jZM8X6": "HARAMBE",
- "463vBSJt4CurDqEnojG3ykMy3Lf9GQF2hFV27JeZpump": "HARLOD",
- "EjmDTt8G3T725eFSV7oWmGD8J848guo3LZ1EB3RfwGSw": "HAROLD",
- "3vgopg7xm3EWkXfxmWPUpcf7g939hecfqg18sLuXDzVt": "HAROLD",
- "7oZCgJNtCFvBNBNx7S1Nza9TwfzSNaovXMkfnk4gpump": "HARRY",
- "vv96jGJhGEqq5GU6q6zqpPrGMayZpGxQ35rrGEkpump": "MILLENNIAL",
- "CTgiaZUK12kCcB8sosn4Nt2NZtzLgtPqDwyQyr2syATC": "BITCOIN",
- "4acvcTQhR2Z3TWauJZHUFaubyyEBtoybrp5QLobuCkcH": "SOLANA",
- "zSyuawLybV374Fiufx4bQnLnwfFRxX2cFsQ6kwKpump": "HASBULL",
- "7ZqzGzTNg5tjK1CHTBdGFHyKjBtXdfvAobuGgdt4pump": "BARSIK",
- "sh3nQze56RGQFBxr3FZidbbVNVh2oUctgt2sGP4pump": "HNTR",
- "7LWanZteUKtvFjv4MHYgKXXdAuCQYFPJysL9pxxdRQGn": "USYC",
- "3b8X44fLF9ooXaUm3hhSgjpmVs6rZZ3pPoGnGahc3Uu7": "PRIME",
- "8fr7WGTVFszfyNWRMXj6fRjZZAnDwmXwEpCrtzmUkdih": "WYLDS",
- "HrqgFZipMFHXvN5nKvTUaCwuA3Tp2UGqcQzArRGAyQ22": "HAT",
- "BKipkearSqAUdNKa1WDstvcMjoPsSKBuNyvKDQDDu9WE": "HAWK",
- "4GFe6MBDorSy5bLbiUMrgETr6pZcjyfxMDm5ehSgpump": "HAWKTUAH",
- "GJQpf6Zjvokd3YK5EprXqZUah9jxkn8aG4pTeWL7Gkju": "OKI",
- "5t3hBZDnxksnWiUu1jw42rq4b7h3VCSXUSTEojHDpump": "VIVEK",
- "97sraAGszzEFY6AW8iuWfTceBQWa1RzuFRXryJqSbonk": "HEARING",
- "Gv8mfuosgCKCj9tPs9VWS1GzETemr69Lnr2jwjbWpump": "HSM",
- "LiGHtkg3uTa9836RaNkKLLriqTNRcMdRAhqjGWNv777": "LIGHT",
- "htoHLBJV1err8xP5oxyQdV2PLQhtVjxLXpKB7FsgJQD": "HTO",
- "8G5ayEsJF4Q7FEWEGeF4jtnUWZBEKCqhySTFQf9Ppump": "HEAVYPULP",
- "A5GeMaHdM281F5GkwA8GnToKZUPPubWuMB99UD4pBAGS": "HEDGE",
- "FFYLoYzPnD1CAVa8UeP9BeXhPPAykRkYiFLqVpxKbonk": "HEDGE",
- "ER4NDfcEckUX5PzqtoLDwtAbCYhhtccCABXCLH4rpump": "HEDGE",
- "9dLuVbJMd4ZpTpFgmaFHAGSsFwVjtcnzFWaLAA1expHg": "HEEHEE",
- "ULwSJmmpxmnRfpu6BjnK6rprKXqD5jXUmPpS1FxHXFy": "HEGE",
- "BreuhVohXX5fv6q41uyb3sojtAuGoGaiAhKBMtcrpump": "HEHE",
- "8Q9VDdrd1rNczTEL3ivPhwsYrYXVuSAdHuY7gFJGpump": "HEHEH",
- "DdyoGjgQVT8UV8o7DoyVrBt5AfjrdZr32cfBMvbbPNHM": "HEIDRUN",
- "E5vSaRkSUDe3ob3KTAzXa6gmCndknzutn4hNtf2Qmoon": "HELIO",
- "hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux": "HNT",
- "iotEVVZLEywoTn1QdwNPddxPWszn3zFhEot3MfL9fns": "IOT",
- "mb1eu7TzEc71KxDpsmsKoucSSuuoGLv1drys1oP2jh6": "MOBILE",
- "XsicTFC7G68d74FaYDctWggkKDgkMx8LpNoFNr81TrF": "HSDTX",
- "he1iusmfkpAdwvxLNGV8Y1iSbj4rUy6yMhEA3fotn9A": "HSOL",
- "9YdvrMsW3qsfa2sRUEgsdMtC4wswGHNbDNWFg4wrpump": "CRAIG",
- "4h49hPGphLNJNDRyiBwzvKoasR3rw1WJCEv19PhUbSS4": "HELLO",
- "YrJEAT1TyQfDvaY1SmBWWHLAethSp8bbQjoRJccpump": "HELLYEAH",
- "BriHnFv9qa8Hrzjgh4vmvp1WxzECPUTyZ4VHbRe4BAGS": "HELPFUL",
- "34AeqX5MQGyrey2VnZdkeZCfM4qinp4F3X7pGxtipump": "CANCER",
- "819T1na5X5PwCT2WP6ahrjoAhZuiQXKZTs4zuquQpump": "HERMETO",
- "FBhF2pcytFSTcTzQWCxisLCyrYDqmRZDu4mrGp1Spump": "HERMY",
- "64GhPSS8P8wNaGWH2uysASxp9XYsqS3An3eJ3w5YNJK9": "HERO",
- "5bx4ttYasp3nRe51vytPgkdsTNveby2zTWTsd89epump": "HPDA",
- "WXRPpJt44kNmiQK495uuxPkDPHa4js4K1cyDEWXCNKY": "WXRP",
- "9McvH6w97oewLmPxqQEoHUAv3u5iYMyQ9AeZZhguYf1T": "ANON",
- "HEYKwDJRoSsiLNQ9F9bZFKo7yxum1WbTFCgiHTX5h6tb": "$HEY",
- "FHKiJEg2zmhv9DEeaXMSZa7R4P8BPFX5VTRrzrtJpump": "HIBER",
- "BDW8YHasD3NSDjSHU9Xy6KXtshGayMGQfj5bJpLcpump": "HTERM",
- "teBPKvR8PH4n58BCvHKVotLKaV9RAoB8taWTmkMpump": "ATH",
- "F7BW1wJsDHrHUkNPcoYkgYcKD1o2DsUooML9kjajpump": "HIGHKEY",
- "Hnq9gGF2HFShcNg7U6pU1xxNs7zwvD5E1LoLdjMApump": "HIKI",
- "bdh3njeo19d2TBLAKTGvCWdSoArfVw8uZBAJHY4ondo": "HIMSON",
- "6GYrrhBy3s6LPgLdrvfd8i6HvhsgmQDEFP7zmNvZyBLV": "HINT",
- "5tZHKgJpnF1hsjSnQ5N9NA2c3S4QzaFw3uq2ARGspump": "GORT",
- "FJpuy1NFuAb4uqkBVYWzsc7gBC9iDj3QT5yaDSZdpump": "DONCHO",
- "89q6aHpZ1fXhuwpnrBgqmCvuAX4GaCrRPQNp5xVHpump": "CONCHO",
- "HiTD4kFXbMHcEuqsr8XYEUR9FMeVAJWKqYWCNehiYQbL": "HIT",
- "6fnYdoJhYkifvt52pfNtUDr31ZYXmof7JiL9SFrMpump": "HMU",
- "FeKeCwKU8gaULTGeLuJN5jQg1f6SiG1aeUSZcG6Rpump": "HIVE",
- "9DHe3pycTuymFk4H4bbPoAJ4hQrr2kaLDF6J6aAKpump": "BUZZ",
- "HGTxJQKzuMjzKkHVpRLcFHwE6ngVCJbcP35FDQtmRzhx": "HGT",
- "Gdck9KXSSiMMhNyjUjo4sVT1GDzeZnZP2yse9jhax3GR": "HVLO",
- "4vMsoUT2BWatFweudnQM1xedRLfJgJ7hswhcpz4xgBTy": "HONEY",
- "7xywcaBrF6vQVyHJ1eM9LdT5Z45EAbLbDgGuh8i5pump": "HMMM",
- "58UC31xFjDJhv1NnBF73mtxcsxN92SWjhYRzbfmvDREJ": "HODL",
- "EpXBP1mNofE6j55wAty4poUh4cJPQS7NWDdCD9HSpump": "HODL",
- "8N9cKkE93grPT2ALLTQ992wwhTNXoqycsCg9Jj5wHiyW": "BRUVS",
- "84NdpWVhTGVuPFximNBXHQyQQPKumTjBYfFYGqt4bonk": "HODL",
- "3WhE7MufQUsQWv56yaRtjd8N23sRBV1VT7cmce7mpump": "HODL",
- "14TGkkYQQeNj5pAKKZf8VGJQJfDagdX1t4QX4Rc3bonk": "HODL",
- "12Z5CsL5kCPRmnLQcwpY2QrEub3MahHCtRHxoQEdpump": "HODLESS",
- "13qAYdft265v36MFbFKSANKo2whvGb6s3ZhpJqQWsump": "HOG",
- "74gUPK636nrieDT9kLSgF1peWg5BB7itNkjF2BkMDwZj": "HOGE",
- "8CuPzHKuZQUyYbear8fi3u6iuTY652WVZT2cHZ2yeNbE": "EARN",
- "BS7HxRitaY5ipGfbek1nmatWLbaS9yoWRSEQzCb3pump": "DOGGY",
- "3DH8WZ6C2HdDR4J9ekYnTfai8Tx8mxn92mW8zcYmP4px": "HM",
- "HxyAjioHtx3xL3ytxAMJg3AgWWXghXx2zgZFk59pump": "HOLI",
- "48TqCgU8zC2H5tWshNriY2bWHDULSTSvdgL4iP1Fpump": "HOLO",
- "8HWLLoctYa7aFttfpHP9zbcEgV9uB9MUoVvSLjhBpump": "HOLO",
- "69RX85eQoEsnZvXGmLNjYcWgVkp9r2JjahVm99KbJETU": "HOLO",
- "B8hCuoikV9gLeuwmTyhNdLbPnb5k3P77Q7WTtEM7pump": "HOLO",
- "BSXFKLVsyrYckSF4SGXu9DRfMb3Fos7tRF9zMXgRCUsP": "HOLY",
- "8uHzYxskWmU8HcXvpTJCjNtnWpLhP6vMEB6Cu98ypump": "SHITCOIN",
- "J3umBWqhSjd13sag1E1aUojViWvPYA5dFNyqpKuX3WXj": "HOME",
- "2hXQn7nJbh2XFTxvtyKb5mKfnScuoiC1Sm8rnWydpump": "BREW",
- "MtEXKVN3Pcggy8MPA3eJr15H6SK3RXheScqj9qtondo": "HDON",
- "XszjVtyhowGjSC5odCqBpW1CtXXwXjYokymrk7fGKD3": "HDX",
- "DxiAg5mqccrmYJuG8JA2RBhYrPvokoU7wPqc7ZQKpump": "HOMELESS",
- "7Uuzh9JwqF8z3u6MWpQuQJbpD1u46xPDY6PGjwfwTh4o": "HOMO",
- "hnstrzJNEeY2QoyD5D6T48kw2xYmYHwVgT61Hm5BahJ": "HNST",
- "3dgCCb15HMQSA4Pn3Tfii5vRk7aRqTH95LJjxzsG2Mug": "HXD",
- "XsRbLZthfABAPAfumWNEJhPyiKDW6TvDVeAeW7oKqA2": "HONX",
- "3ag1Mj9AKz9FAkCQ6gAEhpLSX8B2pUbPdkb9iBsDLZNB": "HONK",
- "3EZKbpU2JDQi1XUcNujqgKPG3u4yJ9CvJcaKNRbab85P": "HOOD",
- "FFButxhra5PbGajLN3e1LhVWtTp2BtUoWoJJGSVBpump": "HOOD",
- "CnbALMqQdGKtcYrBk6f9DqMh8oCcsp6BvtXta8DVpump": "HOODED",
- "GNYLexaKyy7GHX8wiKVCmohNcuh6fvtrFkPsbVypump": "HOODRAT",
- "58ExX8TFqiDqUpr1ZGiAhhiUsKfT14gwTFykLoVCpump": "HOODRAT",
- "HootvhN1jGXQk8APL2fD1StHqu9eWZJbMmfdutf9hnLV": "HOOT",
- "ECZxKmKGEkyKhYUau7WkUE1L9Jp2yLebwX4SnKc1pump": "HOP",
- "2JVZ7LF7dPj8EfmKcGe6CPjXZRLRZqe3wE66jR4Bpump": "HOPE",
- "3g3YFfUZLspiKpVmv9mDkaDcKh168CLArcqShR64pump": "HOPECOIN",
- "7kJejVVe6wRj1RiLTjZM54dNxTY1DPV6iE89VzN7pump": "HOPE",
- "8AS9yeGsAwvTs9gCDKMmB2MgX8NiSvv4uppH61yqpump": "$HORNY",
- "7S2bVZJYAYQwN6iwwf2fMMWu15ajLveh2QDYhtJ3pump": "HORNY",
- "GJU3bXxNkNtYxgjkoFhAdq7VrXJAB2GW4Cpt6kLcbonk": "69420",
- "yFtG6tU4mZqiUnrBC4gF9eXTdWyzj7ZSKb92wv3bonk": "JAIL",
- "E5UdugdLvgsccqe3pdq1ivNBTZhaxwthjvnE85Kzpump": "HORSE",
- "EqquikmAsy62SHadHzHnVXWusLRnWtP2vgseAthdpump": "HORSE",
- "Dx2bQe2UPv4k3BmcW8G2KhaL5oKsxduM5XxLSV3Sbonk": "HOSICO",
- "7bdPWWy7qbVZgjzR5fr5dQK3nohZ96HB5Ey8Jyaypump": "HOTDOGE",
- "H4SFaUnxrZRoFnhBeotZnuqw4mfVtJ2nCvGrPmQupump": "HOTMOM",
- "App2Sp9pgmQG7yD6uVaygULxALf4TpfALgnhHEkJimih": "LOCK",
- "DitHyRMQiSDhn5cnKMJV2CDDt6sVct96YrECiM49pump": "HOUSE",
- "BR4sacH5vBdoJsdV7aC3X4JZTAAtBPFsDEQsGLy3pump": "HOLD",
- "2Pah9ZUfpii27ABrWfQorzdW8FSJimxj6izFr4oGpump": "PLUMBER",
- "77RBCP95AFT9XRsx4xuGUHjBQsjcatGYCZ2VXx8Epump": "HUAHUA",
- "HBB111SCo9jkCejsZfz8Ec8nH7T6THF8KEKSnvwT6XK6": "HBB",
- "B8zW7B8T7ntCiiRYw18jrFu9MBqMZVk9pP7nYyT5iBLV": "HUCH",
- "96zMCM9nALK2cDv5p2CiDkGrgbJX9McCnQkxyBaoBAGS": "HUGGI",
- "6Ra49aqZTbEurJB1UQgAj1TjvbqajGP5um7gsTym8tWm": "HUHCAT",
- "BTWvZsjwgnGT7qSM3AAXxjZohCLsMHpdAhaiQMJbBvcF": "HULVIN",
- "HUMA1821qVDKta3u2ovmfDQeW2fSQouSKE8fkF44wvGw": "HUMA",
- "HUMANx3MBnTtMqZ9PyxnrtjpiGV1S8sncFziWbtUejk9": "HUMAN",
- "WETZjtprkDMCcUxPi9PfWnowMRZkiGGHDb9rABuRZ2U": "WET",
- "2XPqoKfJitk8YcMDGBKy7CMzRRyF2X9PniZeCykDUZev": "HUND",
- "HUNT4B1dJWqTm7aZCqjUW6L3KAcEoZwqedf9eknLKWrx": "HUNT",
- "HLwEJQVzs7SvjXuXpBTRHaLp5S6uWoWTUhLjJxBfy1c7": "LAPTOP",
- "22513u2QwiY6xaJn7nVFWGKy3aBdw6WfZsRPW2RRtCKj": "HUNTBODEN",
- "7dVH61ChzgmN9BwG4PkzwRP8PbYwPJ7ZPNF2vamKT2H8": "HBTC",
- "Ez81MaRRsT8WSc4w1kmxZh9vSnyY5QySSoHy4yLrpump": "HUSBANT",
- "HrTofxQLFCF86icrLQ81KRLsYM2iWVZEsKtunwVz7qNe": "$HUSKY",
- "XsG5QyZTQnVSpsXRpD92K5ZGoxXjsmfTyx7fW7r18DV": "HUTX",
- "HxhWkVpk5NS4Ltg5nij2G671CKXFRKPK8vy271Ub4uEK": "HXRO",
- "7XiycwkFwd1ig3yhncPxaq3qwJ6S2RpHc63C541hgmdC": "HYDAO",
- "4sWNB8zGWHkh6UnmwiEtzNxL4XrN7uK9tosbESbJFfVs": "XSOL",
- "hy1oXYgrBW6PVcJ4s6s2FKavRdwgWTXdfE69AxT7kPT": "HYLOSOL",
- "5YMkXAYccHSGnHn9nob9xEvv6Pvka9DZWH7nTbotTu9E": "HYUSD",
- "9iQFnxrDDMFrhLx2pYJCDeqN3wFuaBimQkUnZQHNpump": "COOL",
- "FEiphCSAqjAxvtyMxj8boFTABrZBFyngfyrZueqeMw3q": "HYPR∞",
- "57iaCFGwsfZYCurbrgmtrDnHggGP6B6oHSdWD4nNXo9T": "HYPT",
- "8vBMibwpn8wpfYKbQ9xqzodymg3LjmYec2tSNGRy23K8": "HYPER",
- "92s9qna3djkMncZzkacyNQ38UKnNXZFh4Jgqe3Cmpump": "HYPER",
- "Aq8Gocyvyyi8xk5EYxd6viUfVmVvs9T9R6mZFzZFpump": "$HYPER",
- "GwkEDwePTa6aFosh9xzAniGK1zvLrQ5yPJfLnqwmuyhG": "HYPERSKIDS",
- "7sYAhEucFNkme29jHqSeFYNenAgD8krH9KmJeUs8Un43": "HYLX",
- "BUDXpnu7opuGuJkQZdet9nAxSzb67MLJpkzJmaKkpump": "HYPU",
- "76RZeKinKT3jRx7aQZsV8TuDfB31f9HAQLwqp4Vcpump": "WO",
- "5w68xqRpVFqi7hCXuN7QLc5ReLv1PfpmT9TVm11Cpump": "HIM",
- "6ZUQAjQsAr3JQRRmbf5wXVgpCxD8vuq6jZGfRpTspump": "APED",
- "GUy9Tu8YtvvHoL3DcXLJxXvEN8PqEus6mWQUEchcbonk": "BOSS",
- "AhiEuwGafsTbu2oUkk1Tmbprg1wdUvWiUCLVvAwvBAGS": "BOSS",
- "C8bZkgSxXkyT1RgxByp2teJ24hgimPLoyEYoNa9ondo": "IBMON",
- "c5ug15fwZRfQhhVa6LHscFY33ebVDHcVCezYpj7ondo": "HYGON",
- "9VbsZNJvcyyZ9LKo42Yyw4h5p9KZgtZ1BoTWFoPGpump": "ICE",
- "G3q2zUkuxDCXMnhdBPujjPHPw9UTMDbXqzcc2UHM3jiy": "NICK",
- "G5bStqnKXv11fmPvMaagUbZi86BGnpf9zZtyPQtAdaos": "ICM",
- "BjcRmwm8e25RgjkyaFE56fc7bxRgGPw96JUkXRJFEroT": "IDLE",
- "CymqTrLSVZ97v87Z4W3dkF4ipZE1kYyeasmN2VckUL4J": "IDK",
- "idrxZcP8xiKkYk6XGD4uz1dxEYCWSgKDHqgjsBbwDur": "IDRX",
- "RqGHXg2eh3zPjyzNM7kUyrrSmhb9M9q4mCKFH1mpump": "IFSCI",
- "9CMf9Awr12juc8oSv4XrvZUwXsW4Jhaakm5FT53gpump": "BUYTHIS",
- "GJLiErro8cbWeDngDMWJug9dkwwckYZg4Lvb79F3pump": "ILY",
- "Be1FLsZBPPkDi5yjtS9g9rLwPtWua4hrGuC9QyPNpump": "IKA",
- "2ggn9cSrL3HyUudaNbB8PzjPkK5WEidK2MyapbnMBgA5": "IKIGAI",
- "EzEGH66Xheme3C4LKeV3V22axMnPYFAbhBcXwh6JybC5": "BALL",
- "AixSWr1ZqjerSLuqzUPNebu3y7xckzmQanZVcCfwX5gt": "IKON",
- "AtortPA9SVbkKmdzu5zg4jxgkR4howvPshorA9jYbonk": "IKUN",
- "BUZFom1YPnAZVYSccbpddBmFYmHcS4Xtc3JQG5cFpump": "SOOTCASE",
- "5zCETicUCJqJ5Z3wbfFPZqtSpHPYqnggs1wX7ZRpump": "SPARK",
- "BzggRTH4TQb8x3MeensGffz7NUa6wWCETcDA79Ptbonk": "RETARD",
- "8Zk5n3pZotY83sZCMJ774HTyAfwpjueLHD3MrzoKpump": "KAIA",
- "fnDj6iuSBBruq1GX5GQwxGa3MvAxiJbnPBSvHt4pump": "ILYSM",
- "aPig1huDbdDTR9HmJBSHK5jiHrG3o2ZThdG4xPDpump": "SOURCE",
- "EZGB14NYbqMrsw1QKSgfLXKpj8PrnQBXSjWHbwxpvbAy": "IMAGE",
- "EuU9Vh37eKDdUnZkUfMZLGCcBqwFYpr1E6X3ZwUxhvgm": "IMAGINE",
- "3Gjckk5jXnJffBruUS2EEYhpiDEN6z5TPXLkFVHkSkkg": "IMARO",
- "D1hmg8DP6qP514Lxpy85kMNXKJhg7Cm8KkHM2Q7rpump": "IMG",
- "7ctK21VZcJX1t1jiWLyWkSJk2Wm7xHYdsnWegzR6pump": "WOLF",
- "5a5iV4jTaxyPP4mMeeRfZStz6tYQ65p2CKTNygdRpump": "EARLY",
- "8z5VhoM97qYGZM4UH9VH2BWhKb6Xyf7kB3J55hM4JUNF": "IMO",
- "8Q194jXJLBdr7Dp5UYnHiv6ThELp33ZGKRyzpt5kjups": "IMPULSE",
- "EjzzyCSiLqjFDprpZj8e1zjXmcTG5HPGFRSEoWcJWHh9": "INBRED",
- "A8vTTQXH5qPHazNmEGrBnBvk2XYkj1i4e5AMVVN5aC44": "INC",
- "3vqvkb7XBTRwBndj9V6WNiSqKGugWyMXLrdBwnkCpump": "INCOG",
- "8469NEfLJC7oRBEQzpkBfYhQqw8chhMXkn7YwAotjupx": "IN",
- "Fe5c469ADZyvnZrB8gdDsYt5eLKodaVYhYJCdunVr1nA": "INC",
- "EQGG5muKhviWmWJwy4Fi9TeeNpJUX7RpHAwkQMnTAyAj": "ICC",
- "4EsrfTaMr3oSNFUscBs9HSph7f1dJ26RyDJNQYE1efRC": "INDIE",
- "HsBG6WGhbHYwyknCqDSZ27edyCWk1aPSVmmSYginhDhp": "INF++",
- "inxKXw9V2NDZE7hDijzpJaKKUb97NEPJDTCEEiYg4yY": "INX",
- "4J5HoZWoKcbo2JQxEEVCKRBfUQtEroY1QdRrKtZFpump": "IB",
- "znv3FZt2HFAvzYf5LxzVyryh3mBXWuTRRng25gEZAjh": "IMG",
- "T3aaDAiAfxZSqHFgyMxbSWRqeZFUDLHXvVAv1ZFpump": "IMG",
- "2jcx4R6R8X2A8bqp4i612izx1s71Srubpt8MeZrHyBYt": "IMGX2",
- "8JaibGAB3S6mUfgairHPnShFU29ujEmZTCNtzxRUpump": "TRUTHS",
- "6BpsMNh6eCDvTH9d5SR3CjPnvB6GpMtuQVrpPthRpump": "INFINITY",
- "5i6piokrXbNKxgzY17WAgoJhoEGYVULGQ2zgekyXpump": "BUTTPLUG",
- "5rXSxYoRxASFrALkhHX2PG4D96J8L24c7DB3qEzRpump": "INFOPUNKS",
- "D1wZHkfk8d6QsCjF3NTiYHLzsZJ2Qb4Q7WBFFbGuzBLV": "INFRA",
- "FdvezWNEEYDPEQKK9FwCqMnaoYvse1f3m28w6okkZDmz": "QUNT",
- "jNw3UW47CkLwmrF4gQzD6GrW7DhnJVBr6H3hZZBpump": "$TRUST",
- "4FDtAagigMuFcPp36rbd9bzcYTJgQah2qLMYcYtfpump": "INMU",
- "32UQH1VjtbvC4rNREPX2YuUEuNA5HUrELQS4auhupump": "ISENS",
- "FwZxfG6WHcAAJD5ShYZZQNQCNgtrw2oniQhoDXR5pump": "IRLCOIN",
- "4VC7UYqBo9Siw8ZnkPXfw9D3dzYCiVrPDzs9XRtyRJMH": "LABZ",
- "DuEy8wWrzCUun5ZbbG9hkVqXqqicpTQw8gB7nEAzpCHQ": "FLUID",
- "5V3vJKE4GKPNHdoU2SaWuDU6dkLdrY6MhpaE7tjwpump": "INTAI",
- "cJpUMp5R7rZ6fGeLHbHhrRuJzK9mkyKDjZqNpT3ondo": "INTCON",
- "XshPgPdXFRWB8tP1j82rebb2Q9rPgGX37RuqzohmArM": "INTCX",
- "XspwhyYPdWVM8XBHZnpS9hgyag9MKjLRyE3tVfmCbSr": "IBMX",
- "F7viRR7XKFeDxMG441DC1KDZu8cFjPvGFF6tnKYNVvFc": "IKB",
- "DwmsWi1yWRiqXnbD6JJfGMQawfcqqBnRSyk6QEoGpump": "IMF",
- "J9BcrQfX4p9D1bvLzRNCbMDv8f44a9LFdeqNE4Yk2WMD": "ISC",
- "3REkm7R5HxCjAnNSMR8ktuv8Ghub71RxZzfWfWheBAGS": "BETANET",
- "HRwo5GY87abyVy5tzW3g1RtgjrnxUEtWfDL7ftpjpump": "ICM",
- "6UxB5HCuuNm2HoHCp4TFVkPPE38L5zktESYKZ7Q5RC3f": "$INTERN",
- "AATECgWF4KjALbpgUXjabqFKHmdtjWdfdFNzCH3ipump": "ITMT",
- "8SPRa884QcKbXRnXo449noBFek2iJRvxfeQaZSb9pump": "FREEDOM",
- "7YKfh8hFbgHkwtAogfSWjsEGVNH5e1DoFF9Dj31U9CMe": "INTOS",
- "4fJVpHzgaQ5F5BmFWpLrVf7zdmkYJccgcz6XMQo1pump": "INTROVERT",
- "DiDWPZ7vQXfpaeQ8BX68XuDYeiQLv7diDxdeUpaondo": "LUNRON",
- "1MGRpPrkhEsCm2GCWD3rsvEU77xTTLAzfKXeFgFondo": "ISRGON",
- "CozoH5HBTyyeYSQxHcWpGzd4Sq5XBaKzBzvTtN3ondo": "INTUON",
- "DbaSVQ87gQumixFumMHCrMKFpq5dSYNtKiVNDw3Vpump": "INU",
- "invTrkA5SbM49yjk9EoknQ8DpBhaprTJ5csdkzTnAiV": "INVT",
- "td1aY5AvYQuwGD75qNq9aPipMexraN9mQXJwqifondo": "DBCON",
- "M6agiXbNgy8Xon9ngiW4ZDPbMFcNCTMkMMkshZyondo": "PDBCON",
- "HrYNm6jTQ71LoFphjVKBTdAE4uja7WsmLG8VxB8ondo": "QQQON",
- "Ffs23XgzXViCtB4Hhb9K1tHMi42RDbaaN8xVvP7YCggm": "KIETH",
- "9DowFjAVk2svDXzFxcfuTgSTHjniW5D6TVaEmxFvpump": "INVO",
- "BZLbGTNCSFfoth2GYDtwr7e4imWzpR5jqcUuGEwr646K": "IO",
- "DDZQijTbaSd3Kas1r1bgCnHPayk8vTP8SfZWp5Tondo": "IONQON",
- "9R1pCPM7GRr9F4gk978LqBQiPKfYStbZKc5iKV4imoon": "IOQ WALLET",
- "21rweMLGYeMNonHW7H3xa5py17X6ZFRcHirCp9inRBQA": "IQ50",
- "AsyfR3e5JcPqWot4H5MMhQUm7DZ4zwQrcp2zbB7vpump": "IQ",
- "3uXACfojUrya7VH51jVC1DCHq3uzK4A7g469Q954LABS": "IQ",
- "2ubH6Na9xWxXBWfNfQYqSvqLPUXRdEdAgCUcHXCKpump": "NOSTALGIC",
- "13QHuepdhtJ3urNsV9i1hdL8nQoca2G7ZaLzb5FYondo": "IRENON",
- "T1nEKn1kMyMKD5D4uvXe7VD5V86D9yu6NegK4xnBAGS": "URI",
- "EjR5wxxVmv3zKbhawpfJb2f1GeHWsQjGQX6JVDgLpump": "IRRAWADDY",
- "C19Q2Mvr1icQVxQJWpDTVDJjLTzAcXbUt3bPmBsYpump": "ISAACX",
- "HjrN6ChZK2QRL6hMXayjGPLFvxhgjwKEy135VRjondo": "SGOVON",
- "EEy57xbaLcUrN1HXj2vz8VWxeWFK1eZQZo4aWbrondo": "SHYON",
- "KaSLSWByKy6b9FrCYXPEJoHmLpuFZtTCJk1F1Z9ondo": "TLTON",
- "D4uWxzR5StYC6sTRhVts8Eboy3pmVtHeNC62dnQondo": "IEFON",
- "t71FyTYHVkPAb5g48adDHmkVxXYbUuP2eq6jDZLondo": "CLOAON",
- "6JLG8iUkAuqiBhL3j2ckDMDf5oWAa6awmyaWezKondo": "IBITON",
- "CeFbGYXDmkyfo1TXXzzZ512mtnCCewNohu6V15vondo": "FXION",
- "C9J9vZ8N79GzzxFoRkPWCkGtMKU8akg4FhUk4r9ondo": "IEFAON",
- "cdVNL7wK8mf1UCDqM6zdrziRv4hmvqWhXeTcck2ondo": "IEMGON",
- "CqW2pd6dCPG9xKZfAsTovzDsMmAGKJSDBNcwM96ondo": "IVVON",
- "cfPLN9WXD2BTkbZhRZMVXPmVSiRo44hJWRtnaC8ondo": "IJHON",
- "CPWkMURVvcnX8hGjqCTb8i5LkzV3VSvyk7SeJi8ondo": "ITOTON",
- "13qTjKx53y6LKGGStiKeieGbnVx3fx1bbwopKFb3ondo": "AGGON",
- "LitNUakTges74cjDJm6HHfFNKGPdySkp3MWSYzYondo": "ETHAON",
- "mhZ69E1vDnAsQJXAwarLYSX5tmgeMajXBJ2rXAcondo": "BINCON",
- "M77ZvkZ8zW5udRbuJCbuwSwavRa7bGAZYMTwru8ondo": "IAUON",
- "CBKcmEvVg5EgE3W5hVSPcBYWh6TFVjQwbmYod9Pondo": "EWZON",
- "BmXVAFyfpW7VuVYeWDtbFtLx7sek2mZt3BEsGgAondo": "ECHON",
- "AbvryMGnaba9oADMZk8Vp2Av6MtczsncGyfWaC4ondo": "EFAON",
- "916SDKz7y5ZcEZC9CtnQ5Djs1Y8Yv3UAPb6bak8ondo": "EEMON",
- "DBNwt3FoYCKQWdfzxKFNZ4mzuz4Jz1iRzFf7HFzondo": "INDAON",
- "C6c7VcxuUYcV5YTsky5HM4PUmfwHTwsDD5DNwwPondo": "EWJON",
- "C8pSaSgjkiTWixS3GM6Hxd6HKnKrgAbY9WDgfVeondo": "EWYON",
- "dSHPFuMMjZqt7xDYGWrexXTSkdEZAiZngqymQF2ondo": "IWFON",
- "dvj2kKFSyjpnyYSYppgFdAEVfgjMEoQGi9VaV23ondo": "IWMON",
- "DX7g7WNjDpVzNK9CG81v7wb6ZbiNzYfkdzH2Xs5ondo": "IWNON",
- "EN5pHc1LccUSojxb7kkyQi7v7iJN5RpDq6qz3DHondo": "SOXXON",
- "iy11ytbSGcUnrjE6Lfv78TFqxKyUESfku1FugS9ondo": "SLVON",
- "XsxAd6okt8y1RRK6gNg7iJaqiWNiq5Md5EDf3ZrF2dm": "SLVX",
- "k6BPp2Xmf2TYgrZiUyWfUoZBKeqaDbvPoAVgSx2ondo": "TIPON",
- "DDcAL93Urf7KrPntvKULnZoFs4Wdee1LkkJqLpjondo": "ITAON",
- "HX6zNkjJ7zy653VoDWzbaYpSg7BrgLfq4i4RA7D5nkkz": "ISLAND",
- "ApEKQzeVsGs5bk9hR1xKUEfoFGzvve2Aszkn4ft5moon": "ISO",
- "BQX1cjcRHXmrqNtoFWwmE5bZj7RPneTmqXB979b2pump": "ITALIANROT",
- "GuVoE2qAS3DHaAGSeuZfBkbLjFXfP46DFbogbrVJNHfN": "ITA",
- "CpdKgsZMtZ54FK5vbyLq5wNyH2uRmSxi8AtEAADipump": "IT",
- "yoPRbNPxDHFF5tfT66GP6E5SboxYjnuGWFW859Cpump": "RISK",
- "iTHSaXjdqFtcnLK4EFEs7mqYQbJb6B7GostqWbBQwaV": "ITHEUM",
- "AtF6UM11gM8pB2pcoBLDV5DDwpHPDzgYEKB8oNqSVee3": "ITXS",
- "25vHoSeyJeroPYaTf72o97rCKmyEoGK7iNNHDAv6zYy6": "SHRIMPLE",
- "61uiuu5aAc2HG1ZQaHd3opfLnK6cM4FQnE1jRi28pump": "DOG",
- "2B5Rs88FYyFp4XciFrJ7zovvEeybiinZA8PXsSptBAGS": "DOG",
- "GbQXFoyPTKjWvtj7LE8efXvjThSqYfnvmNYn6Vccbonk": "ITTY",
- "6RFfHjBTgjK3VjDTH6GQ7FN3EsYjjxWcTdExaubzsx1W": "EARLY",
- "146Pouk195TZZBFBc6f1gisFsgsKFviPbwbbV84AfMqt": "JACKPOT",
- "DKnXmFGBcpYEnPsoHLrdj5cbZdEq9DV9z6bVfYrrDEBE": "$JACKY",
- "8cNmp9T2CMQRNZhNRoeSvr57LDf1kbZ42SvgsSWfpump": "JAIL",
- "FBbnzHwJ1WHYwP425cqMNb2t7o7sm6AXQjsQ3sZRpump": "JAK",
- "9g7hrNJUUwgLznSxA3X2nexCGhiqscBq3nJ3vSfkpump": "JAKE",
- "9em5B5cjY7VYGCcEuqnbSDLViezXFgwhPDiAXTospump": "JAKPOT",
- "Jambjx1oJoZNBZiqbiF9TqgatEZPdyfvYa9WVsKNzUh": "J",
- "2cMYUjUQJzrTcnxrD8JgL1BQL1AQKCtRkYLdmaTpCWYB": "JAMBO",
- "51zudBR4NmATG35goida4dLQH5YPn9k8hVkLcizNpump": "JAM",
- "E9uUgGXJ77AVmaqVhN544oz644VUPBGU6r4qUaeppump": "WYNN",
- "6f8V8b9eG5Bhy8iVedzdrX7LyoQKk1Ag6G56XHfYpump": "JANRO",
- "KZtqx9BJbpcGY7vdzhqPXM3ECKChxE5YhXaDiwRondo": "JAAAON",
- "EHCwJQi8dSpZfKm4LJypzozEj5vAN7pESRXJGpESKMfJ": "JAPAN",
- "CmpuL8k9KY3NrpfDRoJrVmuwd1zRMFRUxX55avyGpump": "JARVIS",
- "FR382Gv7RxrEb2q1MZkP9athyJC9rUBt8M2jKfyKpump": "JARVIS",
- "6SUryVEuDz5hqAxab6QrGfbzWvjN8dC7m29ezSvDpump": "JASON",
- "HLQR9Rc7rzfiydRs5qaJGoKniu64zCNN75v5ju4HF2ap": "JASON",
- "JAB57kZjbmqcmaRtgmbeoeGtCjnotLowKGSCfgBMpump": "JASPER",
- "9VY2rDbtsBmTsBxoRF8hWSEUKGqnoQoe9V6W3JnjNgfm": "JTVO",
- "9e75hhwsXQkX6bsHAuwYAQs786XXKnvfReW3gKEcBAGS": "JTVF",
- "E1aUS5nyv7kaBzdQzPVJW5zfaMgoUJpKYzdnFS2ondo": "JDON",
- "GAjvGwTZok2HHSUPi87EN6hCv1TeQMjokbru1y7Wpump": "JEET",
- "HPHau8yipXRgJShyhFxBpeaAfCc5rzkb3KduuRErzZPh": "JEET",
- "DTLYtCJ6cBHbA1ZTkkL9SAVmUVemdCCuH2QeNNXPpump": "JEFE",
- "6ZaQ5yKKbUbNpocw9XaTQUzvsucTcDekofsqAvFRpump": "JEJE",
- "GFreY9SAUz96P7qkF19A4dtA4TmZgtL9Gmu8gV9Kpump": "JELLYFC",
- "5z37F9LJ4evEn2UncteJAyPgoJJNtCPGgm1onNespump": "JELLY",
- "412zDygnwP9DzitnQVgRKUFFTDmrYScFch6P2k39pump": "JELLYBEAN",
- "FeR8VBqNRSUD5NtXAj2n3j1dAHkZHfyDktKuLXD4pump": "JELLYJELLY",
- "EmNFqmSi5DvwGjW57LJ7J5i8R6T155JrNf6GNFaupump": "JELLY",
- "C2nneybCJP2i6mk6Nu6SfTcxoNXNLjngnzwDgje2eNrr": "JHH",
- "3psH1Mj1f7yUfaD5gh6Zj7epE8hhrMkMETgv5TshQA4o": "BODEN",
- "DtgDZb83TqywcuBuWE89jx4k5Y7b6nQ4GYJq3Wd61JQQ": "ROGEN",
- "FQddEUoqKPnAsc4UTkAdAUV3LnCXoZEJMazguC1N11kC": "JESUS",
- "2c8TQe4TUf2doRXd3yQ1XEn7zhT1vWw1y41SXz6G4j7S": "JESUS",
- "FotrwPuTNxP2Rx7DEWVcM3wVNaG1Fs3JV6nW5aYQ9AFF": "JETCAT",
- "EFY8GToe4HrmpYrRpfRUgNEPmfVnUbZrsUhd2mJQpump": "JEWELS",
- "GT5qW4HA3hzfdioeTRhSQpdhcpZWZcDP3Xj5nXraTiAQ": "JIFF",
- "94XduSfSnyas7jAEFSJSXiCi1xQ4mENWcii1aCvjVuqu": "JIMMY",
- "Gaqt6hKqBSRga8pfJ43CfTbc9ZGw8ostPnjytfbNpump": "JINDO",
- "WrDYG6miZG2UcXAGN6jQ73ukbigGEHbZovjY7GVpump": "JINGLE",
- "GgzJWhQWTpv2VHqvJnx5uEWQzNkfQSncDEWUdgQk4fvh": "JIN",
- "FdpH2hc9kXewsvNtrbWbgtWXVHHFCe2YbjE7S57upump": "JIN",
- "B4eppPm1Dj5Nd7KsN1cdJfQgWSSqqSfi9BsNZYkUkXm2": "JINX",
- "jtojtomepa8beP8AuQc6eXt5FriJwfFMwQx2v2f9mCL": "JTO",
- "J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn": "JITOSOL",
- "8WNzazee7WbPLDHi47vt3CdXVNXJnigLjBMmGmXgpump": "JIWA",
- "AyrQpt5xsVYiN4BqgZdd2tZJAWswT9yLUZmP1jKqpump": "JOBCOIN",
- "CXbypcjnbV7A5b6XqfkUCUkLiD3czHXoxAsWBYa4pump": "JOBLESS",
- "6TUJXvuUrS4rnnm8LmG23AZYsWQavY9SpeAG3Cdjbonk": "JOE",
- "H2ZpBXtzk1DaDTzsoXqMhjN6Bd3qzgefHjUZ1e2zuwAe": "JEOING737",
- "JACSU5f2fCsQSCDNz1VX2Se4vmQyj8k5EYigD4RppvGV": "JOEL",
- "86QASyebqezuPdbbkWyYMK5jmTAL1td1SuqobeKEpump": "MCAIFEE",
- "2nCeHpECQvnMfzjU5fDMAKws1vBxMzxvWr6qqLpApump": "SUEDE",
- "CVGBG44dKpUFQBANot9jY9KQ68QCBXAwd4sf7BJxpump": "PORK",
- "KUXt7LzHWSQXp5eyqMZRxWjAP6yM8BUh4LRHwiwondo": "JNJON",
- "XsGVi5eo1Dh2zUpic4qACcjuWGjNv8GCt3dm5XcX6Dn": "JNJX",
- "BuxH23osRyFFLbWG3czrTsfBQYbxzVZ8f7QV4cjTHN5x": "JOHN",
- "4RwVoEESmPWWXG1wJGgpbapYsRdfB2Q3mVHkYXtLbonk": "JOJO",
- "H52CAqEJXY9dmPJChvi86cUR3vLEobUhu7B9wBMppump": "JONAH",
- "BHcPVARUJEV3rCAmbLgRm7QPmZotsCcHcKWwzvCSAHJi": "POOWEL",
- "7ty3ruNJebb8RYmzfpUommJnZnCwaoB8RNfqpjLMpump": "JORKIN",
- "HZNnmhAY6xfq2iKRyBTEvTVeoTYJzpkK8mfnfG8Ppump": "JMONEY",
- "JPGCPKWfGCEMRraSKhsCcn1qvs7qVaLjmq6ihveXn62": "JPGC",
- "E5Gczsavxcomqf6Cw1sGCKLabL1xYD2FzKxVoB4ondo": "JPMON",
- "XsMAqkcKsUewDrzVkait4e5u4y8REgtyS7jWgCpLV2C": "JPMX",
- "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn": "JSOL",
- "orairHM3Yw2PbTfCty1PXy7tEUx3uBMfjouNbm4KnRJ": "JPOW",
- "AvL9rHWzJA8G8mTeipKJ3Y4XBzdeXMq1P5nNEBt9gem": "MENTAL",
- "2LzLh5pHg3nDQz6goTLAvDXfDbSBgAR8qem3bdXdpump": "JUICE",
- "Gb9jGTUrGLvqHacsKDXbxsbEr6pqZb71J661WkBFpump": "JUJU",
- "JosjEXh69RckgSs2AWsN1xN8zmiSHxBuJjHLURJnHhg": "JOS",
- "8rUHbf6cP8ufxqKQUuRhhM5yyDKPr4tN5e5ANz8Ppump": "JSS",
- "9P32yqucXfZnDoXmmJNzBpqXQgfou4tA4sB1RaQh9cYw": "JUNGLE",
- "3UQNqYwBZyZz7WNmGSoyjYLuc8meVnysSCYBDsQ3pump": "JUNKCOIN",
- "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN": "JUP",
- "27G8MtK7VtTcCHkpASjSDdkWWYfoqT6ggEuKidVJidD4": "JLP",
- "jupSoLaHXQiZZTSfEWMTRRgpnyFm8f6sZdosWBjx93v": "JUPSOL",
- "JuprjznTrTSp2UFa3ZBUFgwdAmtZCq4MQCwysN55USD": "JUPUSD",
- "AbBEjBdz31yCb9gTFfWgEi7uprCzjTEKL58xqHVbbjhu": "JU",
- "83SDWc8CaGWwMTFwo1pmktB18SEH84DLbD9AikG1pump": "BONEGUY",
- "HFyN8wr8B9AY5VeWgWTaWxSowVjpkXnDjPJ7DJUrpump": "CHARTGUY",
- "HyU6PuA4oDPxnEpP7E3MGc4u6MQ4m31LZihTF7RPbonk": "CRCL",
- "Fshf9niKKQbAS3KjAxkyhPTTyBcW5k3kVE6DhB1fpump": "COIN",
- "3tPqGuHeHcqD7xgAPNSCv8Wxfb8Ja2v75MQWp6W4pump": "DEADGUY",
- "FWGWrsrvgcz1w6LjSSnuHB5y6KyWXhUKjLWhvDSJ48hE": "FROG",
- "3Cmv9wxP1yNQZErQEFabB3L8uHxz49AtCRMrbKnBSozq": "LITTLEGUY",
- "bwCs4bAMoExahc8Np2rxufxfrGai2Jb3mwkMqxkpump": "$LOTTO",
- "Bb4jR951QtVjeFAYFLBYXDSMKjbTDroCLPbFLdd7pump": "MEMECOIN",
- "wo1zgt8rfrYpvdVi4nidoj1SYfcR4pQx69bmNv2JLhQ": "EGG",
- "GaPbGp23pPuY9QBLPUjUEBn2MKEroTe9Q3M3f2Xpump": "SHITCOIN",
- "9eppz2tFJRStziW3Hgjxu17BDAdpD2Jat4TxMHCRpump": "USER",
- "3LZq8TKNtX2kT8X1H2A4AHcvhUjQ5JTxYWTTc5JBpump": "¥1",
- "GHichsGq8aPnqJyz6Jp1ASTK4PNLpB5KrD6XrfDjpump": "$1",
- "9X45NjtGbGo9zdCFmMyqZyNzC6Wa67KFbfvGc8nubonk": "DETECTIVE",
- "CQDfbCK17ExoXA66nLS2XFrtwPVDhQJDdFRWErjx3Zba": "JUST",
- "FH5sNBwBNNcGdkZmB6oHkoTH7cjEpVN9hgfhoRC6pump": "CUZ",
- "6RxB1KdzVMXrrYn7nQWvaGgh5e2EpbA1FcEFtq74pump": "DELULU",
- "DiiTPZdpd9t3XorHiuZUu4E1FoSaQ7uGN4q9YkQupump": "ELIZABETH",
- "Dz6Pw2zMjXH4pY1bCkUeHvcTfrKGH5fHXZTgTUJZpump": "$HONEY",
- "8iMCGF8ynFMPj4z5QhYprgRDnuE2yk8KbMdZAScbbonk": "MARLEE",
- "4kNS9EDwpiJNBJpUCQ2eYcZkuj5Xo4cco4jsrwk9pump": "PIZZAGUY",
- "DGagMywvLG3DwffZHX4eWWE6svnoJpiod3dSNBDwpump": "JUSTICE",
- "M5MFPbS4X6eYek21xhFU38DTavMLuGY9eyC5p8Tpump": "ZACHXBT",
- "HBV58vtGSRWDppXpaER3KCRU2SyH5Z9YPTF92PTwKvzq": "KIRAI",
- "4daoTLufDmV3ods48Zh8rymaZKBLtgEvuH9qALYLbonk": "MEMECOIN",
- "EtKq5MVm8vFFVAYHX9Y7rYMQu2aWfXDxt7eEnZDjpBvm": "MOON",
- "4xgZmdKKHE3PXtUwUtvJGPSCSTJMJohSmWufJhiVo6q": "REST",
- "AK87oZM8ovFU14bq8mu4ufi5zsCPDbqqVvh5b6WHbUdL": "TIPS",
- "JWmDeJQwXBmTinz7EQVmMMBpjXNU3yHTEQY7Bhy9UD4": "JWT",
- "3FkfFXtMDVkKJ6SAouMSK4qYFmErYxSnAUx6vP52pump": "$K8O5",
- "F1uB7phqFVuyzsFoXWkcwNoCY3KJGFNsFLyeSoQYpump": "TITAN",
- "4CKd1pfak4Ss3EX9aHqz7hAkwVdhTqtrDKNexwq1dFxY": "RWT",
- "Cm1wUvp5x2GuSkU3F9q3GoJaFvVWExx1MH8jEscWpump": "KABOOM",
- "3h4DGQd9k5gsiMnNzDuGXAcjkMm5G7iC3knykdvBBnxU": "$KABOSU",
- "FJup6BbEBoCeFJZtqW4qcaqABLco5SkV8683do38P9tu": "KABOSU",
- "H758qwhw8YHLbDYmJsdN6Jta2ioguZ53PY6Qcisupump": "KAFKA",
- "2MuDS29b6rQb9MydKLMvggST5Yqez3B6gYWitvvjc6ir": "KAI",
- "AaoHhEyupbhaASkCCr7AgEvZh8AknSuDFwgw1nskpump": "KAILY",
- "B6dvdDUUYBinNDUT4xsHBSCNu2SKb9P33Z79ySakLREV": "KAIROS",
- "kZEn3aDxEzcFADPe2VQ6WcJRbS1hVGjUcgCw4HiuYSU": "KZEN",
- "3ejk8LXAS9kUC7XhpDGHRjARyUy5qU7PaAq7PMykpump": "KAIZENOS",
- "FH6jc68WzeAUXKp6uDg9QPciTeU75o32xFDzKLzmbonk": "KAKA",
- "PreLWGkkeqG1s4HEfFZSy9moCrJ7btsHuUtfcCeoRua": "KALSHI",
- "6BuKbBATFnUF34g97Vtni5Xq8qNyzYD412SaEBoStPKU": "KAMABLA",
- "HnKkzR1YtFbUUxM6g3iVRS2RY68KHhGV7bNdfF1GCsJB": "KAMA",
- "KMNo3nJsBXfcpJTVhZcXLW7RmTwTt4GVFE7suUBo9sS": "KMNO",
- "Gy55EJmheLyDXiZ7k7CW2FhunD1UgjQxQibuBn3Npump": "KAMIYO",
- "4yTZ41t1WUPJoEFwhmFFzrL3UbFWkdDRVUKJTtLwpump": "KANGA",
- "CQSPU12VppGZB7LeRkEaKzrRBzvo1LyA9mR2ydiwKHaL": "YE",
- "doPqjCxi6UkANkvMz5fSuYGEo5PGppVpTZMeB5vondo": "BZON",
- "CEhFvMotKm3zucKUBEHVvTaxQ4e9QVPaAjSfkzFLpump": "KAPPY",
- "EdN7mEndu6esJox7WxDdPhGZhmhYkFN9bTgsAxnNpump": "KARMA",
- "Ta1wrnVmwJ25RpE4KN7z4YNMvBhSKgi4U6uu9xEtime": "KAWZ",
- "A88EaDaxmui6kGAy9MqEhLSpx1Ds4bHcPeK3kNVXpump": "KNU",
- "5Gb67sU9UgZsrbhrbKs5yYtWLFPwPLYKzRQuUEZfmoon": "KFR",
- "4ZDFnVXL2ED9htVnLTNMwCwVttp8TbBJcwzFePZwpump": "GAMBLE",
- "2fZTwhbLg3xPquk8CqS3KKYbrNMbhKj7Q5zBKuT2pump": "$KEK",
- "3HxDM7xreHuop94zzzVP39fTKLvJCwHcSYgrSf8cyg5M": "KEK",
- "Gp8GVGPc8QCe4Jn6ryG5YKokG5bjKycATEzqpeyspump": "KEKE",
- "HuAncxDEsakCDgZS2Yfo9xJbHmtHXMnxxkT9jqdXnHhm": "KM",
- "HAVVqPQf4MKVjvuFVi8y7g3xkArdWQemaJPBvKmEpump": "KEKIUS",
- "FThrNpdic79XRV6i9aCWQ2UTp7oRQuCXAgUWtZR2cs42": "KM",
- "XC78JjRHnSqaysrHiTrhR8eRngFbvX3rrHyRjWEpump": "$KEKIUS",
- "6P7xxdfAZzY4AYZuZCwcfgQLaXpDnkxYjPjrBN3Zpump": "KEK",
- "6HP3PZ5DkCy6kEjS8CKPfeMCXgoxyTcdvEakzFyzpump": "$REALKENDO",
- "2nnrviYJRLcf2bXAxpKTRXzccoDbwaP4vzuGUG75Jo45": "KENDU",
- "53oF2Fg2RZcVKNPwzQ5s7eqtF6i7orGWBpNkBAZYTTqD": "KENJI",
- "CEY7Xa21gE8fh3ksS43STCftHHJNnSE2seF1Vscdsmth": "KDT",
- "9pPE1q9EW1bMQWbHmffrzUCfRr7S82UoxNUFfA6mAZC6": "KEYCAT",
- "3fGoNjPohYRVPk9iJuwEW5WuURU5gmAdSRgNgeaanexQ": "$KEYDOG",
- "4KVGATyKJNhm8y8afj5314rNAkB9MZGJVDE5cCKTpump": "KOL",
- "AiQcnL5gPjEXVH1E1FGUdN1WhPz4qXAZfQJxpGrJpump": "KHEOWZOO",
- "BxBkTCHsrcYChcwB459CAGPX9x4fWSVnmzqh5efgUN1R": "KIBSHI",
- "HhCLbkW6FwhriTkk81W8tYstsRCLUu6Y7Je1SQjVpump": "KIKI",
- "npB9cxTzwUiGt7jk2dXZa52xZve8SgVD6Et9Bpipump": "KBBB",
- "CFYhdWXsYfS7swnJgHRwb5toTHMEQD7Ljd5gGwKLpump": "KILROY",
- "HaUXAdAWWUkb2WTmh8z1TdaEmZkYjnQnmC6tHUdTAHvi": "KIMCHI",
- "AWpD39myXc7emw5M9cMCofkbo92x5FKWdGHWYpZFdoge": "KIMCHI",
- "kinXdEcpDQeHPEuQnqmUgtYykqKGVFq6CeVX5iAHJq6": "KIN",
- "V5cCiSixPLAiEDX2zZquT5VuLm4prr5t35PWmjNpump": "KIND",
- "CVfniqNEj2f4Yd8Z4TEtaTU49gWNTwUyCiDDUbsZpump": "KNS",
- "9noXzpXnkyEcKF3AeXqUHTdR59V5uvrRBUZ9bwfQwxeq": "KING",
- "HV2tLSVHRk3Yx76GsR6dGRTsebbkJJyY4ujhLAyf9T7E": "KING",
- "9BySdih23rwDPZB8auQXX9k5u6a2Nk4GSDji2MB6pump": "$MYCO",
- "CfVs3waH2Z9TM397qSkaipTDhA9wWgtt8UchZKfwkYiu": "KNET",
- "GZxrdsiXEuGBkUbhAov394489CtiF9LMA7g5HsdVpump": "KINTON",
- "87n4vtsy5CN7EzpFeeD25YtGfyJpUbqwDZtAzNFnNtRZ": "KIPPAH",
- "CefZxozhhxK88XPJoeWBczYSaBPd35tsKnziTH6Cpump": "KIRA",
- "AY2Qidgrky4TFymeJKe36w5buY7QWK7TSd7obQLupump": "KRA",
- "3Ei8SaoL4JWZv1XsWePqiAjVtb7QtpJbV2TSuURmpump": "KIRI",
- "JA8JfHs6v8ZXmz4MDFaqgEJHkxWxRnXfVbXidm1sTGCG": "$KITA",
- "CyUgNnKPQLqFcheyGV8wmypnJqojA7NzsdJjTS4nUT2j": "GIL",
- "AUgdt7wjBifF9vZpde7BjU6HLroCYh4SUHYc7yhheECW": "KIT",
- "9hfKxLSnwh4LhpRgmxBYDRgrKeYUgszMePKxuidPpump": "$KIT",
- "DN1sKvPYqht7Lx2AkhsVeMYGR53rVav1iJzygmstpump": "KTE",
- "7rCrPCf5qTcEAvDC3mH89rjZMetpRDLXZBvqLoPPpump": "MEOW",
- "3TWgDvYBL2YPET2LxnWAwsMeoA8aL4DutNuwat2pKCjC": "KHAI",
- "6Rwcmkz9yiYVM5EzyMcr4JsQPGEAWhcUvLvfBperYnUt": "KWIF",
- "8yJ15ee2AUQmwbWPxXLTTeBTzyMGn4MtSRKMqVHw1J1G": "KITTY",
- "41fZewbrb8x24yE9KeMJExoVXCDggebPMEwRVvX8pump": "KMC",
- "72LTryHMb1m9j4NEcn673sXkFMXMmHvmB8grYcVspump": "KS",
- "149o8ppQf9SzKCKXZ4v3dzHkwumvtQSRzSEkr29uondo": "KLACON",
- "1zJX5gRnjLgmTpq5sVwkq69mNDQkCemqoasyjaPW6jm": "KLED",
- "CeFrV65BuLHSsa4XGjaJau1af8Jr8e6Kxqc1iixwpump": "KLOUT",
- "5ritAPtFPqQtEFHcHVqNjR5oFNUJqcmgKtZyPd2AyLLy": "KNOB",
- "LhcykxUt6xVdiSZyWyaGdNHE3W8sAEmdnEjpMdkpump": "GG",
- "7RDvypx3p9EWq4nZZKux1ZQAc7DUWXpHTVKxCCnupump": "KNOT",
- "Gw9saRvRTQUyMmYBabsGibceFaFe4RKK18nrbWYZpump": "KNUT",
- "ALWi1o3qgXp68UyyDkG9EvL1Cq4ofhLsRbDJYbMkpump": "MESSENGER",
- "FsA54yL49WKs7rWoGv9sUcbSGWCWV756jTD349e6H2yW": "KOKO",
- "48iJcUv9jsiZ7cCisyVFLPFLMoNBKg3L43bRvktXpump": "KOBX",
- "HmfNGq7kxE6ppMDGW87xPuMU6wnKbeYBZf76K7t33w3s": "KOHLER",
- "6fdCC8xfrXNy6PmNaVcxdEY5XNCTAha2V54zYYnmBCey": "KOI",
- "5HkhVG2bSb5PGjhX5QHm9urUquD7tx5eAau5Fonq78zc": "KOKOK",
- "HTWDJbpi6o9Zd7SuVDBRo5fUPXgffmo27f954Vzipump": "KOL",
- "6U932RLNzovLyi5rFpc1K72yRCSb2dtwMcqXK2svpump": "KOLBO",
- "4q3Z58YxrZEAVMLtMwnm7eHtodSD3LSpSNt3pDnqpump": "KOLIN",
- "58AYn86ZvgwfTJo56xpnPQ8u21W2NsK5QhnSuMyBbonk": "KOLS",
- "6jTQCFZR8JwvvenVGa3RzGM3a5YEagk9kQXDpHHdpump": "KOLSCAN",
- "3M2vepByfZTG6xUSmFidvSCFzHWFoVw7cPvyRDnUpump": "$KOLT",
- "DZpa4peCErsNzsYJ69XYYTSjZGDQhuexnzj7EiZ1pump": "KOMI",
- "EdkMbLbaHZNUSez4Z36t8fZbHwtQ4Wt34Q4YLx2ipump": "KTO",
- "9GuqvJbdtSrK6JNHKTvi742T75ShGv1R1ieTmEutpump": "KONEKT",
- "AhP7ojZMRMMcmxwr6S1UubGWagFbDuU36tTj7ZYypump": "KOOK",
- "3H4srZRfFDkp1MxsVcRreMYVmKizFz6B8YcXWv5ppump": "KOOKY",
- "8neDcPFwrvRNM9WXHCtHwTcKZrVm6wr4cs4PSN9Hpump": "KORA",
- "HtTYHz1Kf3rrQo6AqDLmss7gq5WrkWAaXn3tupUZbonk": "KORI",
- "t5cSTUSZzUAQXQKzQvhieFG4Hz4xC23z9du1Chp8gES": "KORRA",
- "D1mM9THeoBEa2xBbRHpinBPc9x6rDeKUYzMvcUDzpump": "KORU",
- "SUBXNGpJq2kseayQihcqTjfc8EbT3W5iQwjXFQpbonk": "豆柴",
- "BfdVHnbt9LSNAFCZU9kvTjbrH3jX78sv2siLKGQ7pump": "KOTO",
- "6kreK2oNJpVweA4wXA5vUsyhtcXxDhANRk1w3BbCpump": "$KOVU",
- "DcUoGUeNTLhhzyrcz49LE7z3MEFwca2N9uSw1xbVi1gm": "KPOP",
- "U1zc8QpnrQ3HBJUBrWFYWbQTLzNsCpPgZNegWXdBAGS": "KR8TIV",
- "DFc4kvax4JYFePaQLZeypGREyeWkeo2Rk7JjU5pS4R43": "KRAMPUS",
- "DVPSYdqWPLvNa8afnEqa3B9eDfTTWpGyUZeXvdMondo": "KWEBON",
- "XsAiRejKuvLAdq9KtedrMSrabz7SWdzKoVK6Qgac1Ki": "KRAQX",
- "F2hgieC18MeUWaWMoyaxLSQCzS7yAjRz1HgmbGAEpump": "KREDO",
- "Gw7M5dqZJ6B6a8dYkDry6z9t9FuUA2xPUokjV2cortoq": "KRW",
- "A8h78muegtuonUxqAhpmWcM8pJskYsTW4Xp5C33ipump": "KUNDALINI",
- "7DJ8Ufmcm7Mh1HCK7C2ZA4WiCnhocecYeJvAGv8PLdQC": "KFUCAT",
- "GQx3p7aTHLQHDqzFR3c1QSk1Qhy2hz4YbAnkjdXtpump": "KFH",
- "7H2k7iSHcAmZrXZ1wv9CWRzJbS19C3LZtEd71XRhjBLV": "KURO",
- "2Kc38rfQ49DFaKHQaWbijkE7fcymUMLY5guUiUsDmFfn": "KURO",
- "919MM61rJb1KairDkbNoH8iCVkX1fGFn7w4Dj6Mapump": "KUUSOU",
- "9Yt5tHLFB2Uz1yg3cyEpTN4KTSWhiGpKxXPJ8HX3hat": "KWANT",
- "DEf93bSt8dx58gDFCcz4CwbjYZzjwaRBYAciJYLfdCA9": "KWEEN",
- "kyrosJC2dtm6EoLV5wffZsS4RZVm2hRafKZCLsc38JE": "KYROS",
- "kyJtowDDACsJDm2jr3VZdpCA6pZcKAaNftQwrJ8KBQP": "KYJTO",
- "kySo1nETpsZE2NWe5vj2C64mPSciH1SppmHb4XieQ7B": "KYSOL",
- "HjdE4j3rHC7YMxFMHXSgEzXoNcVU6YBCfg9Q1gTJpump": "KZL",
- "CMDKx3TGVJryRDQ2MnAkTRNSyguQLrKgiCPZ3Jc6r8r2": "L24AI",
- "E5MBirnq71DthjqwsAsgvCtgCAzShoWqnrzkmVQKviJc": "LABI",
- "3nSMUVeDed6G67RwLvBWxiYU2qEGVJXf2TD5MiTRpump": "MEMELESS",
- "H57gd4TRhsmhg5brTe2bygibAKp2btwS1uEStoUrpump": "LAD",
- "7TgfC7finEVA1QcCbn1Jb2cz4RiDL4if4ATEGHZupump": "LADYBUG",
- "Fj6p7eodS67517JTEJeYNN54bvk9fRK1Q7oC4pAupump": "LAMA",
- "LMFzmYL6y1FX8HsEmZ6yNKNzercBmtmpg2ZoLwuUboU": "LMF",
- "LMDAmLNduiDmSiMxgae1gW7ubArfEGdAfTpKohqE5gn": "LMDA",
- "FhAdp55ngkaRCC3TGAMsJdDCUHQDPTMcxQDJ4HCfnxMf": "LAMBO",
- "GQsefQc5YPE12wkMnYMxD8Rq1wrRX7f9iFgpBjNpBAGS": "LAMBO",
- "wFJoeEYpKg9oRhyJy6BWTT3J95gmXBLvoeikDQNondo": "LRCXON",
- "43uhykFm8Y9gLvHrWs7r7w1HCKu6vikDi7j394FaSfNz": "$LANDLORD",
- "2qRbtXPMx9LGcgk7TTEHbbemEr57ABdKsLbjxUSwMbJd": "WOLFINA",
- "LnTRntk2kTfWEY6cVB8K9649pgJbt6dJLS1Ns1GZCWg": "LANTERNSOL",
- "8PH1XWXyhvFWXWeixSbcWmfHX4uRJHQtcjnwkCgzfTkY": "LAPUPU",
- "98mb39tPFKQJ4Bif8iVg9mYb9wsfPZgpgN1sxoVTpump": "LLM",
- "Lrxqnh6ZHKbGy3dcrCED43nsoLkM1LTzU2jRfWe8qUC": "LARIX",
- "CE5hEYzTBwUP5U2uDcmdfGHJMh7oh7VVPvKNP3Ffpump": "LARPBALL",
- "5UmDWgyLV1JBg8Jr8NwyezXdQkiU3vHGJu2efm7Cpump": "$AGENCY",
- "6m6TjSDEbbpcEYEyvb2ksdRd9CFYENRU6yAZ4J7jpump": "LASHI",
- "6yJbrQLd3N5xKgz4PLjADwxnNZj7N1g5bWXjz46Dakhr": "LASTCLICK",
- "BnszRWbs9LxSzsCUUS57HMTNNtyDHFsnmZ1mVhAYdaos": "LLM",
- "HfqS59Gc3CjMsLTUEcWznkcsKBUpqZJ8FTyBU2jhVVKX": "LNCHM",
- "B5boCskXEFb1RJJ9EqJNV3gt5fjhk85DeD7BgbLcpump": "LAUNCH",
- "86ZnAujEVLmtnNazeCeT1zYR7hn2PeF5ZPEwUkTdpump": "LAUNCHR",
- "5yes8vgfrsqP31JZnFxKVU8A5X1brigqkxySYvgS5kLk": "LAAI",
- "F15Vp1vqJdQ58Usk4T4GDcL7YGegcp1pznHrpt9opump": "LAWN",
- "9RAghejZNirG4skdqUXxVVSnKGmYSjjjgnPMPjyJmoon": "LOA",
- "FFm8NUwVsDpfaGvWUyL9xcAmk5cdnjHq1tb7eBzBRTZv": "CODE",
- "5k84VjAKoGPXa7ias1BNgKUrX7e61eMPWhZDqsiD4Bpe": "L3",
- "HeFNBDauVZDD86dV8TmFGx39kGxmFLrVKqbYe6wXWcPT": "L1X",
- "7iqRq48RjwPzXHEarqSiYW53jqrKfuLPJd8z6S9Ybonk": "LZR",
- "2JYuVHdmRtKu47xiNgff5eTJwxBFpTnBFkF8HYJFNL3S": "LCP",
- "43YakhC3TcSuTgSXnxFgw8uKL8VkuLuFa4M6Bninpump": "LC",
- "8SpPaFLycx897D6sowPZkEkcNdDahzRZb5itr6D8pump": "LEA",
- "52axFFPqNeHHL86yANnRpu8iedLjx71iJ4LZJoDopump": "LBW",
- "Fdp3GvvkJZkaKLF7DBwLs5Ar1xeNgg4sPR3LCoSgXn58": "LEEK",
- "oraix39mVDGnusyjag97Tz5H8GvGriSZmhVvkvXRoc4": "LEE",
- "3KAeVfDbU6tZxSD2kqz3Pz6B6f42CW3FdA89GUZ8fw23": "X",
- "G2jXu2puUqyQsXmcL7SammGfkHX734wLZPce7yDepump": "LEGEND",
- "J4ixzSEG99FWNoHRYfoaE3y2e7T7e7KX8NKNPy96pump": "LEGEND",
- "LGNDeXXXaDDeRerwwHfUtPBNz5s6vrn1NMSt9hdaCwx": "LEGEND",
- "5rSP1W2Jkir4Qy1M6rEYXFFi5HgbhrkVTajimrVgpump": "LEGIT",
- "7obg932wg2A1oTZhrPzR4DSdhKbjXzKSfHTBo2Hu5EbP": "LEH",
- "9EPYaNqzJLSPSFH9aKSxn2EaJoxHS1oqt7pVBR3yivt": "LEIA",
- "7usVzynPTUJ9czdS96ezm9C6Z3hCsjb7j6TMKipURyyQ": "LEIA",
- "2ru7VX6NnaZ78znCtgGmYs2PdcAQRCr3UaPfRkDUpump": "DUCK",
- "Gc5hxBYZjxWNpt3B8XYbp4YoGCHSMfrJK7ex4GUTpump": "LENNY",
- "AdwCEWQGzt3vuFMEPMf97AJMiq1eYL2sR7gk2x42pump": "LENS",
- "8Cd7wXoPb5Yt9cUGtmHNqAEmpMDrhfcVqnGbLC48b8Qm": "LEO",
- "Fnmq5udTPPkxGjw8nDtnRsjJWfHfdNmsfKGLhUerBAGS": "LEON",
- "GsEbfbyjjnYZGMSkXhoxrqTyrzdYC5AFcCisS51JEGEE": "LEPER",
- "C9smdbQEsoZhnNCYhqeLDNE17aMGdBjJvqzk59DCpump": "LEPRECOIN",
- "LFG1ezantSY2LPX8jRz2qa31pPEhpwN9msFDzZw4T9Q": "LFG",
- "HEZ6KcNNUKaWvUCBEe4BtfoeDHEHPkCHY9JaDNqrpump": "LETHE",
- "G8Vy25NzjRmuQtnN35xF7j3X2Z1TrV39XijZu8Mg4w8n": "$COOK",
- "7JKRJxWihe6Pt22L9vudAGaomD9ViXiZgXdk4v4kpump": "NOSE",
- "CDBdbNqmrLu1PcgjrFG52yxg71QnFhBZcUE6PSFdbonk": "LETSBONK",
- "hqYtLoxviwGENvogcJ5324YTbYqW5H9LHtmQu5Jbonk": "BONKAI",
- "2vFYpCh2yJhHphft1Z4XHdafEhj6XksyhFyH9tvTdKqf": "LGTB",
- "8SePknMizxUWZFnyHcNLXy6wiqEWUKG1kgV9Z6N7BS6a": "SENDIT",
- "W2bAuFf2Xeb7ZNpJTywFSaCs5jYkaLYtBMR53SzVXUo": "STOP",
- "AMEdarx3ryELQsFVNynCQdC6ABi94x8whxGjbmXBpump": "SINK",
- "4fSWEw2wbYEUCcMtitzmeGUfqinoafXxkhqZrA9Gpump": "PIGEON",
- "E4wg8YF472u8oiLvSNKB84Y23gZhkSQ3PSCJaUj4pump": "LEXICON",
- "v12TwfofSbvVqQ5N5KGG4d3J8rtEi4BjGfn2apyondo": "LION",
- "GwKKPsJdY5oWMJ8RReWLcvb82KzW6FKy2bKoYW7kHr16": "LLD",
- "mntpN8z1d29f3MWhMD7VqZFpeYmbD88MgwS3Bkz8y7u": "LTAI",
- "FLTHudk5B5zag7JmGXqrYrFfey6otevLQA6jm1UHHLEE": "FLTH",
- "7Zt2KUh5mkpEpPGcNcFy51aGkh9Ycb5ELcqRH1n2GmAe": "LIBRA",
- "Bo9jh3wsmcC2AjakLWzNmKJ3SgtZmXEcSaW7L2FAvUsU": "LIBRA",
- "AKKasEPSAXaf9BRwyJTuU2TczYq6yUwj2FAk7U5b8cPZ": "LICK",
- "DFhT16WmZjyUYaz2qwWWb7atC3w3yfDffz74cFFBUDAz": "LCKO",
- "HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p": "LDO",
- "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj": "STSOL",
- "5XqzzdodsNtAM8TtQyiqGVbD7GwLBBN7oVnRA3hLpump": "PILL",
- "C4yDhKwkikpVGCQWD9BT2SJyHAtRFFnKPDM9Nyshpump": "LIFE",
- "6D1hQ22C7oCUKKVuy91i8HTHnzSjsHCuNAcH9WH2pump": "QI",
- "LFNTYraetVioAPnGJht4yNg2aUZFXR776cMeN9VMjXp": "LFNTY",
- "node3SHFNF7h6N9jbztfVcXrZcvAJdns1xAV8CbYFLG": "LIGMA",
- "qnko6WJGEwEU3JYQFZakLe9V8dmS4YAXFARHeRipump": "LIL",
- "3meWn4683ng7FgLVJJB2bYPaNSoqhWdritNdkd4Aw1aj": "BUB",
- "5UNr4EKg7rBwjKK9xBGxGVwHuYWXFWu8VkewKquTpump": "$LILLO",
- "9vrGUHwsC8LyLjQoh3zJb9S53x7A88u49La63qPB6F5t": "LILPUMP",
- "Co5WwGeZfpfqGE1tUyAp1SBjcmumoY9sNN99MXRbX98K": "LILY",
- "5UAMZkfNmuVcKzr2wo8Jqw4R1k8vfdAVJNN6h3bVpump": "LIMBO",
- "H3QMCaMh5LxtS9oGDwaMaRXPSPSiXVqnY4YsfrQMRjqD": "LIME",
- "44o1iDPGuzHxQgDrPE3HRb2WXwGLsBsY7yMttX47pump": "LIMITLESS",
- "86t88w3MKT38HChTBKBwEeb1RW1MeTceaW68qY2Vpump": "LMT",
- "Edik9MoFp8LAXS9HNu2gRFyihwYqDqv4ZmNmVT9ondo": "LINON",
- "XsSr8anD1hkvNMu8XQiVcmiaTP7XGvYu7Q58LdmtE8Z": "LINX",
- "7DKFa79o6QfbGGEtBZ5ZYBJw1qLJWyNuVoMD5rxbpump": "LINGANG",
- "GWZGj6AM4pkWxQW6bifE6JChSRf2hEQFWFkYC4REaL7H": "LINGO",
- "6ty746K8QZFpGGrimYHMsAfXQnewszEgPfT39atbpump": "LINGYAN",
- "25Ew9oMprcypdK2KbecFE6Btvy5HChaDYUmLdm7aLinK": "$NATION",
- "9LrT8gAKJ5qUJA1wJoQRrVfapJGrNnU2ca5UYiJipump": "LHX",
- "GF4mRrsd52LHBZ4Fj9ijEwHCnh7c2wTMwDKwZQqipump": "LINK",
- "CV38eqqRKfhvqZ5yyuwuNFGTfof1wYvNguJXt2mZDRMj": "$BEAM",
- "678qt3ZQCCBLjjzb5iC5FVmav94ayRiwsz3FUysrVyNc": "LICO",
- "4wjPQJ6PrkC4dHhYghwJzGBVP78DkBzA2U3kHoFNBuhj": "LIQ",
- "CKafriN2DxGwTWSBZJLhAe4JgyugadBg27SyL1ameow": "◯",
- "J2kvsjCVGmKYH5nqo9X7VJGH2jpmKkNdzAaYUfKspump": "LIQUID",
- "BoisYJqhMhgpD5291J6HRC3u1jeDkF8uSLyFy3fKb5o5": "LIQQ",
- "2PrJoPoRzsm8DNuH6XPcTCtvt8XFzHBxqjwG5UC1pump": "PISS",
- "BaaYhmQBjX3B6JAayG5mDbhziyKsf4KDr9ZHzaEhpump": "IQUID",
- "72hdqAZq83HUYz9kxsswbS2r7NBGEnxtnugCSzi4coWY": "MERC",
- "2Swx96wtZw9tWAqCLvPCnht3jmJ1SUQwy9FBbeHGuZvn": "LP",
- "DDti34vnkrCehR8fih6dTGpPuc3w8tL4XQ4QLQhc3xPa": "LSD",
- "3sfANVyJiq5uZCZvyizaDzBtHQQTNBr6RBGdXVmFcN5p": "LSSOL",
- "LSTxxxnJzKDFSLr4dUkPcmCf5VyryEqzPLz5j4bpxFp": "LST",
- "Cn5Ne1vmR9ctMGY9z5NC71A3NYFvopjXNyxYtfVYpump": "LISTEN",
- "5z3iCe53hUANTiG8Js8RjHNE2Arjik7L2CXLyr2rpump": "LESTER",
- "4Y47LEufvcSSSbTFojcvW4Y6x2KZXrqG2urNBSvHpump": "ME",
- "DqRB2BZUfWFX8ZbCQvjWFor8KQTohaiTynSsYafbonk": "NOTHING",
- "G2ajLzpiW6tPvRqdjz6QfFKyArrh7zh66Zi1rmoppump": "LITTLEBUCK",
- "CS7LmjtuugEUWtFgfyto79nrksKigv7Fdcp9qPuigdLs": "MANYU",
- "5eycqvLdZGfPUFcwsk6pzWJDkq9yAGYXxDP5jJTWpump": "SHITCOIN",
- "FyB8VxxYAaVVchAgbB1kvjWdw26ovaD4ipwV1j8epump": "RUNNER",
- "347k5f1WLRYe81roRcLBWDR6k3eCRunaqetQPW6pbonk": "LIZARD",
- "36iztMbw5zshWLoyhdcNUZgsVBgEGzoF4NPuwk3rpump": "LIZAI",
- "H74CYmXgMkYHYuSRsZt6RJb4NYp2u72Vw8BS5huApump": "LMAO!",
- "FkdpsuYhtWnmLctmVki1ugKdxLj4nXco7XCLGcx1pump": "LMEOW",
- "7kN5FQMD8ja4bzysEgc5FXmryKd6gCgjiWnhksjHCFb3": "LION",
- "LoafdJ3WSAvsrx3zppSGKA6sRvL9GrRrU1iRV7HkLkm": "LOAFCAT",
- "AVF9F4C4j8b1Kh4BmNHqybDaHgnZpJ7W7yLvL7hUpump": "LOBSTAR",
- "75mwivXSRWm6sxUip91Zctc9m9H1NE48qDLcTgiXpump": "LOBSTONE",
- "EoReHwUnGGekbXFHLj5rbCVKiwWqu32GrETMfw4ondo": "LMTON",
- "8Ki8DpuWNxu9VsS3kQbarsCWMcFGWkzzA8pUPto9zBd5": "LOCKIN",
- "CXBVSveFCtdih8mhVWtyrLcyPvpzNejCARHYhCzhLode": "LODE",
- "HJUfqXoYjC653f2p33i84zdCC3jc4EuVnbruSe5kpump": "LOGOS",
- "LoL1RDQiUfifC2BX28xaef6r2G8ES8SEzgrzThJemMv": "LOL",
- "6fvys6PkSCgZcrDCCkYp56BjLMKZ41ySZK6qtgzX49Hg": "LOLA",
- "AKyVUXwrYPxnt9cf9EQUpRmty6yrW25d3R8R1YVepump": "LOLA",
- "Dt6vESocrRixuFz2taZunygpKcNQwxAjUMgYUxvNpump": "LOLCAT",
- "53Xy4g1RJnGR6saaJRDNoo1rYTGZ3W5U321EDdSa5BGD": "LOL",
- "LBTCgU4b3wsFKsPwBn1rRZDx5DoFutM6RPiEt1TPDsY": "LBTC",
- "EGMuM8qhWTzTEa9P75DuT3G4DNVsexWww7fp1vo8pump": "LONER",
- "gxNuJSHRScR7WkzQEYqvxVditaKkcc9V32KXPJLCbcT": "LONG",
- "2HUDMBsnctpkQo2fdf6Z4ECrXhAJbemJ4NJr4X9Spump": "LONG",
- "BCzBBz5c6fCcRU7UjdJxszaECh7FdnU551MoQewpQv7L": "LONG",
- "CBW9tWMs2yF7oXLCZpRfGUjyqui5ppEKQ3NrQvjEpump": "LONG",
- "CLEjjvLaGoQjGxu1N3iVvjaCxDVtEZv4YJ3pSoAYpump": "SHIRO",
- "9yBr75m6TBZzQqHeh1ztfv454pmqAiAvHUHdpPQcpump": "LONGAI",
- "AuYzLSUHCKiX4MTK21J2vDAqj6JX5Wa6BPSwugw7CoJA": "LONG",
- "CyRbC97yrkUB31sv9PLw5Hw8276zXH4sRoTE1KcDpump": "LOOBY",
- "9223LqDuoJXyhCtvi54DUQPGS8Xf29kUEQRr7Sfhmoon": "LOOK",
- "BSqMUYb6ePwKsby85zrXaDa4SNf6AgZ9YfA2c4mZpump": "LOOK",
- "8aZuUoqr9rBLjikz7kvpajm1JRqhoWiLMnrNtnRNpump": "UP",
- "8ztixkSGb1sdq4cBAA44NRAdkUZBuRz9snquq72Gpump": "SENDIT",
- "3Aa1AjmRw3MdAS3xXp2geGwsknd9s96CfSLzYLR5bonk": "SENDIT",
- "sRCDYrKbg186hfdrVnY3K8WTeW13cj7M25sA1Kvx2f7": "LAY",
- "CHX3FSxGYSJ2LHeQTcGp2oMAoBNngtJ73jsuamMUnZQx": "LOOPIN",
- "GSSPA5zDNqpmao8BFnUHnnQrc3tgUeoVSesXtHhxpump": "LOOSE",
- "44bzge9EZJGPJRYNmsA64mdKZ1eeLdDcDiczRmoyAtez": "LOS",
- "BYMCXiiA4om347ChR4t6bYHzkKJwnULLAg72BeDdpump": "LORE",
- "G2AbNxcyXV6QiXptMm6MuQPBDJYp9AVQHTdWAV1Wpump": "LORE",
- "4riQPy1yXQ2d1FfzgLy9eJy6yoUdZuQkMj7JsVKr4bGu": "LOST",
- "6KeQaJXFHczWKjrcXdMGKP773JKQmMWDXy4446adpump": "ATOM",
- "5DQSDg6SGkbsbykq4mQstpcL4d5raEHc6rY7LgBwpump": "LOU",
- "EJZJpNa4tDZ3kYdcRZgaAtaKm3fLJ5akmyPkCaKmfWvd": "LOUD",
- "BprPz3BbG5dDqLoY1qYqnSadTEas54E5bi5MbyLAZr1x": "$LOUIE",
- "7BMb4jNt2tQG81jX7W22H2h2UyL4SW9QJgz25HRhpump": "LOULOU",
- "EEhPz661wF7t9DmEy3SufExspgj1DcxBt2FywvJnbonk": "LOVE",
- "6LDF727vvVi5YzisQ5XRr5Mu38sr8qttMe6MbvdHpump": "LOVECOIN",
- "4QQV4LQUUXAn1eN1XQGrfY65TfLe5STJcfsCQozqyb8T": "LOVE",
- "4EzbvuUVUFBf3gvtPu5js7sfMaDW7WQVTXdYXoM7pump": "LOWCAP",
- "edLdFJVVR532qhcrNTJjLAmhmyV7NsctbWVokMBondo": "LOWON",
- "HKv9jA7VREs68BA3PZMREiwuQKzfLUjr9azgrzbNpump": "LQC",
- "LYLikzBQtpa9ZgVrJsqYGQpR3cC1WMJrBHaXGrQmeta": "LOYAL",
- "4SDfM29FFTmQDGKBHtThh9oYhdRcwPSTqYVgJ6EtyLSD": "LSD",
- "Fof1DyVSYiQGCnT3uTbmq8kQMPdwL35x1bD82NaTs9mM": "SANTINO",
- "5Ke381D44MEQg3BQarWhAwhj1xbdNvXe2KHkTiZzw7r5": "LUCI",
- "qZtEkb7KAPDtgx8AzeMPWMvXAiYXto5dGbJGk9Zpump": "LUCID",
- "Ak1StSUAardZ157jSQu4hMkkoPFiUowttuowUeompump": "LUCK",
- "9aCHVRfLuKV6R5yBnuEjHQjs166yu6y2St8rp5pKpump": "LUCKYCOIN",
- "Hg4sgaK1ppfYAokghanL825WtteecpdXsoaTbB7x6tqS": "LUCKY",
- "F5qFr17LeunQk5ikRM9hseSi2bbZYXYRum8zaTegtrnd": "MODRIC",
- "XsDmtC5EpfzJoCzDN2SJP98xpCsSR2CqdZauJSvHNXT": "LULUX",
- "4pTN87RQi7Bt7yzU3CFk6FDiD8BYbH2dFYPwsAfjBAGS": "LULU",
- "6Q5t5upWJwDocysAwR2zertE2EPxB3X1ek1HRoj4LUM": "LUMEN",
- "6DoRX8vRqH68Nxz5ZnErndHdpAeQy9pDahaKqvaJ59Fv": "LUMI",
- "BzpqoPc44oaHu9SB5hek1GRNjzc4UwFcL4oWusWozm3N": "CHILL",
- "5Mp8mZuRpWn1t6MkZJJcpj2AyMS7kv9mvBecg6t33oH3": "LUA",
- "4FkNq8RcCYg4ZGDWh14scJ7ej3m5vMjYTcWoJVkupump": "LUMO",
- "HZb4hrdUoKCEDf1iB5pp6ohCpzJsv7tZ21JEGqHhpump": "LMR",
- "9se6kma7LeGcQWyRBNcYzyxZPE3r9t9qWZ8SnjnN3jJ7": "LUNA",
- "5DXrzEo4aGgtZRqDxFDcsp95hCakAJKi642gerppump": "SNAKE2025",
- "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W": "LUNC",
- "WPgmcrani3ZybubqiZmMRP4XWGyUkMu8DeBTq8Kpump": "LUV",
- "Gd4qRUCe3J871r5uVuxv8aUUnDbeT27TGaFjWVnhpump": "LSQ",
- "BmXfbamFqrBzrqihr9hbSmEsfQUXMVaqshAjgvZupump": "LUX",
- "3bSGpKYPut6RXDxp41nvb2GM7eR4kEmJExFFHoYkW3w2": "LUX",
- "DHsUQZYRqZ5WNEHZxL5evnAt7A7W19BJ5GxUdJz3NcPh": "USAD",
- "3hFEAFfPBgquhPcuQYJWufENYg9pjMDvgEEsv4jxpump": "LYN",
- "HZG1RVn4zcRM7zEFEVGYPGoPzPAWAj2AAdvQivfmLYNK": "LYNK",
- "8bd3PSBp15xbjjCJzEJDrQDPiBTXgAJtgoxTcmXxytWL": "MMX",
- "M3M3pSFptfpZYnWNUgAbyWzKKgPo5d1eWmX6tbiSF2K": "M3M3",
- "8UiPofjkbjqTqrymz4VY3wXxMcPjFuyq3Psofekymaca": "MACARON",
- "FYK7uK4mobuk7EJ37hhmL7n3C5DRqGvrzFyyo1xkpump": "MDEL",
- "CiYXBwHPrdNkMtxR8YEWKv78K6bQjFoEWhPQrZqEmubi": "AUDM",
- "AnvacL8c4PDLyrQ92bbhfxMYtnckRja3dj6p6Yzepump": "MACRO",
- "madHpjRn6bd8t78Rsy7NuSuNwWa2HU8ByPobZprHbHv": "MAD",
- "Fa7ZE9nCEYnrHsnoeHuhEExJpchtrBtKXnWe6CgHpump": "$MAD",
- "Dy7M5B3Z5GnyhyHKkcHRFpYxw6eyiF1gqsDTBiT4t4oQ": "MIA",
- "8H1qfZSZjmfCeRvh1AdUX5LqXw6Wuem1KCWUf8t4wivu": "MAD",
- "98i1pJRAy4yWbHcjX5mwgBUNsX7XskvYWrBBrXgN8QLU": "MLSTRAT",
- "TrumptpNNBEgVjDc8bnemRTNYZKhdsst9ujNAnTSHqp": "MAGA",
- "D4n99BqHGvdL3ExyvdETV6Y4rWXkf2WwRxhaV1Epump": "ATLAS",
- "8igRQGU3C1dAMrgc5qJWbZr8Bo7zxkucQvq2eFkgZMMW": "MAGADOGE",
- "A6rSPi9JmJgVkW6BatsA6MjFYLseizPM2Fnt92coFjf4": "MAGAIBA",
- "A2ZbCHUEiHgSwFJ9EqgdYrFF255RQpAZP2xEC62fpump": "MAGAL",
- "2Xn4cBcrksaBMMxw8EbwuxY7iG8HUiZx1XEiCXQsGeSo": "MAGAPEPE",
- "2ZRsj42U3Pt5dSfKbizp3HVygCEsLijwYBepKUMqvCxW": "MAGASHIB",
- "6dk9H7RD5m8JtRuUErNztwhBbr5ynzWvzPTusLpxpump": "MVRS",
- "55qMv1HtV8fqRjnFwDb9yDi9tBCeV8xwfgrPKgiJk5DN": "MVP",
- "MEFNBXixkEbait3xn9bkm8WsJzXtVsaJEn4c8Sam21u": "ME",
- "G33s1LiUADEBLzN5jL6ocSXqrT2wsUq9W6nZ8o4k1b4L": "MIM",
- "M1M6sdffCs3ozzhpRveweRCWdZhxth4mvVujPtYEC3h": "MIM",
- "2TK6MgLTmHDhmdh4EtdnBkYKZPkcjMp6cj3gcWhqpump": "MMC",
- "GjYWU3CfPKzURV4B8vGMdpGkNd5PKiwARYizJjeLc3LF": "MUG",
- "8iWsK2WH3AGviQwAnt43zvc8yLy6QMUSuv8PK2A7pump": "MAGNET",
- "3im75zkgSaSwnEBEe4DiCSKUkKGKbWADyGEW4teZEmha": "$🧲6900",
- "HPm64oG8eoCKuPj2MaHc1ruqdZ4Pe71UEGiUET1MtJAu": "MAG",
- "Gi2ce3Eu6dt8iAS2pa8hLsoudSEvew477SVJkHUipump": "MAG",
- "G5e2XonmccmdKc98g3eNQe5oBYGw9m8xdMUvVtcZpump": "MAIAR",
- "HoCunqcWb8b3PtuX8aPvvF3R2nCmfjmTj32zSgSvpump": "MAIN",
- "E4pa6gJTn9DTjmyDRF5rAXGG9YbXFCCUFZFxQCimpump": "MCEN",
- "CNyMaRR4krm1yAxfCvPXevNMArZZZk7sRqKwX68uCeJk": "MAJOR",
- "APXEzWaC12YAejZr1v4sBhTcJMosGSA6oV5aTn9Jpump": "BASED",
- "DdPkpeRXdKLfZkR3iYmbTG41eCRrgjfagw4e4o7kpump": "MAMA",
- "5mfWKJrjVtpZo8EvwbytFWH5X6T8YecxrrYCgskjpump": "MEGA",
- "ACXK4KmfXrf93e3AEo1ZiGDDDpcBpNEnWVxy9BHFpump": "MHGA",
- "87B6mb9KBjaF5NHrB3H33f7grdUHi4oWmMErjhZ5bonk": "MMGA",
- "jkAWzPumRhJE2KyqVy4kB7m9KwXBeSEXnFAGoWtpump": "CLAUDE",
- "2Yb3VToPpKvFuNLqoLeVVvTt4o2dpjdd8TUqaXjDpump": "MPGA",
- "BAmHS42JqR51sZ6oqPhj4pcqi6dFFYDka77P4Q22pump": "MALAKAI",
- "SJWKUQ8hcSjxizfVGmAB9Rb97znrXFHbRiad2J1pump": "MAMA",
- "AG5iXv6pFuQtszqcVzZatTiH3EM5LvUhm6WnP42Gpump": "MAMBO",
- "25hAyBQfoDhfWx9ay6rarbgvWGwDdNqcHsXS3jQ3mTDJ": "MANEKI",
- "147uk4CFxsppdmKZUAakfLvduo4x459HiJ5Ct6MzJory": "MGN",
- "MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac": "MNGO",
- "6cvrZWgEUkr82yKAmxp5cQu7wgYYBPULf16EUBp4pump": "MANIFEST",
- "13TVvChoA7S2qdB7GhP8sDret3aPBetBjvWHtL3Ymeme": "TIME",
- "EWzC9XK43NaEZ7wA3L9vyucKy9BDjzRR9WTrQ78zEgjU": "$MUSA",
- "3srdiFxca22oK1g7qdbGGe9qXy4aS9QGVdTETCBFpump": "MANSION",
- "1xdtu7y3LkkrVCAbm5KGKfYzq1qgKhxxk5AaJBqpump": "MNSRY",
- "JBYXZaWcgdWSGvdYXior1hYyygm3eMYiPdd7KiWcpump": "MANSUKI",
- "Mant1sZcb8x2YMZe7RdqSfStCj4YxjmQByNKyHpLJK9": "M",
- "BsTRFEVZhXbBuy5fhxbttuim8iwzXqMdRCfFftDAkkeu": "MAO",
- "Fh4GcNpEhZJvDDdXhUCe7jxzhqQKZk2NGgDY9zjBbonk": "MAOW",
- "8i9Ak4wieisvyYvk92S3tDGhZLjG3AzRdq4saUSWpump": "MAPPIN",
- "MAPS41MDahZ9QdKXhVa4dWB9RuyfV4XqhyAZ8XcYepb": "MAPS",
- "ETCJUmuhs5aY62xgEVWCZ5JR8KPdeXUaJz3LuC5ondo": "MARAON",
- "XsguBZPkM9BDmxspmWe29EmrYZBv21ENcC27Pqh7grB": "MARAX",
- "7u9kr8ZCHnkeS2n46jVuyq6tUegAtaCUM52AQ1iARKP3": "MARIE",
- "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey": "MNDE",
- "FprQaYuyA4CN1f7UtLd7Vd1NR9vyACBy91cE8tiGpump": "MARIO",
- "HTJjDuxxnxHGoKTiTYLMFQ59gFjSBS3bXiCWJML6bonk": "MCAP",
- "C4j7kPx9PqDnfvxe2uycJQRTAeyGwmU4DyGf21Xgpump": "MD",
- "jDjBkYnLT7ruUziEkwWKYy9hVUjLtfkf7dY3PMarkEt": "MARKET",
- "6QSVGUEyBZWRshnXKhS96NQ97vGWiTu61SyHLAbYpump": "KACY",
- "3CnqgfQmiCyjMgaDfJpBDi9mjsE11vFnTfniM8BTMBzK": "MARS",
- "EqMuraVKeuEUFsDfRJuqNbyibcDNkYCaBMrzZJJNKAQU": "MARS",
- "Cfmo6asAsZFx6GGQvAt4Ajxn8hN6vgWGpaSrjQKRpump": "MARS",
- "2TobP67e8TXkGAqcSQpu9WJPeBnKKZxAnHN518qxbonk": "MARSE",
- "GqXX9MfkURBZ5cFym9HDzqTL7uZkjtCSqLkUSe2xpump": "MARSMI",
- "maru4DtHRrPytGBgRk81qBLby8f72t23u4Xi3EgPPgJ": "MARU",
- "FovBwhoV5KQjZCdhoM6jgXYwXLX3F8vgAfvmLH7ondo": "MRVLON",
- "XsuxRGDzbLjnJ72v74b7p9VY6N66uYgTCyfwwRjVCJA": "MRVLX",
- "GmcjrrHrJ9v2dAYzPYVFBm2CrwLbX2ZvYzJC8Khg9E13": "MARVIN",
- "Gtas1jTXjD4EpYqDFKk7cEaArFSdaUXKu6bGhbSvpump": "RUG",
- "7M3mfsJ4eQAwRt3WwfWUccTPGCRxQauFqBULEDVepump": "MASK",
- "R3ywbVQ5t8LNmjQsn2Ngv43dSqyZscQwNag9G3Eondo": "MTZON",
- "63bpnCja1pGB2HSazkS8FAPAUkYgcXoDwYHfvZZveBot": "$BOT",
- "EsVHcyRxXFJCLMiuYLWhoDygrNe1BJGpYeZ17X7ondo": "MAON",
- "XsApJFV9MAktqnAc6jqzsHVujxkGm9xcSUffaBoYLKC": "MAX",
- "5npn63u1pATvRxevzUsDTzJ9yChVxTKXHBC1KXfStoy": "$MATCHY",
- "MAtesZXcU38mgPuteRFo9ApCauYRRuwn3xf1cs5y7ZX": "MATES",
- "CaGa7pddFXS65Gznqwp42kBhkJQdceoFVT7AQYo8Jr8Q": "MATH",
- "Gz7VkD4MacbEB6yC5XD3HcumEiYx2EtDYYrfikGsvopG": "MATICPO",
- "6gJ8ZmypNAJmE3uQPgM4Xi94H5aYtDLZRoMGFSbw39jQ": "MATRIX",
- "ALQ9KMWjFmxVbew3vMkJj3ypbAKuorSgGst6svCHEe2z": "MDF",
- "E1R4RF89GcKxz62DVfojxDJteLFFs8rtiXcGcrx5HbTj": "MATRIX",
- "DEJqUhPTarcaNqhT7c6fktUszcJWN6skqyWSxXchpJNm": "MATTLE",
- "oraim8c9d1nkfuQk9EzGYEUGxqL3MHQYndRw1huVo5h": "MAX",
- "Ajm9zwikHFeJqKpuDmji7dvyKS4PL1CJDPvLx4Q1pump": "MAXI",
- "HUPfpnsaJtJGpJxAPNX1vXah7BgYiQYt1c2JMgMumvPs": "MPST",
- "H84qihes12nVQarr8rzmw87hDXUbHtFKRm5joBcbpump": "MAXWELL",
- "F5hXpxtsK7UeFC2gsbiTbyhVrUNXN5JG7xkDqpQfpump": "MAXX",
- "32CdQdBUxbCsLy5AUHWmyidfwhgGUr9N573NBUrDpump": "MAXXING",
- "25x9Av7ddPJQFVJy512VzzQ96A2Tqza22LtfHTKCpump": "MAYA",
- "81uWcu3yN3VJmsnXnfEpbTZ5T9EZg9aJCRsnTMER72NE": "MAYHEM",
- "8R47CZYmHbwXMnsVLXzTCnyLyR8iofkN5WxFgmnE3NHT": "MCBROKEN",
- "EUbJjmDt8JA222M91bVLZs211siZ2jzbFArH9N3ondo": "MCDON",
- "XsqE9cRRpzxcGKDXj1BJ7Xmg4GRhZoyY1KpmGSxAWT2": "MCDX",
- "Buoj8HCZMnLRwzDmjzaswhkVhLZD58PG4pZ7rnYp6pCr": "MCDULL",
- "CdmKJqhHEkqTr1BFBdcoBNHQvh2BEqLap6ivt2b2pump": "MCFL",
- "6m1Au79gHDxBztJbne1yhj9QzUT3FMzzz7AK9fw6is5U": "MCP",
- "MEANeD3XDdUmNMsRGjASkSWdC8prLYsoRJ61pPeHctD": "MEAN",
- "mecySk7eSawDNfAXvW3CquhLyxyKaXExFXgUUbEZE1T": "MEA",
- "9MT9TEqxJQcSYjzBhXJzQvQa7rvjPLN7FyamYvZpump": "MECHAZILLA",
- "ETAtLmCmsoiEEKfNrHKJ2kYy3MoABhU6NQvpSfij5tDs": "MEDIA",
- "8H2WoidBArpZGK81KMrTGNqnE8gT2CxdvwUETvUm1Ha3": "MEDI",
- "5RyT8Yf32dbKMLqyKqTwv9zBHRz2cmgXhVCFj3jWpump": "MEDJED",
- "XsDgw22qRLTv5Uwuzn6T63cW69exG41T6gwQhEK22u2": "MDTX",
- "Fosp9yoXQBdx8YqyURZePYzgpCnxp9XsfnQq69DRvvU4": "MEDUSA",
- "8xbMY4atJXBNKR8Kk3u9y5XztXMd56uS8TXY9Gx5RwMJ": "MEDUSA",
- "WppXGfc63fwKSNpK42xVRxxV8dRBtHKRE6YQPhMpump": "MEE",
- "GEdBv2DnES89DvasmZ35TaxP9kBibznYKbacXpoGTEBU": "MPIX",
- "9WAdURmxA9Xr2HwdwkKbAnkv368eTgxMvwnD7XDnzyk8": "MEGUSTA",
- "jimmMDpC9VDEeggKkgNwdMVDNhTqcbQ5sMG8ZoFJ4b4": "JIMMY",
- "FUAfBo2jgks6gB4Z4LfZkqSZgzNucisEHqnNebaRxM1P": "MELANIA",
- "7DGJnYfJrYiP5CKBx6wpbu8F5Ya1swdFoesuCrAKCzZc": "MELON",
- "83iBDw3ZpxqJ3pEzrbttr9fGA57tttehDAxoFyR1moon": "MEMDEX",
- "Bw5K8eZaf361uDLHgX2UUn1PNfC7XtgQVvY9sSappump": "MANA",
- "ChanGGuDHboPswpTmKDfsTVGQL96VHhmvpwrE4UjWssd": "CHAN",
- "BVvywU1wt4FaLDfZe7y11yrVnHbJpAU7YirmsuW3pump": "MOIN",
- "5HV956n7UQT1XdJzv43fHPocest5YAmi9ipsuiJx7zt7": "MEMECOIN",
- "8W4qpyLx74vwBRewa3rVEPPVMnJ8VWMkCTWCTSYPQTDu": "$MEMES",
- "GRFK7sv4KhkMzJ7BXDUBy4PLyZVBeXuW1FeaT6Mnpump": "$RICH",
- "5gcMBTPeogu1d9M6jjxWdHkHSgQyWsxWMBjpnf6bpump": "$MESSA",
- "BPhtSt3fXqL31hhwbX52iuhR9vSjoLFPVcMQCXfCUhXs": "MEMECYCLE",
- "4ep5qigDe3DSSzZjuMKe8HcX4ohacS4H1Lksy122pump": "MEF",
- "AgDNMAi8r2QS1FQEeTHLsZSmkQKCK7xXP2bR7jQ2pump": "WTF",
- "CAY4vG5i4kJNs9i28sjHf2shG96si3r6yusFQxfXFray": "MHIVE",
- "34VWJ7PPwcPpYEqTGJQXo8qaMJYoP8VKuBGHPG3ypump": "MEMELESS",
- "71mfKdePwyWXtiF1mqu2aaCdMKnKuN664z2vEM2Xpump": "LIQUID",
- "HfZiQSCUTpvWa9Mk3FKieQHzZfiduPqTEMVDbP1Gpump": "MM",
- "6CfnWgNKqJWWTTZsU2GswHNNKyXR4VfjygUZ73kh3U1L": "MFUN",
- "598HSJPxc2dwH3V3Gxm6dhBL1te8NzsgA81quqezpump": "MEMEMIND",
- "5EpbKX221NYVidK6A2nJGhtuLPvrPiQ6shknLbtjBAGS": "MEMEPUTER",
- "5aYpWBtJpdiNFMcitxsysdFuxfMK8nRMePvVfkZYbonk": "MEMEROT",
- "8D9foi1nqfabp8D3uNJCrzt1xkvxq8xHYH8Lxb4fbonk": "MEMESAI",
- "Ccgfe34o6auHHBGgtZp2RRcScxxJgbEhQUAzNieE1cX7": "MMIP",
- "6kjzL6NBtwhzdhZJASqHMimfaxNBGqKd2h6JHnnbRuao": "MEMES",
- "8wvLsACsR3owhGzmLLHTgh2waW2vKNtVYWDs9cCopump": "MEMESTOCK",
- "HwVWzgGTL7gUbdawENAaknUnoHZnAyCj94G672dppump": "MTF",
- "EoRe4xECTe9imaYtwfdmrGoinD2S1N5yMeu1LrjQpump": "MWOR",
- "AsjP9VyKUSuLSeycoTb9AqGs3PH6BWAvqDoKmxrWpump": "MEMEXSOL",
- "8Rqc8foPzUZkxRQGuyCTAZS7QKAwncJVvgKXz1AKpump": "MENG",
- "4oz9DZabbYNeB7UGUA4HYZKYRb4Hwm3h2u2x4CrumbAr": "SPICE",
- "qRUZaCpgxaRH1s5V6opjPA6Hnpv5BM37LqkDBw7pump": "MVG",
- "BUhS5coXEt9hcxN3JSpGYUWSKbNo96RsKu52LcMo12rf": "MEOW",
- "dmdrY5iZhmZNGVXsPqAXuAXJ2nP3U8LCfBHA8MGpump": "MEOW",
- "AcJTj14wb9VjVtVrR7E7eoxeK4HayqZ9bPdNvkiEpump": "MEOW",
- "CRQdQmb9TDmG9FFTPEL9gqDvfyF6HxGaHwiq5eybpump": "MSPC",
- "EWwdgGshGngcMpDV34pWZRSu5bkAuiKuKTTHKQ8ondo": "MELION",
- "bn1fb8dwzafGePqNPrM8m8cbAKQiFqeEPuZkPySondo": "MRKON",
- "XsnQnU7AdbRZYe2akqqpibDdXjkieGFfSkbkjX1Sd1X": "MRKX",
- "7X9H2VvwRMJqLBUwZEN9CMptFESdyJ7Fp2SjLyNDpump": "MC",
- "8HxW9Z3YT1gXgQcgEynZaHsEpLXRgijGfMYCkaAypump": "MEC",
- "SUhzKcEZdShM9ifMb7kDKwAdjy6R9MogwG4fWiZtime": "MERT",
- "METADDFL6wWMWEoKTFJwcThTbUmtarRJZjRpzUvkxhr": "META",
- "METAwkXcqyXKy1AtsSgJ8JiUHwGCafnZL38n3vYmeta": "META",
- "FrkF4GNdqKZLuzWXTk1imqMJRGK9uxCRE3PaBKZbpump": "DRIP",
- "7gcoey4EXJcZ8u3iGYhgTBrh3JuhLWzV4Gs1zNaPtu3U": "MEFAI",
- "G8vP2rt8Q16yVD2iJvqRve3mQjE7qA1T1EZCD3htpump": "MKT",
- "3oqcUejEoAjGKcqBRs98XRmB4grsBk2rjjPZS7wEbonk": "METAL",
- "CrFBNi3GHQ8boqivWUTbdwd1a3xwSMfkaxPzkocipump": "METAL",
- "H1nf1F4eoHtiWiSBwLYAhJvAb7CDFY32eYA64mhL8Rp": "MCG",
- "8SQkCjdA7E4xVyF1KTWcYJ727szoZGS9hyuHigLkpump": "MTLR",
- "fDxs5y12E7x7jBwCKBXGqt71uJmCWsAQ3Srkte6ondo": "METAON",
- "METAewgxyPbgwsseH8T16a39CQ5VyVxZi9zXiDPY18m": "MPLX",
- "HCgvbV9Qcf9TVGPGKMGbVEj8WwwVD6HhTt5E2i3qkeN9": "METAV",
- "Xsa62P5mvPszXL1krVUnU5ar38bBSVcWAB6fmPCo5Zu": "METAX",
- "METvsvVRapdj9cFLzq4Tr43xK4tAjQfwX76z3n6mWQL": "MET",
- "7w9gX1WBAYs6KnTd5oZdNNDS887YcBo4yScj66dUpump": "MET",
- "Akzhy1LzbUzXVrmHtoiht1tyRVf73RdtRLFPX6aspump": "METHOD",
- "9bxaVJmUwSc71j8Z2pvUL3UAr1s5fCnwUpvYhqV9jtmw": "MEWING",
- "FyPDfX92B4uEk4zZouy96d1Kk1LgnCznBpzAFSsZpump": "MIA",
- "HSqifUk8nHKcrwVSxt4urYngDAZesaiAxRHTtr9bG8W4": "MICDROP",
- "AywAYdNJnSLSXwKWYxDciPjqGRnwp4iZdQptuuQTpump": "MICHI",
- "5mbK36SZ7J19An8jFochhQS4of8g6BwUjbeCSxBSoWdp": "$MICHI",
- "Ebd7KhyvViXd13ktu9tPnusdvJHojUayeBNT3ZFybonk": "MICROCAP",
- "qi2bq4ACHHk2d77XaNx1xUNC3axcQSCDYcpeZxZpump": "MCG",
- "Fz9edBpaURPPzpKVRR1A8PENYDEgHqwx5D5th28ondo": "MUON",
- "XsQLZycSZ7QnBBdBXQaTbQdiUcbRqjNJgyBGAMzhHav": "MUX",
- "FRmH6iRkMr33DLG6zVLR7EM4LojBFAuq6NtFzG6ondo": "MSFTON",
- "XspzcW1PRtgf6Wj92HCiZdjzKCyFekVD8P5Ueh3dRMX": "MSFTX",
- "FSz4ouiqXpHuGPcpacZfTzbMjScoj5FfzHkiyu2ondo": "MSTRON",
- "XsP7xzNPvEHS1m6qfanPUGjNmdnmsLKEoNAnHjdxxyZ": "MSTRX",
- "J7CSUzsM2VfBUaeaer5aGVVLzzUoizBWF1vQX2NLpump": "MICROWAVED",
- "72Nb8vtM6KPhiidZBscKVzzyUrUckM83B4ChW6Vpump": "MIGHTFLY",
- "2eCVVZ4tomqn4eyuA9Gh5PSKrjNXGwgMhPALGtAkpump": "$MIHARU",
- "55WZGGCwE66xnCxBcAxKSNT49wzeaHhT9jE2xWSXpump": "MIKA",
- "5Jng6jkLKU1o8BNrCzTEMXMFvPjNJZTpdWR3Hq4RHJb6": "SHIKOKU",
- "8CZf9HMSEfDpsjgovrj9xDgikPJ2XRMtGG6L4sLUpump": "MIKKI_OS",
- "6Tk3uHQpLDtd4Qob5fduLjfhXxAasWgvdo8hYeswxMiL": "MIL",
- "Byb8WojwPWthyMm8iwtcd9CQhcZjnjQmhTRi5GN7BAGS": "MILADY.AI",
- "3X8GcLiH2HttjyqePg7MazpMbwbgq5URUMTyDz5tkmdE": "LADYF",
- "43N5UGr3mnfhJFzpBPNM7ZdnobghiYBtHTaQfZQv65mh": "MILEI",
- "2ubuHGFS4VJVxSEpvV3kDwz6JiuXdaAoGMwrwYC87tp8": "MILKBAG",
- "Ax8PSfCXxmxb8C8kYTzN5CPpTe6PyeZfFf8rrXNCjupx": "MM",
- "3tzhVtTYHmqSuzLfne4S8YX6cpyaCCsWXW14XxESpump": "MAD",
- "5nDSCvBxXY7hEsAbpjJr51WaLDDKgmFjNWAc6wD2pump": "MOON",
- "3Rcc6tMyS7ZEa29dxV4g3J5StorS9J1dn98gd42pZTk1": "MIMANY",
- "AXyd5cZqJDYRoN16xcv8s6k41M2kJMfKJnQiXeMd1rCg": "MIND",
- "AJofCoVif3wj2Uy7mpzgxbqDyHPyn7xp6WzJBy7gpump": "MINDLESS",
- "2eTJqpK4QqWofGLSoirWNdC3Goyxp81KC3JDMqcupump": "MINDSHARE",
- "9VYUuSVZGw82Nz8rcSix4x4zurBmvkfiKtyvYCY4pump": "MINDVOID COIN",
- "zgQnq6GEUWuEEa2QvqT69amJtKaj7oU4nKDP4cTpump": "MINDWORMS",
- "27265MRQFxz2LSTnn4mNTmcz1HJsjJVBST1cozxzpump": "MIND",
- "axUxN2q4AWzHaU6LXmjqQh7KEjaXDPKScjmzwEBpump": "GRANDMA",
- "42yzLyxGDjD5RFFQFYNVy7Pzubz6QPCK7HFK52f1pump": "MTARD",
- "9uu3yAY9uAa76pxjAuFe8BPKEQ56CZGJnaxstgW1pump": "MING",
- "JCe4cq9bqL1238wfFjfFQ316PrS2sASKkesLYEyCpump": "MINIDOGE",
- "8J6CexwfJ8CSzn2DgWhzQe1NHd2hK9DKX59FCNNMo2hu": "MINIDOGE",
- "DSXVmrBySfBcmdNDGQkk59hGwXhAKNjEwc4as8nfmysd": "MINIDOGE",
- "2JcXacFwt9mVAwBQ5nZkYwCyXQkRcdsYrDXn6hj22SbP": "MINI",
- "9VucGkAroxyVJzuVadJy2ErhxXxAnPCpyWhong2fSYdw": "MINT",
- "AvoecWraqX969kfXUF5XCCDz59sjRjiDa1KUDyj225t8": "MINT",
- "minty8wwFx6AsYcDHXZXnWG5kcf8VskJHhsJrDeLuCb": "MINTYGIRL",
- "RufNMBEbKJr6CM1t3nwakZ3BaE9csF2AR15s32VWcRE": "MIRA",
- "GBUxQFRXQjSPjkxymAUKPfbUbSpRY8Ui7az1HCxtpump": "MIR",
- "AbVVstroW1r3XZ2t4YbUYyBYyfpuYCr6d2kaYQnXDWhG": "MS",
- "FjTJCCQpLU4fpH58mN1bTQXiQsjJVYai3QYFjYqYpump": "霞",
- "FDEF2U9geiWS7sdGPCUo2r1wGswkJr2mmVTECiH6pump": "IDRAWLINE",
- "4s4H5v4TXpmS4Ss66nxcCLgxrU5nunuwtkQceinZfGuw": "XIN",
- "H53UGEyBrB9easo9ego8yYk7o4Zq1G5cCtkxD3E3hZav": "MXM",
- "CdqUsAfihtKntBsXPrFaovYyr642zKmZmLxzwWQfsoar": "MIXOOR",
- "964ssiZnVnZJrjCDvCbBuwgsozW13gmGtJdPWTAwpump": "MIYA",
- "2jPaomSE2eNsqX9skmeAtRVWSQ3XrV6xBBcDuwzApump": "MIZUFI",
- "9XS6ayT8aCaoH7tDmTgNyEXRLeVpgyHKtZk5xTXpump": "MIZUKI",
- "B1Ycj8Bqv5fjoNZJkzAvNiis4FVwTVeGWvrLd8ABEqT9": "MLMX",
- "6QhZ6WQyYjLGDXFuc9CP1MzzvfeA6rDVnPYUke6ybuff": "MMO",
- "nuumnQ637GtKPis16AeU3PhNru74S7tK9GdjYVATbxL": "NUUM",
- "7NQSHjuEGENZDWfSvPZz7oP2D6c5Jc3LjFC6uh179ufr": "MOAI",
- "2GbE1pq8GiwpHhdGWKUBLXJfBKvKLoNWe1E4KPtbED2M": "MOAI",
- "Cy1GS2FqefgaMbi45UunrUzin1rfEmTUYnomddzBpump": "MOBY",
- "EVDQN4P1YTTD1Y3eLBDBoALWnR4aMBC9y2xUYCrbGbuy": "MOCHICAT",
- "4ky1REfghVawQ6EPZGdx7zss5KNKStwE8swjii3uU5sD": "MOCHI",
- "JxxWsvm9jHt4ah7DT9NuLyVLYZcZLUdPD93PcPQ71Ka": "MOCKJUP",
- "14VP7DvCAdBCc5XGNZkPt6zhtPzJrWWS64Koxtxyondo": "MRNAON",
- "BsoTnJbaYECP5LX4oFuJnNHBxUxoS9usjTC7fSaebonk": "TRADE",
- "2obLASom28dxTDLJxfocejSD5emSzbESWmXuX4Fubonk": "PANDA",
- "8xzoj8mVmXtBQm6d2euJGFPvQ2QsTV5R8cdexi2qpump": "MOE",
- "C6Q5fMpuPjBPox84wbcE3Rn8HYJg11o4YHEmbQSuYs5L": "MOEW",
- "BR4qrJbhGMoGSaF7QtUMvSZRtWhzvMUk5dkgkRrnrn8A": "MOG",
- "GKvFocz56H58xVv2Yh6hHdp3sD5NdQST7NsnMMjC6A8q": "MOG",
- "5oq4zKetRkUMMrFtkWH7r1Q6HZJMsTjgCeU6isgYpump": "MOGGING",
- "HJwToCxFFmtnYGZMQa7rZwHAMG2evdbdXAbbQr1Jpump": "MOJ",
- "Eiy4a5QjY6PsDTcjFnoJTFa3noTCn1xFVXN8BzFNpump": "MOLECULAR",
- "3QPiinFaKeBkv28boLjn9rv1ci6WEd6VXAfmNHz8XEeJ": "MOLECULE",
- "GnkitxfvNLGGsXKGckU2Bw9uEnzwmVmJKzTaHpp1pump": "MOLTIC",
- "DgN9zcmQgWF98qkhoMEshq7G4eRDjxcHoXvijfffBAGS": "TOWN",
- "HYhnRdn7nridbDUUcRsd3JtmvMCyKrVDew52CWGtpump": "CRABS",
- "moLtguTf84g34S34PbnJDRKR1FXb5di1UCRsnB7hKjE": "MOLTID",
- "HndwegC6q7UGn5MErjvdH6BeQzcWQtjZf1nJX6rhpump": "MDEX",
- "CHVggq5Bu2UKLB1MQtLciDV3UKv5hwLkJwA14egApump": "MOMO",
- "G4zwEA9NSd3nMBbEj31MMPq2853Brx2oGsKzex3ebonk": "MOMO",
- "6VHXipL9pSV5MCYuB9tMR4xkwojhc1gQ51ku2GR7pump": "MOMO",
- "9JbxQSKNukRA7cPZxCfhSNEcAP9iKRo3PSyYNbW4pump": "MOMO",
- "HcQbgvMTCNDgMDY6GAFzP1WwCNZeMoEwZfUuHepzC9L5": "MTOS",
- "3zomtMhRRsBpLZeJLS86fgueXE7xAhoN8dnymNh8pump": "MOMO-CHAN",
- "DycqsssTijnk7AzAyPj5nJuLHW42PXd2NDEJGW77pump": "MOMO",
- "766whddpsQHS8wy7viUfmuGPrMri1kgGMFwfZMdepump": "MONA",
- "MoNAoCoXKLb38Y2VpbukGacdNYhvRTyVn92DvRApXep": "MONA",
- "Bt9tUAuuoJTihrLvgK1kWErBJduaGEeQbF2VhAPHtYm4": "MONA",
- "3Wp5z1GtPqKwyiaicXa7nyXhBVJJ5JgAwzWXuPXqpump": "MONDO",
- "4bvgPRkTMnqRuHxFpCJQ4YpQj6i7cJkYehMjM2qNpump": "MGO",
- "2MpjiarUbQnJaWbnypSaeoA3ks58Qv4YamXjtKBxbonk": "MONEY",
- "Gh5uaxSHkdvRpmuYrZDkXEeNCYcWKdkVDsWYjx5ae9Am": "MZC",
- "FsBPYiGZ4bhUxVSPP7XPJYfTPm5PsLJc2WGZaFaDpump": "MONGY",
- "G8dUSvywefr4GvfFZBZiLHmbjnwjrrJPAnVifjj7pump": "MONITOR",
- "9EQSeWY7pDB7MYoSFr8QJ19onGS1ehDmLbSGT2b3pump": "MONKE",
- "hxcxN81ma8m5PMzPuCyysaMJ9wqJenBr811DbX4moon": "MONKEPHONE",
- "92d5AncUVELq79xqLWNQ5Zoxz7fn9XHwijYswYWFrKtR": "MONKEY",
- "921MoB1U7VprQfWw5D37a38LCBgB3nareT7rNffk66BG": "MONKEY",
- "6cnDfXAG9EsGn5BB1QF3i6Xx1SNJ88Qcc1nckJp6pump": "MONKEYAI",
- "Fm9rHUTF5v3hwMLbStjZXqNBBoZyGriQaFM6sTFz3K8A": "MBS",
- "HyLXondhNhGkvWPXr8z4EPSgZNRRs4j8BHdyqMdVpump": "MOLT",
- "5jPAVBTrCVWNy2Lh9wtyV6y6XMvD4UAgADjEnMp8BAGS": "LEAF",
- "FYa25XnBsXQXAdTnsyKBKd5gZ1VZhChBRF57CqfRxJZX": "MONK",
- "mpoxP5wyoR3eRW8L9bZjGPFtCsmX8WcqU5BHxFW1xkn": "POX",
- "8HWCntWrLE4GJ6iK5cwvbhvuQSoRCiu3QB5jHyqLpump": "PEDRO",
- "7TSCoke2mSZzAtyuRmzANf9virrnyv4xSUeaxUrKkLqw": "MONKEYS",
- "E3SPN9aQjT6yeCsQou5wKb5iaG68CbUE8ZnBaFBpump": "MSI",
- "AMgMqadZ7Qpe9PCQwehAG3Xbg5cf8JxCxH7sGCSupump": "JORGIE",
- "CNNQZyEWfz9mDBRCiRNwjaUvMaLnaRWem8HeJYh7bonk": "MONKEY",
- "XsyusqQvb8RDULsY9szwvUv2CxrDKa642w7kecZPdRM": "MNSTX",
- "FuLH3f9TPxiLNojPBZxfaT5Rb5VFfia8hMzLo9e9c6CG": "MOOCAT",
- "8eKeugXxvTgowqQZWfxuWJJjKKYe9vcZ92GBu94spump": "MOOCH",
- "ED5nyyWEzpPPiWimP8vYm7sD7TD3LAt3Q3gRTWHzPJBY": "MOODENG",
- "He8S8wC7KQUH7qGWAaLRNFpjqrVyQBwUud34Eyj82AZo": "MOOMOO",
- "JJ4QpqUYzs9LUPrF6uJKQbkA4ofSnvkwQ3RBcVLFSjd": "MOO",
- "3ZvUPAegNgfWnTRfAhhkZkn4jn3XERxvSW3uQetmpump": "MOON",
- "aDJLHm1KxsHmnoYJY8VDyWvbGykBNhWJqNgPX7Ppump": "MOONA",
- "Fdxex2V4Ldun1aFhPsuGKfzPrrE1ay4UM8xt92EaL5N4": "APP",
- "B9jYrBoCPN7FcXVHe56KXsYgJE5gbTxsadjvyFiVpump": "BAG",
- "7AyQmiveQGm4NUbg65hqDzbde6q9E1b2mNtuakz4pump": "MOONBALL",
- "4zLQNkPEAn4oSVtFCeaJ7cZkZAuD9ysHbMRVm4typump": "MOOBA",
- "G7vQWurMkMMm2dU3iZpXYFTHT9Biio4F4gZCrwFpKNwG": "BIRB",
- "FNP2Dw2GU5wPBZgVCcerbEemV9dVfvQrThEor1jmoon": "MOONCAT",
- "D2QvT2fgdvaLxDLiTFjHeRqeZFXU8UqFdJr7xcgHmoon": "MOONCOIN",
- "8vVHBmASTSFAYEFNQg3qxQQJQ5vBoAVRWYsdgEahpump": "MOON",
- "86N5k7YfzPvdgRZ1ASE3fhKniAwc6GwaZwXes7ssmoon": "MOONDOGE",
- "yM3AbxK4B4iTLddjGGW7JeQaVLzMiF5y81vK83fowTn": "MOONKIZE",
- "AMdnw9H5DFtQwZowVFr4kUgSXJzLokKSinvgGiUoLSps": "MOLA",
- "7ybKUMNTuK9it2mFd7y5P4RMk7dUU3EqSffRm24Vpump": "MM",
- "99YFbXS6iA7s1qkRDTMBXEywtLNmrRtHtGKvNxpKWcdT": "MOON",
- "8x41eXaZhA86vHnyovggfvTGZYA9twmXG1BMLhyVpump": "MOONMOON",
- "Ai3eKAWjzKMV8wRwd41nVP83yqfbAVJykhvJVPxspump": "MOONPIG",
- "8PVFdKx7fX1FmmoASfTu5CUPEWuD1WY73Z24UTgCpump": "MPUP",
- "moon3CP11XLvrAxUPBnPtueDEJvmjqAyZwPuq7wBC1y": "MROCKS",
- "5HsZR8eG7QpQcN8Mnp8oFdENRkJMP9ZkcKhPSCKTJSWh": "MRC",
- "FHHeb1ji8Qm5Nq68S8zPV9HCPbE7YBdBmV7fgqYRpump": "MOON",
- "BqhNdGtS1Nqtzi2MvZ7G8NN1vRuHZ12UpHGJKe71e1JT": "TRUMP",
- "BD78uBLz87HSw77mSt3zCTkxpFgBE2HJuaM8c4Es1ray": "MOONUT",
- "EBjCSRYrGJzQtqgyddaH95LWU3sw8YMjK8CgwNoWpump": "MOONVEMBER",
- "moon18sDJGhymHnyEMHWPdqjmSykNhFP77LxPZoueTt": "$MVB",
- "moonThZEkkTVoNB7v6YVCQiT56JYDZ1oN185ba3WizL": "MF",
- "EqKmC2f6fQsE5WVzXKkExrnfBabohHvSrkf5xxjwpump": "MOONWHALE",
- "7Em2S9HUxrMm7mDA84j3Kg8N86s35AzhrotHQcUwpump": "MOONY",
- "6P4yBuWs6XnFf9hwyDsHVoqP4PnKtzKkcLhm4YFTyvWz": "MOOSE",
- "HN2n82rahixyTQ6LarLjSVRR7YX7GZTmmRL39Vvdpump": "ENERGY",
- "8ZHE4ow1a2jjxuoMfyExuNamQNALv5ekZhsBn5nMDf5e": "MORI",
- "ATo5zfoTpUSa2PqNCn54uGD5UDCBtc5QT2Svqm283XcH": "MORK",
- "34HDZNbUkTyTrgYKy2ox43yp2f8PJ5hoM7xsrfNApump": "ROUTINE",
- "ACu1RKQWdXAyoXvKzfSDsFKCqGfyBxngXq8YnmBPGomj": "MORPH",
- "4FysfnLNVkjKTkEZbPkbvrfBdHQhXfMbCLDsFRK5pump": "MORP",
- "HqqnXZ8S76rY3GnXgHR9LpbLEKNfxCZASWydNHydpump": "MORRIS",
- "FfoqzbWHM2U3cuTWtJvPBfVSyYHFsaUVyLHriVBHwYN": "MORTGAGE",
- "FskzSqy7Pi1f3nWorr4WhhQboxzyv8fv6Q2e8xyDpump": "MORUD",
- "7U7FZaLfJTt2pN9Canp1Njt3vbz6eiqHbxn2bpmEwtYB": "MOSHI",
- "9bNUjxEvygayUE2ZRN5zh9Hhjh6cN6GPK4zoHzXXpump": "MOSS",
- "7cyAGa4XsNDnSgnFuwmVFgp9JGqZoZYkiVyFPSke9CuP": "MEME",
- "EfRr6xyFYAwVLSV2sYt68gXwPFfUYayGpEyRoSLGRS5L": "MØTH",
- "C2MvcWD86peRanQAnJfiDPurs7e7CkMsnP1bHBNJvBpA": "MOTH",
- "3S8qX1MsMqRbiwKg2cQyx7nis1oHMgaCuc9c4VfvVdPN": "MOTHER",
- "FFVcrc7wxCQ2HsxY6jhKNPwWUeKJsL472K28Vw16pump": "MOTION",
- "5qvPyRS7j1cBYgFuK1umYjqGCdP9qLwfYjHBCHwLbonk": "MOTION",
- "7PagSBusvxQ252fuBFnhipMZwd4T4jGikLeuwrDibonk": "MOTION",
- "Uiupt55owCqBJdunYQxyYf48KRMU4F53xQAyf31dpzx": "MOTION",
- "uPXPhEXb8cP1jkd1xrrbxJSMt47TSEEKRvu7jS4pump": "MOVEMENT",
- "BVSv98vyMEkjwCd4ZSBcPUB8MjDPqQfVHTrbCGtYpump": "MOVICH",
- "XwFm5GiKPVTvPiEbQpdc6vJbFEpsUXRMf6TcSxnondo": "MPON",
- "pv5TUu7tVbV9NgqBrfbEfQ2bTCULuNXdbP4kgHrpump": "MPOOL",
- "39Mzpdw7NDGiXmZZGWiCdR6Nzoc7muWuYkPsVDV4pump": "MEME",
- "GzxpqHdQeseerHTM2Gikq5F4o8Bb1oTENRTJa8E2pump": "GIVE",
- "3MoLRueScRN3kHKbqwZnyjtPGoG5uVgKhAwMEVNjpump": "PUMPT",
- "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So": "MSOL",
- "8x9c5qa4nvakKo5wHPbPa5xvTVMKmS26w4DRpCQLCLk3": "PAINT",
- "3T5gKSRQy6ZbUJwGEhDL6yg73nTaLVax6TagkcTDpump": "MUBARAK",
- "Fnm6Jf4BtRHSjMcUt7jYk5cJksQhzuwhtgg94kG5XB59": "DNA",
- "J6F9W8CLa1afkCdbxDSAyMeXo9Vsfvprv9QzHYMS5HgP": "MULN",
- "6gvWSka7SnJDn4mqV7Ydn4q7AyVNSo2aX4TNGjBg7Cct": "MUMMAT",
- "5LafQUrVco6o7KMz42eqVEJ9LW31StPyGjeeu5sKoMtA": "MUMU",
- "8ovs151K45m77kWeDUYaRuNyKebpiNfwr7SrgFShpump": "MUNTZE",
- "FtPqJ2YTKmPyBxp3Npg18RE9Z77SQu9jrkRVYLzpump": "MURAD",
- "2YDMeite4gKusVQGAXvQPnbEXwkLKm2pUz8CTqHBpump": "MOM",
- "CQ4PZEmJkR8Zchhfp21fkoCAJuZiv2dhA4QfKqupump": "MUSH",
- "5Jr9hGmJgxBRjjF8XGcGgQzXUdsbpZNNMpigEv8Wpump": "MUSHU",
- "9So52ugZh2BLBT3f7p61947q91uQh2DyvbfyMDeRpump": "MUSKIT",
- "22Xeo6diWfJrScaoVFzgkwzrCByPukK45fdwkJyrpump": "MUSTARD",
- "AMp6nNmvohjGYEnfDZ635nykM1msQTRAhmquUnHBpump": "MUTE",
- "C1kzNkFfgdtP8VF1pFYA4S32RLPqk5KPaurCaQJwxfWb": "MUZKI",
- "ASNoTS4cYopuUbmDMWM4AU9xdCQnb5zPe3gBWfTUsLTE": "DEV",
- "A7qn22uQNpUHWmSk5GY5N4vmVJ4uPUzGySegdkm1pump": "LINK",
- "8Up6R3g6qdpsApu8DUCtajSAWANxSty2eQmSjCSGSHH6": "MLC",
- "5KCGJJpRMtbydUDTAoc5MoRPnqmJNNDaFwvBDdSG6daC": "HIGHER",
- "H1aN3vcvB68eaFPbMkoAss3vnfi4AhP5C2dpnrZzdBc7": "MYRA",
- "HhJpBhRRn4g56VsyLuT8DL5Bv31HkXqsrahTTUCZeZg4": "$MYRO",
- "mysticrSzUfD2pz4RayXF5oEHGfNNAFsSY3z5hTQZSN": "MYSTIC",
- "dgU3DSSTFyHx4j5MKx94V3BB6jMse7EQpGDi6zUuULt": "MYST",
- "5UP2iL9DefXC3yovX9b4XG2EiCnyxuVo3S2F6ik5pump": "MYTH",
- "HB99pDdRG7mBpzWXkmvDJF3XCaDQ5HBEow5zAj6RadF6": "MTK",
- "HBRPNwdcT67cadiBS8VNP4mRt8ornngLF34TZXthrust": "N3ON",
- "NAE5Rik3FrGoXoqoqW8boyCLrgEDnEKHNfPAVNNdQJr": "NAEST",
- "mkvXiNBpa8uiSApe5BrhWVJaT87pJFTZxRy7zFapump": "NAILONG",
- "Fxm6tJ2khHbLVcSgnYUqg9FiBduVRLEvdQR67dvQ3eGp": "NAI",
- "CKVZPWFPaJArEaPnk16CXpFtFXjuCxCh95vBcS3Ppump": "CRABFURIE",
- "H9muD33usLGYv1tHvxCVpFwwVSn27x67tBQYH1ANbonk": "$JIM",
- "BWJ7zJauzatao4FsBnGdVsqdBi3k5NbgSY62noZApump": "NANA",
- "HxRELUQfvvjToVbacjr9YECdfQMUqGgPYB68jVDYxkbr": "NANA",
- "EVqkPanBKrx6q2cuej5CwjdEoK8CM2UPdYi9nmSPbonk": "NANI",
- "BVFGj2ww3sz1Mc2MgFQqkDfjmLVmTQD7MU6NVvS6pump": "NANI",
- "B3eYHYLwitHsPd5d5URKUYxwjwsugdmp34EgPEHrpump": "NANOBANANA",
- "sctmTAsDn4tLUcemqoqYijfuRkiEfAMPi84PNq2EueR": "NXSOL",
- "FYFq8aYYpRgwH6x9Ez4M1xEnv6aWpMrtdhYRUhbJyo43": "NDAO",
- "Xs8S1uUs1zvS2p7iwtsG3b6fkhpvmwz4GYU3gWAmWHZ": "QQQX",
- "yCYSJATPJiFgtE1Up7LFGQEV8XLZ5Ma7Y53JnXKpump": "NDAS",
- "FRySi8LPkuByB7VPSCCggxpewFUeeJiwEGRKKuhwpKcX": "NATIX",
- "7wM4MnbsPsG95A3WhZgbrPWvMtydKmJjqKr2ZVJVpump": "NAVAL",
- "GYTd9XbZTfwicCV28LGkwiDF4DgpXTTAi2UeCajfpump": "NAV",
- "5qmykKi3zkM1sGvcMNgj4bqy68qvpLqR9fQWWrtfpump": "NAZAREAI",
- "3bV6a2fBT9EzWBbXiphnLMmmAEQ1faYwppCY2Fnhpump": "TROLLBOY",
- "6CcbeMGmV11Rh6wFC2LE5ALEjBUUBCiHfQY2zw7CFQRK": "NBMLUM",
- "DiRshqNDE68bWbGdLHm1GwQ76MvWQG3af6w1NdQondo": "NBISON",
- "Hog8azPhaoZeXhcBF8DZ3TZAq8AXcX885ZBX3zhP76fq": "NEEDL",
- "Ce2gx9KGXJ6C9Mp5b5x1sn9Mg87JwEbrQby4Zqo3pump": "NEET",
- "CTJf74cTo3cw8acFP1YXF3QpsQUUBGBjh2k2e8xsZ6UL": "NEIRO",
- "CTg3ZgYx79zrE1MteDVkmkcGniiFrK1hJ6yiabropump": "NEIRO",
- "BJ2ENyjuBGUQJr6CCDBcGAQNQDbayoNbDziDGrWSQQ4": "NEIROH",
- "GLEmV9TBLJBK5orHQLgU7x4a2nEzopy25jR7iHk5pump": "NEKOMATA",
- "5hUL8iHMXcUj9AS7yBErJmmTXyRvbdwwUqbtB2udjups": "NEMA",
- "GiN6u4pYqQB1tUNCTxN8n8aM1N2hDmtqaKWCSiAv1uLW": "NEMO",
- "NeonTjSjsuo3rexg9o6vHuMXw62f9V7zvmu8M8Zut44": "NEON",
- "53kC8TJ5gfBPBPN4afNA1k433vL7ZhNHaw9NGh3HBo9N": "NEKO",
- "FJz7ptUR1FwxSHbb8Sfd5Cn6Zt4TqucJZKLqU4n66gdq": "MAY",
- "bj7xHohoXetk461iGPSAoDS62yiJsmxgV82RkA9moon": "NERDY",
- "5HTp1ebDeBcuRaP4J6cG3r4AffbP4dtcrsS7YYT7pump": "NEROBOSS",
- "AFoiQ3Go8PTe7sGy36GsQbMVMcFqJMSCFuiqoDuzpump": "NESHUDO",
- "7nFYpHyhDgzg3ioU2JFko5kaVwm6bjkL4MtbUiVAiYbJ": "NET",
- "YeK2TdPtGLAme3Phg4pb1GBN2YxKgX5UNVyD4asondo": "NTESON",
- "g4KnPrxPLeeKkwvDmZFMtYQPM64eHeShbD55vK6ondo": "NFLXON",
- "XsEH7wWfJJu2ZT3UCFeVfALnVA6CP5ur7Ee11KmzVpL": "NFLXX",
- "DH7HuYR54FNp49isrus6AdqREuQfWYV6qaVPg8xVnZQ9": "NED",
- "B45FhPi6d7UR66TGLpQ3EPnWhGfzdGVkCKNp9neR5Cxt": "CITIES",
- "Dc2mot4v1rZn6r9taoc2Mmqi3LM1h8eUbHtkQ1Xupump": "NETWORK",
- "82Rc22mnyHrmBGwj15rhYhFzVrU3bgFkjNtV3iHjpump": "NCAT",
- "BNC5eVJZixJFykygncDuUK5TpRBsWZuT6eSA99YNh2cZ": "NEURAL",
- "FrQNn7xSTQWdv3SC8stZfT76QeWgvFWVQtCJhdGVjHJK": "NEI",
- "GFSeaid3PrKr3agHd9dQt3qFEG4Rxosr7U8aLSsEpump": "NMF",
- "CyQr3CGBDd4gTncX4qSRMB4wQqQyRLY5iDgKHjhXpump": "VISION",
- "3N2ETvNpPNAxhcaXgkhKoY1yDnQfs41Wnxsx5qNJpump": "NEUR",
- "Guko5GPz4g6E2cjDHukGtdnDNJeQQvpEW9SCgRZcpump": "NEURVONA",
- "Gka1TQEevBbVw4W9K15ER96ZzKByMTb6TBMQzWFEpump": "MINER",
- "6T7xYGQxtSRjKFpJHvX1ondUnULLLyx8iKsGmM7Xbonk": "NPAY",
- "CxrhHSqyW8YTDWc4csJMMgo7uBUJSXzNzrWhtw9ULdru": "NEVER",
- "EiKZAWphC65hFKz9kygWgKGcRZUGgdMmH2zSPtbGpump": "REMUS",
- "AXTCLqqupJN3YWikgDtAZxRKWizsbePDyV9XtkDtpump": "KIRBY",
- "U237C8hKyZYL42TEtTv6JGtdwDr3pZaQeeWMCVVpump": "HAGGIS",
- "97WQm8aUu2gprFzEYfGmdJ7wcF4NSDPgvn3hvbDHpump": "LAKKHI",
- "HHcsLmPyZoVpHP6pVNyBf2vzxpeMkxgaZw9NJZyWpump": "GNOCCHI",
- "7DRmRvxK9G6a5uMyFdfa7UaQC6dRAZz1dgioy9Htpump": "NEWERA",
- "AVKLphLUpoNCwiyUHt8PuK4vz6JFkhRFni7HwZKrpump": "NEW",
- "Dig28Tf1ufhCBAsjTmFkXCgcNgMqDMYj5A2rDQmondo": "NEMON",
- "FY7EieWUE7ifbQoABC73w6bxjuRtc53PdJAnojQ3pump": "LORIA",
- "2Ar2n5DJSiQuMhY4XeSzg7C5AGMezZPoLUt98VmmjsAR": "STATE",
- "38PgzpJYu2HkiYvV8qePFakB8tuobPdGm2FFEn7Dpump": "GORK",
- "5AmQVkVnELiBV2cLrSWfBePmGj85vLXCG5vkMeETpump": "NEXA",
- "9JErKCoJX7nmMsYvicoZfEdTdW1qiF9oeocHWyKLmoon": "NEXGENT",
- "t7eN6cGwRMFaZvsNW2SmVwkedmHtDdrxA4ycNE5ondo": "NEEON",
- "2Zaq3WyDJj2ZkMcuqUiTBfAXCjqZtqihxcwUdwv9dyHA": "PEPE",
- "8xTDsy1UFBYK1J37igAdwRDRqvgCEUJYe1QggFNApump": "NCRS",
- "88dnPHaZDxwCm9xiDgB15uPwGdgE2y7ALcqsgRTopump": "NXR",
- "4SLbbckLuMiUPFBT6FrqKtHd1j97ePmG3HDJUd24wBLV": "NEXUS",
- "NFGgKCroEe2EucBJmFfCUNmU41MHv9Sc8qUhbceNTvy": "NFGX",
- "NGMiXUJbCVaa3cYggper7fZudvG6MFk6DwsnrULy65Q": "NGMI",
- "CJBSwuppGWjBQfCueziH1czsyQp7DuW2wwYedC31bonk": "NIA",
- "3gC8oidaJ61fkB2QCYvm9xKMZG8szBgBMbuLAGgNeGJD": "NIBBLES",
- "7fj85y28pKMndm4So66Szkb5GMGfLHFEkwsZdDx2pump": "NICE",
- "BEamfAJycLnX3ij9mR22T71XWdruM1uQik8TyL3Mpump": "BABY",
- "5zy77ie2LVoLaMDy2h4SAvPCo3uc8Zno85YGZDZjpump": "NICK",
- "BfFU13dyBbYT5E4dZdeFHe5YeH6p9DdTh8fheThspump": "DOG",
- "8Jx8AAHj86wbQgUTjGuj6GTTL5Ps3cqxKRTvpaJApump": "PENGUIN",
- "3boRKAxWR6weV6kufr9ykdLcm9cL5q2p469tCqeCAnHy": "NIGI",
- "9xK2Cj2tKq1jzyjr6BtdqHxe2niTtshxF4Y7PTHMpump": "PENGUIN",
- "g646pcdG2Rt5DH9WZzL7VVnVDWCCMTTrnktwE74ondo": "NKEON",
- "d8ed1gwSmD45qwEK5wZGMb1Kh1MQ9PXipKsHevtpump": "NIKY",
- "FgX1WD9WzMU3yLwXaFSarPfkgzjLb2DZCqmkx9ExpuvJ": "NINJA",
- "G7iK3prSzAA4vzcJWvsLUEsdCqzR7PnMzJV61vSdFSNW": "NST",
- "DFrJxDoLMYt6bNYeNe8Wrjzj2UPUSLZLEMMYBLuTKcTk": "$NINJA",
- "yQ37dFiGAbzrb2FRAEhGNzRy5zFfoYGWYhAepFEondo": "NIOON",
- "5DkzT65YJvCsZcot9L6qwkJnsBCPmKHjJz3QU7t7QeRW": "ANA",
- "9DZvu8yahirm6NagRa7Cm484VbUwZYKRm3xvpMrbpump": "PUFF",
- "ESVRQ6phc55VCw7sWB6JgW3PeTB6N68kvwjfsMPcpump": "OMOCHI",
- "AYABiqKuTh9Va5Aqc6AujFevHwDGmECGQiFmKW5g3K4Z": "LONG",
- "C29ebrgYjYoJPMGPnPSGY1q3mMGk4iDSqnQeQQA7moon": "NOBODY",
- "B61SyRxF2b8JwSLZHgEUF6rtn6NUikkrK1EMEgP6nhXW": "NOC",
- "2kQXaTMyf6tojju9bx5Hq24ahdAHBu1E9dkfkxSfpump": "GHOST",
- "B89Hd5Juz7JP2dxCZXFJWk4tMTcbw7feDhuWGb3kq5qE": "NC",
- "EumKiGHzr894F731MV3heFQygNQ5qrYVBtvfQ483node": "NSAI",
- "8zbUbQSt1QvGAPr7r2SQ2mH3SzYDkbGddQrKPiDbpump": "NODIE",
- "7rnxiXfV4kajobuZ2qBHjVPBhhcT82TPdzF3cPfHpump": "NOFACE",
- "FTggXu7nYowpXjScSw7BZjtZDXywLNjK88CGhydDGgMS": "REX",
- "9sgZAUEyUsifAjrzsD74cCeV3dMzdeEswAJAHxoWpump": "NOMDOG",
- "6ZrYhkwvoYE4QqzpdzJ7htEHwT2u2546EkTNJ7qepump": "NOMNOM",
- "NomuBwKJEvJ8d4dsaq7NZoHaXWXzKcfke1c7Y8ruFYL": "NOMU",
- "8ATm1hGfhkMhm38DREUQPiWU8mhFzAupqkNv7nhmJVNF": "NON",
- "CuEPELFSwRcs4nQ4Dn6a7RVz9ZRVoa1rBapcqG6ppump": "N0NOS",
- "BeGY8KqKxboEwRbJd1q9H2K829jS4Rc5dEyNMYXCbV5p": "NPC",
- "6nGnXdsabPPJ88CsrigJUA7QY6Ag4PbRZkRJqEKypump": "NOOB",
- "7cEgQdp8JTXvBrpjSzji7bLEeCHWENRwX62B2Ep97k5H": "NOODLE",
- "4E3CrfKrPWmnE2kFrdeRKyiovpUWpUXHtqXpXzZZsxZ2": "NOOOO",
- "5Vt84ukEKHuxYA7wjH3PDwCzTGumPS7MDNGX4cFLpump": "NOORUNG",
- "3Yie9s6iuEmk8aiXYC19xaq2iccTuFzyfKBWv6gFpump": "NORA",
- "9M26M7CxkJdaewdiH8v5kSiiXKbWBBirTE1QmXHmDvVg": "NORM",
- "FrSFwE2BxWADEyUWFXDMAeomzuB4r83ZvzdG9sevpump": "NORMIE",
- "Dm6FpQ76SsbVmAZ4NvD2mjZP7cxbw1CASr4WwCiondo": "NOCON",
- "BwcamVymEARNdx2chNraY9CpJgKHUQk9Uj7m51tLpump": "NORUGGIES",
- "nosXBVoaCTtYdLvKY6Csb4AC8JCdQKKAaWYtx2ZMoo7": "NOS",
- "4Bf3MmVBm94pMcXmnUfWrG95AApZHuEbGoztdGAxpump": "NOSE",
- "GZcVdxXSenrKgnkAKCj9Yp7ConTB4poGfBohFVpupump": "NOSEY",
- "F2HE9krU9HkpnYvv9LKom3hB3Nvm8uZaThrmiE22Zdpy": "NSTR",
- "E4x2n6RLMPTjw3vqkCxZkEgiQXhDEHHByvwUWttL1uuD": "NOSTRA",
- "B2GzD514ByBioqDY2XoZZW23mVXA5686wPotvWi41GF9": "NASTY",
- "Et1nwX1U2PrS1A4iRvFcd6LGzYWh1C33iHvKWBCVpump": "NOTBTC",
- "6gh8b2mqUrVb6Ew8Mwt89tNyN9keCDNstzT5cdp5pump": "VOID",
- "FD6vGnA4iewV1B6TVo7e6MApusSreE2sBY3LWj5Bbonk": "NOTHING",
- "iNKezFtQnxqjX8JMrez3pT6VaV8VwhA1SZXTbbzpump": "NEES",
- "7nePAcJhg88s1KFJptgaBvzYgHaUDzddgU65Etvtpump": "NIRE",
- "NotMMjBCRGKg1eTZMhiYFbfGJNLj2ZHt6k4fZqchA35": "NOTMEME",
- "NoVpnNV3Mj6ozo6SF2E2DAGkQZ1DmBcsKuSL1xz5a69": "NOV",
- "AfLh3wndb2yHQWJZFSjyncvRDDyU8DQPcGbY1eiABdev": "NOVA",
- "GtMtXoJiqSf8Gfp83cuunnDTiJTeTmv7cniVtJ6UAMWH": "NVX",
- "BDrL8huis6S5tpmozaAaT5zhE5A7ZBAB2jMMvpKEeF8A": "NOVA",
- "STKmfGGegeoYqrHrJ3nvTafSvRC6GJJBbLwN1cqpump": "NOVA",
- "3SkFJRqMPTKZLqKK1MmY2mvAm711FGAtJ9ZbL6r1coin": "NVAI",
- "AUDDttiEpCydTm7joUMbYddm72jAWXZnCpPZtDoxqBSw": "AUDD",
- "GeV7S8vjP8qdYZpdGv2Xi6e7MUMCk8NAAp2z7g5ondo": "NVOON",
- "XsfAzPzYrYjd4Dpa9BU3cusBsvWfVB9gBcyGC87S57n": "NVOX",
- "Eq39Q9bwTx1YHY5pkHLVeahVA6JYZmmMJ71rPjQek3Hb": "NPC",
- "GdKWebBBvM78HNYGxoZLgsXHqZKAELEZk3ka9i32pump": "NPC",
- "5ToDNkiBAK6k697RRyngTburU7yZNFZFx7jzsD1Uc7pK": "NPCS",
- "xNPCScK5Hs9ywamnLNsDcxGG9bP3CKaGjcP8xE5KGNy": "XNPCS",
- "GXUisEapYfHJe8oFoWSPPyiLSLYT6Em9iEeXTFxUHyUA": "NSDQ",
- "vQQ3Z2j8Rz4bupwENK9rhGkpgy3Bj6LdUTPz9J2pump": "NUF",
- "HkVRqeohQAGa7oZMrGPs6bFUf6aAmFdQfCAmtN3PXt9s": "NUFR",
- "2eXamy7t3kvKhfV6aJ6Uwe3eh8cuREFcTKs1mFKZpump": "NUIT",
- "HthQKKW6M9Q8pb27r9xoqjfviiJ3kzdojP8TKqjJpump": "NULLA",
- "D2jtkGU93qikXr2dpftsStLs3EXEZy62ww4VQpM7pump": "NULL",
- "AD6StJzK8sFJWUetQdsnfHWrmmEs1dtSYuuZLrYkQUy8": "NULL",
- "B7tP6jNAcSmnvcuKsTFdvTAJHMkEQaXse8TMxoq2pump": "NULL",
- "48eKhwwadm7LJ57msuDYdq36CXx23Ratdbu74Pa1NULL": "NULL",
- "9JK2U7aEkp3tWaFNuaJowWRgNys5DVaKGxWk73VT5ray": "NUMMUS",
- "HeJUFDxfJSzYFUuHLxkMqCgytU31G6mjP4wKviwqpump": "GNON",
- "q29umWshmh2fmm1CdRb4cBKhqtW9xX25ezNQi7Bpump": "NUNU",
- "7HHCwGd7UAPF3gtHExBREYgY37cbyYcCaeyAHKUc7mUn": "NCASH",
- "BoyGMfttsVUYK3n6WrSeWEeqT94ExcTmgJsYEkJVpump": "NUT",
- "3KkQ3AaMs2nZoKvYzGnh5bwRocAGFFFzDWUR4hLT7JpF": "NUT",
- "gEGtLTPNQ7jcg25zTetkbmF7teoDLcrfTnQfmn2ondo": "NVDAON",
- "ALTP6gug9wv5mFtx2tSU1YYZ1NrEc2chDdMPoJA8f8pu": "NVDAR",
- "Xsc9qvGR1efVDFGLrVsmkzv3qi45LTBjeUKSPmx9qEh": "NVDAX",
- "NX8DuAWprqWAYDvpkkuhKnPfGRXQQhgiw85pCkgvFYk": "NX8",
- "BAsnXPVYuvZDfEFR7tmu9sG9gPyHy58Jpjs2AuUw1FLx": "NX",
- "NYANpAp9Cr7YarBNrby7Xx4xU6No6JKTBuohNA3yscP": "NYAN",
- "CMx7yon2cLzHcXqgHsKJhuU3MmME6noWLQk2rAycBAGS": "NYAN",
- "Ho5fkxk9uqUuVN5kt7TUFacduWCpKPAuYkM9HD3KAXA2": "NYC",
- "7NgzCgQ8vrosdtxUonHvWETQ41mL9XQ5Z2JqJjhQpump": "NYLA",
- "EfqR6H3knDCgYq7QLtwjRAC5wPzustQvkzNTAMzUvirt": "NYX",
- "7W4geAJyy7hxuPXESMMBaW8Zi4MbhVN9uvt6BJ2SEPAV": "NYX",
- "HrLx8MLKegpbmbmWePZiuvf3AbJNx1CJyjBwUHwicEgW": "NYXC",
- "H3cHwjGfcAgm17Q4w68od2za4epqpH7gv9rkbAA4pump": "NZOS",
- "G5oL8AR1pd4t4xxGheZjS1DBxTBLJYsT9ukjcrKc5vJH": "OASIS",
- "CzkM8bzWFdXsjtZQnz2piTxJKPtJ5mfTL8S6sNZg7n7S": "OBEMA",
- "9NyLK6MHjbaKd1bY3EnFPJQDmkDLvC2WajUCErp9pump": "OBEX",
- "5WGkdemJNEoAVKveDQdzQmDqTyxCraXGw9ACyrwCEUMS": "OPK",
- "8SQQ1urC3Dynq9C2ieM6AozWgi4GCrLE6fnRoiWdpump": "OBVIOUS",
- "ocadaAXpD1haGy2JnjHbgUhczqtiMdYHzvnBihjJHg9": "OCADA",
- "1GNFMryQ6c9ZpMhgNimmsbtgYM21qnBJgRAFoNiondo": "OXYON",
- "octo82drBEdm8CSDaEKBymVn86TBtgmPnDdmE64PTqJ": "OTK",
- "4CoTCzobYt38zVbSieZxcmz2CCs8kmZJ6wnbj8HWocto": "OCTO",
- "DEhDXhtUFuz6Uodhde3rznGbVbdiECahp1kTHnFpsna3": "ODIE",
- "odinyvt9FgWWxw9BwZFjf7Agcch6Pk9mKubszw4izAG": "ODIN",
- "CBdCxKo9QavR9hfShgpEBG3zekorAeD7W1jfq2o3pump": "LUCE",
- "caer1UmwhRsfFk5huGYkXcFmiL2tj4cyT7YjVxUpump": "BTRUMP",
- "7VRvzb8XExciDb98kPcFC8v3P3ALbW9bhTUQQhBzCBPn": "OCN",
- "Dz7DKLAbAbzBXMDcLUFCVzd4PKKDtZCtvjKJ7Wykpump": "DOGEWLFI",
- "JDzPbXboQYWVmdxXS3LbvjM52RtsV1QaSv2AzoCiai2o": "FO",
- "5T17aqgJ8cM39SNuVBu2LK2cq5MWUpZxcQnnuwNjpump": "LIZARD",
- "6ymxqmDH8HPgheJMhLYdrM9exvwZz8dsR5DJBvnXpump": "PP+",
- "ch7rTovcUK7C1zNFM7F93kXU2CByYUsJT4pwYx7pump": "PP",
- "CqGMgsUDbj1XnKe45FbzZLd64MivoKPSgnZQJb3emoon": "FIT",
- "N1FEMCzP8gEPQ1HeL32v4wEUuKTz3X7KMGRM1jgpkin": "EXOTIC",
- "6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN": "TRUMP",
- "GAYCVRGZH2tHms1c5sCprE2JEbuz8tJ9ZxCNUX1cKwWR": "USA",
- "5m9AhhwMnosop8CAWdSJDNfLLkg3EFkX5sJ3zAuMpump": "WILDNOUT",
- "G1VhWSAhYXRRzokGqxs4aQ8u5DSuP69ki2bN7hnapjzZ": "ZUNO",
- "jE7q5qieKaUXmyhuWTXmGVtpeBoKtgbMbtks7LKogme": "OGME",
- "2nhStpBLy7umUR9NfhvurKoeTf4BJV5ui6Z5sHA3jaZf": "ROAR",
- "Fa7mkzDfzkgU2iQrwzpAvrpQoLFnMM85qnZCdaK4agQR": "OMG",
- "6FgPuEv5gNiHCTJqQeWiY6vu79fuSSqYJkHrpdompump": "OIL",
- "kLf5mp1wpHfJPhHxgM1DEDwJherwWrz91txmQagpump": "OILCOIN",
- "PqXub2t6A2vvUb3Mevk4uhj339rMhhmxq2HQzYNmoon": "OILX",
- "GJqCjtgEwqdFWVRsDs8JXKFoTeRVZeHs1RL4ccvrpump": "OILINU",
- "o5XguNKkz71K37BJsAhyMJnatwwbJ9MdixSmDW6pump": "OIL",
- "8RX8eViRE9hDZucrhQ9fUfiGejvV29nkxu38ugKzY69d": "OINK",
- "HRsTTwQn6FuC347F1k8V9NpfQSY9JfDEiwh8Cxuipump": "OINK",
- "AKzAhPPLMH5NG35kGbgkwtrTLeGyVrfCtApjnvqAATcm": "OI",
- "H7N54K1TjCgRtRLanZaPaDczdKFBTAiA4grvcVuArQzr": "OKANE",
- "8biqsLDiRPaPM11S42zKtNaC3WWKF64PNoPG9htzy99n": "OK",
- "HvPrYvgJiBtwUC7H4bi8L5bqnirFPWc2J9NdVy6UFiZm": "OK",
- "m6oDLvJT7rY7M1TxuLWP3pWmAPg2cCWDQR1NKiEondo": "OKLOON",
- "XsJb1p4Ks6VFggq68JyMz7S3kdRfkqh4wA6EMyxi4DD": "OKLOX",
- "CtzPWv73Sn1dMGVU3ZtLv9yWSyUAanBni19YWDaznnkn": "XBTC",
- "H5tnN12NCWqa6zhpmY2ykvmreEUiRaquqtQiPayWpump": "PHOENIX",
- "2Xva1NeLRuBFdK41gEuXqgeWtnKKDve9PKeCnMEpNG6K": "OHM",
- "3DkVGaNSMTcxFkgGDAm299FaVxgnCw2411vxZTmRpump": "OMEGA",
- "FTBq3w9gCv27E451DV6w8AbUjBQbyVxxj1ZaYEYepump": "OMEGAX",
- "4Aar9R14YMbEie6yh8WcH1gWXrBtfucoFjw6SpjXpump": "OMEGAX",
- "A8vJzs6ygbZQyYLf9FKund8j3pDfUzxBeje8rJiypump": "OMNI",
- "A7bdiYdS5GjqGFtxf17ppRHtDKPkkRqbKtR27dxvQXaS": "ZEC",
- "7mmXL6Et4SbpDs2iXoZQ3oPEeXeAiyETxh1QjDNi5qnV": "OMNI",
- "CgZTsf3rNnXsy3YkXmRr988p1Lrv9FpqBpLPWrAbmoon": "OMNI",
- "omfgRBnxHsNJh6YeGbGAmWenNkenzsXyBXm3WDhmeta": "OMFG",
- "Fzpo8vGJRRB9d8h9hv5FdNuvskTSXc55GGFvNpZupump": "ONBOARDING",
- "7qy1j4Mechfyr6uAST3djH4vk4kiEYC2cjEytXdondo": "ONDSON",
- "CJRXkuaDcnXpPB7yEYw5uRp4F9j57DdzmmJyp37upump": "ONDA",
- "A1KLoBrKBde8Ty9qtNQUtq3C2ortoC3u7twggz7sEto6": "USDY",
- "2L7zBZsKLJFMqQH2w7rUwiM6eKKg52w3iyeu37fMpump": "ONE",
- "4PbBkuZvub6Ugj8KwCCRsqk1Ya2defHXn7RSLbbEpump": "ONECOIN",
- "CEm2Fg6k1o9GKFnfzXqZyTE1UcfUw6dGt3Dsn37UHBwJ": "ONE",
- "8tKWk9c3o8sbvcqTBePv2B99ZTthMdXAhSVRQ1zApump": "WORTH",
- "of28WzrGVqVKCC35zjkQBrndCCDzErtzg7cj2mypump": "PUNCH",
- "7p2Rs9KkiWNKZkWNDFUCxG7EUBxbCByQC95fCNQ8pump": "GAL",
- "CwbpyHPZJ133hgWQvd1hZA4ZxjQu3mL7WRxEhmqQYkCB": "ONEZEROS",
- "CxN2KctowQ216p9wWRgiQeMe9ExRSrL7UeR2UYRzpump": "ONGO",
- "8KDsEUE3NdafcCVPqKrMrPfqh3oT4FzcxsYjwbMqpump": "ONIGCHI",
- "3bRTivrVsitbmCTGtqwp7hxXPsybkjn4XLNtPsHqa3zR": "LIKE",
- "BqVHWpwUDgMik5gbTciFfozadpE2oZth5bxCDrgbDt52": "OPOS",
- "onoyC1ZjHNtT2tShqvVSg5WEcQDbu5zht6sdU9Nwjrc": "ONO",
- "13qtwy5fZi9Przz14pzo9xqFSr8QHmLyUpUCvP1xondo": "ONON",
- "3AZAjwZZCe8Jf4yccheZ5Z1c2SPEPyoYJHFT3Le2pump": "ONSING",
- "29m5CkFSZSxKnCn9v7nqANdMTZXoNKydTNzsEcGDpump": "ONTOS",
- "5Y8NV33Vv7WbnLfq3zBcKSdYPrk7g2KoiQoe7M2tcxp5": "ONYC",
- "4ZfitzW524FUvWrGuNTg3x7d7cfCuNZzUaNEiB2BT5Lj": "OXA",
- "EikyJKSVWPK28rX5FG8KyJcSzv3D2b2Qg7VodzqQoobe": "OOBE",
- "oobQ3oX6ubRYMNMahG7VSCe8Z73uaQbAWFn6f22XTgo": "OOB",
- "48UE1jHd1YRR2EpTnRXi6dA15eboq92jm1YusW2epump": "OOF",
- "4QEFktCy1LzPyQyitkTSVEkd9m2AYr43ZJ598FDwbonk": "OONI",
- "2VRC6F23CjLv3nBHnNw41ua21jACWKcFmbWH4KohNKWU": "OOPS",
- "Cck21qHq33rezTeuQbPSvULXF2vLUTMErJwbPdUGpump": "OORA",
- "4HuSTfcJruukNbhrF9sc5iKrMeGxNBs6XpQ1L2hUpump": "OPAIUM",
- "2PzS5SYYWjUFvzXNFaMmRkpjkxGX6R5v8DnKYtdcpump": "OPAL",
- "ANV67ojLzxLeout1zi1q5yZAKdUTmhMjH5EaZn3zpump": "OPAN",
- "3Ydb2n8vAFdBJYpdiZEoDxRXLmiGDY1fuizVmMPMpump": "OPAN",
- "PreweJYECqtQwBtpxHL171nL2K6umo692gTm7Q3rpgF": "OPENAI",
- "76uBMvo1WL644VaUMhnuzSJSLJtQbNvr8ThubQi7E95n": "OG30",
- "ou1uE526v7zmUYP2qCb2LJgfXAyWAtWS9SETtr8ondo": "OPENON",
- "4MmJVdwYN8LwvbGeCowYjSx7KoEi6BJWg8XXnW4fDDp6": "TBILL",
- "cpbqtLWH8DkwuVYvKeVVjV9JowkFd8kkpo1vjCSopen": "OPEN",
- "HakUTodhpcA6T379NtPAUFajLykY1yUq4yrnSciWpump": "K403",
- "3mXoWmUd3LcWEhtY1vQwuXwRnnhn6h5SQHnXbWqpXopL": "OPL",
- "5q9bwAWb25x8m57mwp76UoMazYgs7MYRGDPprJfDawgr": "OPENSOULS",
- "Cpzvdx6pppc9TNArsGsqgShCsKC9NCCjA2gtzHvUpump": "SVMAI",
- "J1YnyKzmxBwFkPftvZexnHTm4Am7JnmWydhxtXdwEmMv": "OPN",
- "6cEeWxTBe6TcE5SsFRAXPUYsid8EbaRDQ1PkoopSkdkT": "OWA",
- "XsGtpmjhmC8kyjVSWL4VicGu36ceq9u55PTgF8bhGv6": "OPENX",
- "gbHFTMkuMQUy5xrgoCBdaQ2XYvNyjWAYcnRPh9Condo": "OPRAON",
- "HmCxqpgxaQng3A73F7vLgJjc9sr6ACFt8CEJwWY2hMGR": "OPIUMBIRD",
- "BK5GJDHXs9Nhnn4fcJrTauZ4guii5oEw7Cyxr6Ecpnqc": "OPAI",
- "Dxg9cLvssqb1WEMpyynjf17kGRc4UTNyUqjzNj99opus": "OPUS",
- "7qQnePEqSRBxnkFQQJ8jUYXUqo7mSkbwuUHj1jz7pump": "OPUS",
- "8AYpR27W1Y8WrW7yVyxB8AaM8qCTuCwMcB3HFmsFpump": "OPXL",
- "5Gzs2DxqK44fK3ob2LuxdmLfYRyuUe1QeE9MRSM3pump": "ODEGEN",
- "GmDADFpfwjfzZq9MfCafMDTS69MgVjtzD7Fd9a4ondo": "ORCLON",
- "XsjFwUPiLofddX5cWFHW35GCbXcSu1BCUGfxoQAQjeL": "ORCLX",
- "BPYhCMNao2XG4UR771LurHrwUg3rcp76jmg4XFfAacvg": "ORA",
- "oraiyuR7hz6h7ApC56mb52CJjPZBB34USTjzaELoaPk": "ORAI",
- "B6CdHKLm1XRxxgTnK9cNvT3DA75hPc9WUjTkxVUupump": "ORAMAMA",
- "29JU4mA9A66F6GLkdGUwL3rKdBpL8Mw6VZZHb8t8pump": "ORANMAMA",
- "GekTNfm84QfyP2GdAHZ5AgACBRd69aNmgA5FDhZupump": "GRIFT",
- "3oZnJZAH8EDJyFxA1xv2L1DJY6r54yFsdTbPTpWBpump": "ORBS",
- "BGyjasmSzYM9hHiZ1LBU4EJ7KCtRjMSpbN4zTru3W5vf": "ORBT",
- "CzywqyWnzACqc7nphTAPHC8cb2h7ou6U9TehBrVnzJKx": "ORC",
- "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE": "ORCA",
- "5YSjRtJJTZpQ44YF6qDpyygPCrJ61q5eNJRJRZMvKjZD": "ORCAI",
- "CEB5aF8w5hf3W2QVXpFVG3GEdvhLYyHVpiVAuFSYwave": "ORCASM",
- "4WtkHh1Gwgd5dc9cfqSY54U2fUZHbNzVLbrmrbvFMGhq": "PALMO",
- "4cCjHnKqLFMMNYQD2NYuRMrw7nXkxVsD85G2MkMA44vM": "WBRGE",
- "ABt79MkRXUsoHuV2CVQT32YMXQhTparKFjmidQxgiQ6E": "ORDER",
- "u9nmK5sQovm6ACVCQbbq8xUMpFqdPSYxdxVwXUX4sjY": "ORDI",
- "oreoU2P8bN6jkk3jbaiVxYnG1dCXcYxwhwyK9jSybcp": "ORE",
- "DuXugm4oTXrGDopgxgudyhboaf6uUg1GVbJ6jk6qbonk": "ORG",
- "G85CQEBqwsoe3qkb5oXXpdZFh7uhYXhDRsQAM4aJuBLV": "ORGO",
- "FBaQqJAuYkuKQpAcDuHtuupSPpqi33fbTxKXSjLDQory": "ORY",
- "NKaTB5vC3srLog8W7jzdjnejig2iH8eDpkDM31Dosak": "OSAK",
- "JCXMR4uW9aGDgqEvzSJcZ88iCtsm8MM2tQqk7P4Ppump": "GOPRO CAT",
- "ThwGDsXZ6iKubWuEQjmDxGwF3bUERDGbBXvcbjFondo": "OSCRON",
- "2otVNpcHXn9MKeDk3Zby5uanF3s7tki4toaJ3PZcXaUd": "OSOL",
- "66MH83n3jRqZMni87niTyKRoGbh9HxBkTm73sTRKpump": "OTCFI",
- "i7u4r16TcsJTgq1kAG8opmVZyVnAKBwLKu6ZPMwzxNc": "OUSG",
- "7df5p5aoW787CqUWGU2cwtdmtjd5Eiy3oJTbSpeRjupx": "OUTLAW",
- "8243mJtEQZSEYh5DBmvHSwrN8tmcYkAuG67CgoT2pump": "OOBE",
- "3Ps2gVJpDyEM2NDPgQNWreVUUn45i3HiRFb9rjdXpump": "OVARY",
- "8WFe29HGpJ4XH1xQUAq2aFJpMTYEVddiDDytnKPWpump": "OWO",
- "CYtqp57NEdyetzbDfxVoJ19MWHvvVCQBL9jfFjXWpump": "OXE",
- "3E2z4KX7y457xJqK9RQeJhA29oPdoUvAAD3Ea3zQyuG3": "OX",
- "H52iXFyxXJYD9VV6h9cCPk4Le1uA23D8gUKbsoGyjray": "OXLABS",
- "z3dn17yLaGMKffVogeFHQ9zWVcXgqgf3PQnDsNs2g6M": "OXY",
- "67iVSrbgQKiPjttU9uXx9CXUoS1Si3XUhrXeiNAUUZSR": "OZA",
- "PAALhGKVeiWMAatwxnwuvXoHHxYQoftLLhkgmXgFdmM": "PAAL",
- "6HsMxxNDee1WsRzonNtEEu35Lti4CXey8wzueY7rpump": "PACE",
- "AbK6sxHUV26mqQFTw8HgckKApHyev1ESZsKiRTJcFESB": "$PACO",
- "FJjKH9Xp2SvNDNUSN7X9T4uMNafFEYzbZpnwEZXKpump": "BOATKID",
- "9tnkusLJaycWpkzojAk5jmxkdkxBHRkFNVSsa7tPUgLb": "WORK",
- "1Qf8gESP4i6CFNWerUSDdLKJ9U1LpqTYvjJ2MM4pain": "PAIN",
- "6z9XSmYTZffoPUrpuManU7rxjfn7naEbWnDacdAXbonk": "PAIR",
- "FvER7SsvY5GqAMawf7Qfb5MnUUmDdbPNPg4nCa4zHoLw": "PAJAMAS",
- "HfsnTS5qtdStwec9DfBrunRqnAMYMMz1kjv9Hu9ondo": "PLTRON",
- "XsoBhf2ufR8fTyNSjqfU71DYGaE6Z3SUGAidpzriAA4": "PLTRX",
- "9eS6ZsnqNJGGKWq8LqZ95YJLZ219oDuJ1qjsLoKcQkmQ": "PALLR",
- "M7hVQomhw4Q2D2op3HvBrZjHu9SryjNvD5haEZ1ondo": "PANWON",
- "XsQ6NfzzLH8nspjrB9X8R2K64Zz7Tnxqu12juDiMPMW": "PANWX",
- "4qQeZ5LwSz6HuupUu8jCtgXyW1mYQcNbFAW1sWZp89HL": "CAKE",
- "Aw8qLRHGhMcKq7rxs5XBNCd9oe3BvoAhpNMVz7AdGmty": "PANDA",
- "DaUq6WNeLkwjdnWFk3xC6NVXpTXfLotVnUCd4qL9Ling": "LING",
- "PANDA8AgjdgQqRRYedrXGKTb2WygNsAhxNDpD7YrBgv": "PANDA",
- "7x1eHwdX1eKffNkQwJJtPsHKy6zEKGMuEvmArVHqpump": "PNDR",
- "4NGbC4RRrUjS78ooSN53Up7gSg4dGrj6F6dxpMWHbonk": "PANDU",
- "FViZQJymuQ9FaxmpudCQS7ffJUt4udHzwJKPBiy7pump": "PANTERAI",
- "Fb2DefbdjKFPfmTnq4xnuZ9xdtVyXGsEAetoFmGLZQcc": "PPT",
- "EXdq6GgKTNGQiMyW3s61CwV9meTEdPM5Yd1EpdoXBAGS": "PAPER",
- "BgV8qdfkjCDLPuDwhDaJGpgJj5XeYJeKwhG7E2bkpump": "PAPERCLIPS",
- "GDH5e33UuoJYkCcsyMBJ1VLtezPZ1hZXq6iVW4ADGGKf": "CHULO",
- "2adFTbyzVwMwPtgV68DUnrfdwB6tTAJiiVxJ6D8nwiEG": "PAPO",
- "9UFoZBPswibT1fWHJBNdBJ4wyKVVpJXNxfdHZnJmoon": "PARAX",
- "HrkKngiUavecwte1ZMrdt4H5Qet3cecNUzMoEAgjTAX8": "PAI",
- "3ywtR9qQH4BuA7LSfLvEuW1gh6ha7EK18XwLbHvhryPZ": "DIME",
- "Hmatmu1ktLbobSvim94mfpZmjL5iiyoM1zidtXJRAdLZ": "PSOL",
- "4LLbsb5ReP3yEtYzmXewyGjcir5uXtKFURtaEUVC2AHs": "PRCL",
- "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS": "PAI",
- "7k6cZGzuBjstHqaY2RLZ2h33jWF5oKWR6zHbFpfkt3Re": "PHAT",
- "GeUX5oxR86Uge9T81NC7JXdRZ9rBhtbKCMN8WhZPpump": "PARROT",
- "pA3VznTTnS22JERJ2okMK3hFebbw8dEpWph6UCf6USA": "PATRIOT",
- "PAWSxhjTyNJELywYiYTxCN857utnYmWXu7Q59Vgn6ZQ": "PAWS",
- "HVbpJAQGNpkgBaYBZQBR1t7yFdvaYVp2vCQQfKKEN4tM": "USDP",
- "E7NgL19JbN8BhUDgWjkH8MtnbhJoaGaWJqosxZZepump": "PAYAI",
- "PAYmo6moDF3Ro3X6bU2jwe2UdBnBhv8YjLgL1j4DxGu": "PAYAI",
- "HumaXepHnjaRCpjYTokxY4UtaJcmx41prQ8cxGmFC5fn": "PST",
- "59obFNBzyTBGowrkif5uK7ojS58vsuWz3ZCvg6tfZAGw": "PSTUSDC",
- "FDgSegoxrdpsct21YVeAbC9dWeTwTxA8Cceeh8BPpump": "PAYLESS",
- "9TwMHjLVck28REn4eHFxeqMYKkJBxLqwX8w7rxrdpump": "PAYNET",
- "hM7B3UQTTR81mS27SxDDPzBbjejmo8fnpFjzgv9ondo": "PYPLON",
- "2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo": "PYUSD",
- "XshWQWYVp5ff8CrAEsGmLVKD47nBWi3Ygn5v8wXK27G": "PYPLX",
- "pawSXHWsonrTey4SX7tz1fM9ksuLpE13Y54K57ym4Rg": "PAW",
- "PAYZP1W3UmdEsNLJwmH61TNqACYJTvhXy8SCN4Tmeta": "PAYS",
- "PnjETBCLC318DRejo9cMQKAmET9PvW8AEFGWMNtondo": "PDDON",
- "J5XxXQueFp1Har8GYa69N8Jw9yAG6r9VKujhAFaTpump": "PEACE",
- "85vdovHhkXnDi98EYMQmD2vXS82jRP1VDDXfkJ38pump": "PEACEGUY",
- "3mFKFGsc2NMAYrcGPmTgemPM2c3hemXAcH2k1kntpump": "PEAK",
- "6N1myX27SLSnb4fnArFAF3yNc98VXCUopZAqyzExpump": "PIMP",
- "dekNoN3D8mXa4JHLwTbVXz8aPAyJUkk443UjcSpJKi4": "PEANIE",
- "2qEHjDLDLbuBgRYvsxhc5D6uDWAivNFZGan56P1tpump": "PNUT",
- "J6dbiL3MfjnkgWkVqz9nrEwVZYLTC3d9ySSt3ensDXKw": "PEBLO",
- "9SiKU8vnRiBYQSBff84K5zwG7habzwYVzn7KrtgCzNfg": "PEDRO",
- "8ci29P8UHBaQVX752CRhD3btuqDh4mA4Mzqb1Ucjpump": "QWACK",
- "CmXr8rZyqxbFKv44kk1u8ixQM9mZnUf625k56p27pump": "PPPP",
- "n54ZwXEcLnc3o7zK48nhrLV4KTU5wWD4iq7Gvdt5tik": "$PEEP",
- "BqP9K6DMAG5hncqMY6uUWuFKzxwwyW4zYF3Ahuf3SZCT": "PGRE",
- "G4ZgRBCFYMEm3JmFRg29epeTTWrWt8kbhjgsY8BFpump": "PEGECOIN",
- "H4PDo8ngWwC4quPTRWfTr2HorUQ2Ep4G3JVeJHMfkZAT": "PEIPEI",
- "F4gxUGrn1xEfRgJj93BqXBqz9ZacR2TzxqfztiMXpump": "PEKO",
- "31eijQgD7tQ9TQoQWvcbGsYQmb2rjrAt24UacBDXpump": "PEKO",
- "AcNia1KNYeaDAuswtpJJZpPqzpuFNyvjd7LbxMXSShji": "PEKONG",
- "BgJW7U1u2RY5XJk9uYb5AqFRzjMtqE7pw3kaf9iw9Ntz": "PELF",
- "SWKT3Sksvtcepkn7MRn74WPUNH1Lo8H25MAogVepump": "PELICAN",
- "A3eME5CetyZPBoWbRUwY3tSe25S6tb18ba9ZPbWk9eFJ": "PENG",
- "5gdmkH7fRf2cHeX8AtrmRS75s87gbnDd4SpXHiVcpump": "PENGID",
- "PENGEKyPYXYDnbXGKcjXaSfMsovhcrtPT8S7127tKcg": "PENGU",
- "4M4ypzyZA7Sp2weYEMfnWuJ6wBVpNaMgaGTanmTspump": "PT",
- "BHtY4w1m4gHLynDxx6RwmU75bNmBadfVcVcQmyWopump": "WIFBAG",
- "3JgHze5iM3ztccvgrnvVaCAjPVqWk4hMssyZXn2KJ5S2": "POLLY",
- "9YHZjCb14bB9XWZz6FZPTf5nek7kLeoGHmNNrgcxpump": "PENGY",
- "B8vV6An7xFF3bARB1cmU7TMfKNjjes2WvY7jWqiRc6K6": "POS",
- "6Jj5vp8sMzj2SRAVRN9ZS2bqBUYDCvPxLGShXKMHpump": "PENNYSTOCK",
- "FCPMdpvwxtWBvgDDsPuBb6wyf41ik2gtPqNN9jWSBAGS": "PPW",
- "KyxLLGRvJZDRoAFS6PZ8geq5WNzY1b4nCwsokYJtYms": "PIE",
- "7k3j3ZsQvwB3eWXMRVMCXGzp9U42oKFLCFnLtUWVh1iq": "1IQ",
- "2wqkw3idoEYFV8fyM54PvS5BYHieT8rAZqzdHg6aqZby": "PEPEAI",
- "BWKyFgvQSfjNRbidRJ5CtuphashZNr3ba7oe9cjZpump": "PEPE",
- "6Neft4334Hqi2ak59K3SActWD3jWuhLvXuFHhGTpump": "PUNDLE",
- "CRAMvzDsSpXYsFpcoDr6vFLJMBeftez1E7277xwPpump": "PEPECAT",
- "EXJvx3KksbWP9QmPmtRr8mkQXD2kZrFRENCJitMs1eZ6": "PEPECOIN",
- "BKmYE8w1GEQ6khhLkvMj4ULvV4Gq7zLfJZSgsHE5pump": "PEP",
- "3tS6fbLh2P8tzxXuqCiHZpZhsxJpmrR3Xb9psmypnp69": "PEPE",
- "8jzRznet3cR3Y1KhciwUxKEqPku3BLcfiJLpVjMU3NF7": "PEPE",
- "DHsPzhYsz9219sQDj6vYtQMBBHeuyXAM1RA4mjv2V9AT": "PEPE",
- "tRmRf5Cycf1haB3p1kekwEQa8Jx4oTyzJf9oXVupump": "BOSS",
- "846XGqAnEhKFwc3QL2e5PQhSRvEbn9KspuxJ3nhY92kh": "PEPE",
- "2yd2Suus3YY4Sa7LHhn1PSHkjXj3XKrars4cCog2tGU8": "$INA",
- "FyJvH1WvCPPvhZaH8F46DAHdgMKvgKSvDRXF6A4Lp1Uv": "ƎԀƎԀ",
- "2FJkXdneMLkESaoU2U4nC1y5VNNFSxpRY4EJZwLpepek": "PEPEK",
- "Gpg9shYtjVgJ8LtMye3tS6izM6a2vK8Eh7XSEwUTpump": "PEPELOCO",
- "F6EzAYsWQb53Zr2VEiU3EefCwydmhkJ5pn2RNxUJ6mGf": "PEPEMAGA",
- "E1THYtEMfKb1RSPQG8d2iq31JQaGN8Jh2j88npwUeVqU": "PMUSH",
- "2mmdiGEDjiKgG2Tefj5UQad7qUT4eEqLDeja2ixipump": "PODGE",
- "PFireKhT5WG7axMSLBmMRpvYH7cgHx9CRWHU8F8HNbr": "PFIRE",
- "EdNiGWbkBwmmz7uhtdY3DqKZn1n5m1c61uLVgvXYZWGS": "PEPE",
- "FchXquY7jRGm85eaSoMtsJuUFZJPQEvcW2sC3AH6pump": "PAT",
- "3X36yhq35MJnt2JjwodeFDfv2MFPb99RC53yUyNrpump": "SKULL",
- "F9CpWoyeBJfoRB8f2pBe2ZNPbPsEE76mWZWme3StsvHK": "PEPE",
- "B5WTLaRwaUQpKk7ir1wniNB6m5o8GgMrimhKMYan2R6B": "PEPE",
- "FDqp7ioPenKRzQqseFv84kxDMUT83CX1qZxgDTQDkwT2": "PEPE",
- "6b7NtVRo6jDSUZ75qfhHgpy99XVkSu1kfoTFu2E3pump": "PRAWN",
- "9kYJGVYTxYUVPw59hcnXG2Q6VsC1GbK4KkhHsdrDpump": "PEPETOPIA",
- "Gk2kRrwNMBU4Dn9JhC1Dks8G5X9nqi4ZE5jMvK6bdgEd": "PTRUMP",
- "qKxNiXm85xhS2QBQBg3u43sf7E4mUDY73LL8N83pump": "PVRSE",
- "2qachMY68G2oPXt2SYPVSu3SyR1YgiiZFZ1pjJxnxKyi": "PWC",
- "8vRnnknwERunJEEDtEFoxzaxbxGnEY61FPbx8uTVKsUD": "PIF",
- "7So8nmhmAMNz7Sc618DPkpJaAy9VnfFvdy6WiBA27PnD": "PWH",
- "EAvKa9kGRMcQ44Eg3MPbXUP8ZEpfxgd5dToHBRF8m8ui": "PEPEWIFHAT",
- "D1ySHVWnaWQsf8WiskayoF7oHuvXLp4CXvYw3PaS8N7B": "PEPITO",
- "pepo1CFNU2RXf7yXX7HNXazXwxsq8WrPvDHpHriwoLY": "PEPO",
- "Gqqdgfkn7bcsuBQZEk9oMBkqCv1bRXvPmTLs3sQ9pump": "PEPONK",
- "zRSBtynHT8gbBBmTfQBAEWMQiUorwwAtng7YFBfpump": "PEPPA",
- "gud6b3fYekjhMG5F818BALwbg2vt4JKoow59Md9ondo": "PEPON",
- "Xsv99frTRUeornyvCfvhnDesQDWuvns1M852Pez91vF": "PEPX",
- "PERLEQKUNUp1dgFZ8EvyXHdN9d6ZQqfGxALDvfs6pDs": "PRL",
- "D7t47PKLFBM5smm9LYrDpEuqJ4C2PBAvWLhit5hhpump": "PERPCOIN",
- "FWoGYRhR6YagBSqncPSdn43GHNikSPw1ggrGzyM3H5rE": "COW",
- "CXobgfkQT6wCysehb3abkuimkmx5chS62fZew9NBpump": "PERC",
- "5UCNsNY2oHDB7i2m8bW7nKJXxRoh5WS4N4xKmUB2pump": "PERP",
- "5QvAeS2Un6ZoNjyKthGYo2ZpbcVP3diTMejyA48NEHTE": "PERSOA",
- "5LwseQRo8fsz4S3y7jbqqe5C7tZTz5PwhXNCHj13jLBi": "PESHI",
- "34a8ALsPmbWxp7D3bQ6erERrCLz1ahr6u6o66Udmpump": "PESTO",
- "GDmSzyg3F3CqgusT4CcxhjaKKfaucN98L4EUePeqpump": "PETAH",
- "GRciFCqJ5y2hbiD6U5mGkohY65BZTXGuGUrCqf7ondo": "PBRON",
- "26HijyQRPisA96er6xWLh32TSMAHLvivTnmcmu7bpump": "XPD",
- "F2k82EcxLtzekq1bfoGVdgp6EXZ5dLT1jE7g3LvQpump": "PENGO",
- "e9tZR9VJXqpjbGGjBuf3ypAgaf4w3K1p22pDfTTMDTc": "$PETSNA",
- "8NrAzg558TYtwdGYcwomsLHfdQ5dwEYckXqgfL6tpump": "PETUNIA",
- "7tPPYTBKrFLKKnoCwijrsfjAYadyp7GpAmSPUbVwbonk": "PETUNIA",
- "5zgTYTDK836G2Fc4ZLQp4rsyi78pAbuDr4qaQUE1pump": "PEW",
- "2kPoRJf9DTvcJPDBr1os49pGC1X3qSbJDLYPw12Rmoon": "PEWPEW",
- "Gwh9fPsX1qWATXy63vNaJnAFfwebWQtZaVmPko6ondo": "PFEON",
- "XsAtbqkAP1HJxy7hFDeq7ok6yM43DQ9mQ1Rh861X8rw": "PFEX",
- "UP5s1srLaHDc4SwJqLPa3A48x5R7ofN3hZWxWEZondo": "PCGON",
- "pSo1f9nQXWgXibFtKf7NWYxb5enAM4qfP6UJSiXRQfL": "PSOL",
- "8fJCtfbuAaFzdwTnQP84nNhSpZdVy4Uc929eXZRBN8H4": "PHRZ",
- "5veVHPNDsmSxDW4Abpb368wLHpo32LP3fqhfJHnkSSwo": "PHAUNTEM",
- "BDmd5acf2CyydhnH6vjrCrCEY1ixHzRRK9HToPiKPdcS": "PHDKITTY",
- "BxVQV55MSNF48H3Lur4fj9CTEA7bCVmFJg7gfym1Gs5M": "PHI",
- "Xsba6tUnSjDae2VcopDB6FGGDaxRrewFCDa5hKn5vT3": "PMX",
- "41xx693uzU3FH7vmq2erpqc4kZWjwhSntJwAhZGRpump": "PHILL",
- "Fss7oX43YpNNWVnRZugZ1NcngR1j8Ar33Z2dLqYfpump": "RAPTOR",
- "C19J3fcXX9otmTjPuGNdZMQdfRG6SRhbnJv8EJnRpump": "PHI",
- "DhRQWsiP53gVXnG8KQwq63Uo1FvouRpVNL8536tsVD5H": "PHTEVE",
- "9YnfbEaXPaPmoXnKZFmNH8hzcLyjbRf56MQP7oqGpump": "GOLD",
- "EswgBj2hZKdgovX2ihWSUDnuBg9VNbGmSGoH5yjNsPRa": "PHY",
- "Eppcp4FhG6wmaRno3omWWvKsZHbzucVLR316SdXopump": "PIBBLE",
- "DAfKg6exaeMMUQeqwRq3UP5KYPJjFNyVuVzFfr4kpump": "PICKLE",
- "PC1ZhGPajd4Xo1G8NNnZ3gpUtSgJUWps6kKuvMhkPBN": "PIG",
- "GB8KtQfMChhYrCYtd5PoAB42kAdkHnuyAincSSmFpump": "PIGEON",
- "Gv7sW9pe9khuPjCYmRUTmHNAFm8yWDJVtDVyA1DExqr4": "PIGEON",
- "7y1gCXgTJQz6XELJayX97ovtYv7PGsyqmLtotwSAbonk": "MOCK",
- "676YgDtdAekpjYwNvLSLFPkBooVxBqJVpgxxoHJPpump": "PIGWIF",
- "Gfvayte2S8QofiRsSXhdX1XX1CbcXvZP9jJkAU5Ypump": "PIK",
- "A18GrBLPSWUGg1pp3tg9oJU2KBQrkkKiyykL21b4u22i": "ORBIO",
- "97Mbx6Jym1iEkQdVfLf5PMWL5tARGnQ5na5jhR9Lpump": "PILLZUMI",
- "CsN1Tyz467bSFLPGd6MJyZhPNtwDaWZtX8ixHWyondo": "HYSON",
- "zrvL3iuAqoBdfwAmaUYrYcS8UjUk6LbKrexT7aepump": "PIM",
- "14GjpGfdm35R6PP6CVuZvtRMpVrKX8nJhH7jHk7fdrug": "PNL",
- "pi1RgmNaLQsNEyEAsrEjgmemojPwitwDAXc3zgseWWF": "PIDOG",
- "2idBzH45gfXFEhivcQVTXVgQGUDhX8scXoZwAiTQUT6L": "PINGU",
- "Ffjrfw9phxYYpQc9fyYq5uRV3K6943Wzo3t9a1L4vfoW": "PINGU",
- "7b36cKRYFZsMp3vLByVwfVQxW2ndcYth5rhPnyypump": "PINO",
- "sxyg1VTSzy5zYANUK7hntNtmFAWoXGJq95AcHuVondo": "PINSON",
- "v1G66wZM51Kjp5YFw3mws5MyQGK2ry5MHRrArZipump": "PINTO",
- "HHjoYwUp5aU6pnrvN4s2pwEErwXNZKhxKGYjRJMoBjLw": "PIP",
- "6d8p12ENyoNmpZ7JXNWHmnLwziNjzXov1JKf327G2FTp": "PIP",
- "WYHYGzvnz5xWs3DzjasXucDppQmA8W5QVnpk38sd8pp": "PIPCAT",
- "3T721bpRc5FNY84W36vWffxoKs4FLXhBpSaqwUCRpump": "PIPE",
- "AX8b9A79uDBTKDQoWTzq3NaD1FN4JEDGKR2yTQGhcwjo": "PIPEIQ",
- "7s9MoSt7VV1J3jVNnw2AyocsQDBdCkPYz5apQDPKy9i5": "PIPE",
- "BZKuDqzD4rb2puUV2cbSNd2kZzJ5JzKiQKwBzCk8hrLu": "PIPI",
- "RodhH2Xivnpt9AjK1ZniRap6TTcK1yx9CJmZ5zqPipo": "PIPO",
- "Dfh5DzRgSvvCFDoYc2ciTkMrbDfRKybA4SoFbPmApump": "PIPPIN",
- "AbP5LEN4sAAjghBy6ww37ngAAT7hnBVfXmXNdCnbpump": "DOT",
- "6ydMmFRaNt4AHBjgvSogbBvcxnTrX3QzUe2AEzVppump": "PIPPKIN",
- "3JsSsmGzjWDNe9XCw2L9vznC5JU9wSqQeB6ns5pAkPeE": "PISCES",
- "5EqRDhtdM5We4a5oyLeebJz7LfsRyXMNC52DMNEhpump": "PISSCOIN",
- "y1k9ZRqLwKLbyUe5LfQf53jYXeSyvrFi7URt4FWpump": "PDF",
- "BiwQX15cvwpyyGa5SC8uEXCqE94yXKFuLFSj5WtBbonk": "PITAYA",
- "Hc5oUkbMAmLHRmyxzxNkkVhsqSAn5A9LEjcCqZH7pump": "$BULL",
- "pxPdoEVJADUP5WD6d7vRQbwZknEzUL7pcNMJmXjpump": "PITH",
- "Di4B2JSRykk27QcD9oe9sjqff1kTW4mf23bfDePwEKLu": "PXL",
- "3FeFKTFQk2pEWwqax7vjxz6jSbFUpPASnACRSzDQcSRQ": "PIXEL",
- "FtHCi9cxJSSizrzMzsPjAfTfJi32V1CGRDM5Skqn4QBF": "PIXI",
- "3bGuPexrqNdmXkSxeUuMavYDFdjpQTSDt9ZusDgDpump": "PIX",
- "EwMCa7DgUEGhVmFP5ubTsfSNh3sgJQA4n6dh2Apepump": "PIXTEL",
- "4AkCN6KLeCmUDjWLg4XyQpuZuWtwBdPcbtBQjsA2pump": "PIZZA",
- "AyCao1LJJKrabYw4ZRLtXTtUiWxE2M34Eqi4Xkx3pump": "PJN",
- "XsMJtFbb8BwzQtck3oRXyAfs7SAPRuTXnSEDNd7BAVz": "PLX",
- "D3QiRT12vKBpj87h99ufQFz4mCpbPC7JVy1U6NRKpump": "PLANKTON",
- "7Rtegu95FZZ2KX3zA37LU1ypicxu6pBysNEagFwhpump": "AAAHHM",
- "DVuaDuQdPZ6H49inC2Xoyx7BpLAAJTPPChSfHuGpy8X4": "PLANK",
- "4NWHUsqene63s56idLAchHC85MgvCucBgCsMjkiZpump": "PLANTFUN",
- "DU7BqqKt7vC9i7paUQSeduxkWkTHQmoVR85M79pfpump": "$PLASTIC",
- "7wMutxpCdP3GbKaoMWoPVf2sFLCeV7a9ox25v1h2QsTp": "$PLATH",
- "EtTQ2QRyf33bd6B2uk7nm1nkinrdGKza66EGdjEY4s7o": "PPLTR",
- "DeoP2swMNa9d4SGcQkR82j4RYYeNhDjcTCwyzEhKwfAf": "DEO",
- "7yF97k6jrBkb7BXJYXzmwQLQyxVirLtCSSGb75qLqAN8": "PYM",
- "49UseCTadQcTQNeqpKJHbZgBXRSiLGuJZRfePQkTbonk": "PLAI",
- "PLAYs3GSSadH2q2JLS7djp7yzeT75NK78XgrE5YLrfq": "PLAY",
- "ADVgDMbbn6LZTdo84UDAgCUew2JMMHe6BnH3KNN3qiLb": "PZP",
- "6PaVHw2HR6ybTvPMXkLcGUF2A6Hiy857k8PQXkTnpump": "PLEB",
- "1dHeFbmsVktbHXGcW2GZkfkfYxV4yTKbcusNV3fyTX8": "PLENA",
- "9kCuaGMx6GNBcTfZHEJquzjZaayVThVLPzoQ16SYNj2c": "PLINK",
- "49Jy3P5J41zkcCgaveKXQfeUU3zNCHCSEEypkJTrpump": "PLINC",
- "ydDccyq66xKtfqn5bsRpfFXz4WeF4fh3bgQBx1npump": "PLOI",
- "TnfswqdE1jAJ8sfnf5J7kSVLEH1cfpAYZ8MWmKfondo": "PLUGON",
- "2cJgFtnqjaoiu9fKVX3fny4Z4pRzuaqfJ3PBTMk2D9ur": "PLD",
- "pc3gLpoZCe79SZAbABtes2fiWAaiTJuTk9NsNxR2ZSj": "$PM",
- "AX9D7Nqtu3enaeL4ELxoagsNV7AyEQEhK2ziwiyJpump": "PMPR",
- "58mWi7CzpsRjrDsv61BN1ynpNLoGHUbxAUeec141pump": ".PNG",
- "UVcu7kbVKW6Rs5PKzuwVSbm8ukvrWByS3hBXqHapump": "PNP",
- "7jYfnjn3jHWmUhhgfkZ9uUEKroH3Zz1BvF8RmVQHm86D": "PNUT",
- "BDbhJUMgQBQ1bJTKhSS9NsxZdfaiBG6Hgp8qNKpc3YSX": "TUCKER",
- "8g32ps7JWAL7EDkmBhW49dkUCHRq1Des1Hg8sPSb3ou3": "CHLOE",
- "2kkwPP6Y5v4aSteLo2R6uqmx3aQ6Veb1xDcRXHsNbonk": "PNUT",
- "AAmgySbEeNWyn1JdKqJbdKAqa8JEtecVZamaNvkt8Ccw": "POCHITA",
- "6LH9NDBYUf7thDx8sMZppZpxAsdXtsQ9VN37gKMpZRSp": "PKM",
- "6CAsXfiCXZfP8APCG6Vma2DFMindopxiqYQN4LSQfhoC": "POKT",
- "6gVJwfHxWov8HxdAZ4v4tt2RpZZst6du74y4bUCdpump": "POG",
- "2miHpQbYLPvXxC2V234jrrrtnJdejd5xW883a5ToNW3g": "POGAI",
- "93x67YtArpqdzmmyXQ7qxhvvoDTkC59dsHWXhD7Ypump": "POG",
- "3ywqi49rbrsgyNoyBDngQKKjqFTMxCrZXF2NgnYDqGo4": "$POGGERS",
- "BFUadco9hktp8wrLas34DL5jmVYE17qYmfxZykV7pump": "PJ",
- "Gg1wPd1JybEYyTDrT5N4pA2YX1pTq7tcpR3CEUuZbonk": "POKERPUG",
- "4v2DRssbwaMbdMwqqN5EkSB9dCkKLorcg3ht9sHEpump": "POKI",
- "GMBA3jpN1pzkQfFh8RSQ1rCT9qCaDLYMF51mtbWMpump": "POLAR",
- "3zjV4gHs3d2saVjSc82hEnxaBwkRe2timgP1onNNXray": "POLICE",
- "DuhSwRVN7z8bWjYzwtRv2uDfpAsbTPxDnDezzi9Nsf1y": "POCAT",
- "D5WJ9eH4WLF1SUazsMZLUKTz4xb6mKHNzS1ufeynmoon": "TICKL",
- "6GihmsqNR21azuRuHgbjQxcDoxX7xgqqs58PQkyxpump": "POLLY",
- "5eMfXSYdssCpnu63WtPprjbbR5YBJmSEnZGRvtuppump": "POLY",
- "FgHpSsku7asGyTThooDmkKwmzy24ucUeyBrW9kLqpump": "POLYAGENT",
- "J27UYHX5oeaG1YbUGQc8BmJySXDjNWChdGB2Pi2TMDAq": "PCULE",
- "FfixAeHevSKBZWoXPTbLk4U4X9piqvzGKvQaFo3cpump": "POLYFACTS",
- "CWR9o6fei1J92MhSoKqDootrhBo5zDgjsqeQecSzpump": "POLY",
- "Pre8AREmFPtoJFT8mQSXQLh56cwJmM7CFDRuoGBZiUP": "POLYMARKET",
- "3pDjFXDsYrPEt8B8SVrJDa1FZ7Q57CJx7uxeNsCVpump": "POLYMASK",
- "HygZx5u3aaXg38grfa39Y59NSGFQXSMCUyAYWoZfpump": "POLYMI",
- "3BWA5RBXyPXuMGZmVL8Snefu573FMJNGpsVi79baiBLV": "PM",
- "2k5o37XM59vQRmnnVnJAEspqfEG9VfoFNTywH49Jpump": "POLYPORT",
- "FsPxXisr7W2mSipE62hXPeVMycDKrV2R1Jf7RQHBBAGS": "PP",
- "AigqqAyxV1quPYjskhpoYEK3szVRDKcHmiaFj3rXpump": "POLYPUMP",
- "5FfhakAvaXPJNR7wDwvB2UbWRY6KrsdDxxCFB7uKcBLV": "SPORTS",
- "BuWe9Wd5XqCUUV1xZMtcpCPg7iqdYoyC8dBdSbEUpump": "SWIPE",
- "3gfm611yupHrsZ34hc5K87Q6pWXx6zLwL481hQq3rGMA": "POMATO",
- "Dkm51nnSbJeet5fCVKgCCMiXGveLH2k6scGVh5DNTxQN": "POM",
- "3h1H6gNEGRsKCV76FDJTQaN9g1LNkGPPX3XmKdispump": "KORI",
- "HeqCcMjmuV5s25J49YiJyT6bD5qWLkP88YPajBySniaV": "PONK",
- "2GMEDWxPhdBicySMjUky49UHgXutxQ8SJjWyrcKPpump": "PONK",
- "5z3EqYQo9HiCEs3R84RCDMu2n7anpDMxRhdK8PSWmrRC": "PONKE",
- "56sDqbDNaRwP6HK1o9wpYtzE5PAkNePsQe52oPx1pump": "PONKEI",
- "9ZoH3ssTQBJNVidsLo49q3buDidreiZc9g3NeETP3F2s": "PONZI",
- "L84NryNjZWNDmBDVy5bYNGwgyxxoFExZmo3Qnohderp": "PONZILIO",
- "2d6UM4ocm5zENYsviZwYWRuNduYd21mWx1QKf3Z824aN": "POOP",
- "J8XFfJgS1cs5WVGxGwZb9Rt5rJZizdyzaLhidtvDnYjC": "POOH",
- "AmXoXkTmLvwoQSVqgRnEXA5mLg7f5D7gpJ4wJVGCpump": "$POOKU",
- "9x4ZSZhBPzv3xJ2QeWwqvfJb6r8CYZ1R2tNNVHoYbunt": "POOM",
- "7uwNJaMRj9FZuubmzguU8A4cR15ykpBymhAiVJEFTjZ5": "POOP",
- "2KiHzSXdnenDoDNsVsjU6VcvgyyDK27iSoZv6TNDpump": "POOP",
- "7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr": "POPCAT",
- "JYPzbZpgYgit2mtfU5cmcuhWJaB7KTdtfBvfJrepump": "POPWIF",
- "Ee4n93iv9vtY8cYcUEqFCpBtmCq1ZMKR3pLzPQsmDMY5": "PCORN",
- "EATGZHJViJsk7nEKkrdJicwNbfpkJfAtmrEmrjXR8NBj": "POPDOG",
- "C5gnRtcm1a2aCBbtfAPqnDjpQ2YdD9PcfBk8VM2iguXS": "POPDOG",
- "DA1qLpgD1M7TNNRPycizyQCoRLCt7GAx1YTeVrfYpump": "POPFROG",
- "CoseJDEHxsfjjQs5CaXWGd4PH2irHam2FxeuwN2jyAL9": "POPFROG",
- "FySqgkyoZXVYbtFM2DHSjzSHj8e2h1TcguGeiPDboop": "POPI",
- "6waeBwy3stLMvxSeA6FjMun8p4TYGre7wpxtyEzCpump": "POPNUT",
- "6kJhG826LGowg7zG6PLd6tg7mqvVSdq2WzHhsfc7pump": "POPO",
- "96QoNkZLTKH7Gecf6dKMRXBQXW1wqh378uF9pnTejgAw": "$POPO",
- "GD1AR5uHytu7nHJ9zWYEEHytmLe7MaD8wg6Tzesdpump": "POPPY",
- "8nez2xunQ1JTnVETFr8YdRBV32JRrjsSMzbJ9qFkpump": "POPSEAL",
- "GtXFYBrS8mobiQpkJpdhL6fBJg1NJhFUMGCPuFrSpump": "PPP",
- "FMQjDvT1GztVxdvYgMBEde4L54fftFGx9m5GmbqeJGM5": "PORTAL",
- "PRTLSwfLzpVGSAQiUfXEenJkq1cwTsEcsn1hPL9zwwg": "PORTALS",
- "PoRTjZMPXb9T7dyU7tpLEZRQj7e6ssfAE62j2oQuc6y": "PORT",
- "JCV8BB8Zde8ukroWKTjLSENSWEj42kBkENjjws2Rh6vP": "POSEIDON",
- "EMKP9FV5wakvyodPh8edQW4RTSbHPrhYRDEiCiz1pump": "POS",
- "9gr84rGyLvVasmqXvj65njjUgKyBemKWSJsvijTPmcQz": "POTATO",
- "PotzPaFGzK3cbu1u3g5HtoZbyTUkyhka8T2aBy8LMEq": "POT",
- "5EQotG3SrMgC1pEqEgkPGGVCK1mHWVBFWV7MnKivvPTT": "PTTO",
- "PouWaap6bHZv1oT7T7rzRgQHTBD4nsWQRHGbB5hfDA6": "POU",
- "BALLrveijbhu42QaS2XW1pRBYfMji73bGeYJghUvQs6y": "BALL",
- "pWrSoLAhue6jUxUkbWgmEy5rD9VJzkFmvfTDV5KgNuu": "PWRSOL",
- "8CkiSHHJDHJV4LUoiRMLUhqG58cUkbyJRtcP4Z3mCXNf": "POWSCHE",
- "5A3TS1kbq8J1ZagEo5RYC2MZsN57eN9mrL1CwqS7pump": "POZI",
- "AW8u4LiMo1SKcGiMBPYzHcWynirZYQA5KwsoFUMJpump": "PRAIST",
- "AaRLHCvt6G8e3dbxLvN6BQi2S34Lvv3eeBjKNzc2QZB9": "PREDIC",
- "57KoEZXm2mJwFqbB7fvcgZmmjc9mivFmKhXA45H3pump": "PREGUNTALE",
- "32hUYG6DVZ92N9N839D2Hc5bUWGQTSVdYUPNBHNLpump": "PRERICH",
- "Dob5TVKdisbwk1QSppADF8knxHtLR6DovxHGqaocpump": "PRICH",
- "FaZwrtepqwBf2TMHVaxRWt4U3Zjv4LxmcisQXYy1pump": "PRESS",
- "AFk1RUr18RCFjhKHQN7ufxPBiQYWjXifAw4y4n44jups": "PRICELESS",
- "6zoshtkmyX4kRFg3p152yV2bPssxeYdNvW3c6EVCE4UP": "PRICK",
- "9BZJXtmfPpkHnM57gHEx5Pc9oQhLhJtr4mhCsNtttTts": "APES",
- "2DfBjrPFZjDTiCY6pxchS6aSdUdEpkm7PdqpovHjBAGS": "PRIMIS",
- "GaZ6En5JWWR7u7dqnpvRr5tk56XRV3KRtZwdeuR3pump": "PNET",
- "28a2oQVCPrJB7SLZo4DVMVdHchSXiG8sZy31DohPpump": "PRINT",
- "CsY1MqwwgyBGUrAZq6pU4n9SCQJn6nN5Bo8s8Xwpump": "PRINT",
- "8stssUiCFbcB2LqCS62EuU2x1K2NWbJJo1YPgskpftWK": "PRINT",
- "PRSMNsEPqhGVCH1TtWiJqPjJyh2cKrLostPZTNy1o5x": "PRISM",
- "H5hygVvXiYxk2a3BVtjiqcDJK8TdHTB5u5U1fXEuBAGS": "PRIVACY",
- "7HcZz4segTW8rLM6m5bR7ZQ8KamTm1MJ3jhdDNirpump": "USDP",
- "BUUB7DpQT1mcTrs55oXawgEbxm5khAozsbmyhMdRpump": "CINO",
- "yhTd5ay9wnYWU5Pf6YncgEPA7ybpnqhdLT9poqhchat": "PRVT",
- "DrnF17MbiKXu7gVyfL13UydVvhFTSM7DDWN3Ui8npump": "PP",
- "GSgxY6HdcxNfLXJqVC8JBhYCKb9rRAdqGfoxZvYapump": "PVX",
- "prmmgF5GJCSDNEcwZe2HWb5DsDsFngxTetZ95C4VKxX": "PRM",
- "4TUNzcgp2fPD48fcW4seRjyqyDZMrPj4ZubnXFEsKeYk": "PRNT",
- "9N9V585yTpmosZacAcXLZWxKJEK7PbaH4RJ8gEKLD9sc": "PROBITY",
- "GZ8v4NdSG7CTRZqHMgNsTPRULeVi8CpdWd9wZY8ondo": "PGON",
- "XsYdjDjNUygZ7yGKfQaB6TxLh2gC6RRjzLtLAGJrhzV": "PGX",
- "HiaZB4rrRXY2pqpHqEfhiGAY1XoMjLRrJoHCcEku3232": "32",
- "Bz4MhmVRQENiCou7ZpJ575wpjNFjBjVBSiVhuNg1pump": "PROJECT89",
- "CJjraBaedPnKzjnag12i7PVo5pSP6cB9heV8zr89bonk": "PROJECT89",
- "72XUGRRzuSoLRch3QPpSPHkuZ8F58rvtCNF4QSosLb4H": "AEON",
- "dJhBorriSsJwkWKTFGNDnvmQm7CG81WksStqaYFepag": "ASCEND",
- "5evN2exivZXJfLaA1KhHfiJKWfwH8znqyH36w1SFz89Y": "MIRAI",
- "76PsEyML7UV9uiBDWMdG3itRRuupDuRs6nNpjNBpump": "PPCOIN",
- "9jpeicbKQKiczgu1wBVTDUgM8rVjbQGG2jBK8g8Hpump": "PROME",
- "9NW7fiBu4uHpLx3rxiMccucyKwADwuptTpb8z2YYj9SH": "PROMPT",
- "3ViHjF8Gy7qXyXTVRfgeQosSuZCRJAs8kdHF475Fpump": "HIM",
- "AkbvXVZPzrHSpcxNADQ7Uxk6nvjHtpHn4nqNQZY8TJBn": "PPX",
- "qKtU9A7ij34XmtxaSzYfxCpkgAZzzFsqnUb2kW2ondo": "PSQON",
- "14W1itEkV7k1W819mLSknFTaMmkCtPokbF2tRkPUondo": "TQQQON",
- "D1tu7Fnm3cCpKyyPXrqm5GXShPqMj7a2SEjjq9fondo": "SQQQON",
- "CWFa2nxUMf5d1WwKtG9FS9kjUKGwKXWSjH8hFdWspump": "PRO",
- "3jMwPagCmBfHezz6jasepJTeFiJcdEt47hJscg4epump": "PRSM",
- "4VwJLikGQ5N59BRzxyaZZjLiB38r6HF4mJ1mU8fjbonk": "PRYS",
- "8gFpUK3KTjCHhTMsCvkJ8E8mQ5jP3uqpHc65rjtHpump": "GRAIL",
- "uPm9ebhrGDnNXiyneeP9WG57wNbQ8bd26DRiWSNpump": "PSEUDO",
- "pSoL47GE52V2bgUUyQvs9LSdWQZsokarp2yNsWQaLYy": "PSOL",
- "DAFdakKAEvB6GtJgnDk1LC1QK4gQrtTK3eKUZtAJpump": "PSYOP",
- "2nP9yKQNSGQy851iyawDvBkzkK2R2aqKArQCKc2gpump": "PSYOPANIME",
- "DAAXmRU9KUEuyqF8VuddbcL5X4QhQ3tTDMYxDbNgpump": "PSYCARTOON",
- "EFkiR1hE91BkqbxA3YxvYuvDxXTTEMea3zQs8ndbyTQY": "PSYOP",
- "E5BuPQkFkGMAvzB6fQCJyGZDVHkdNaYZuj1Kfz92pump": "PSYOPPEPE",
- "2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv": "PENGU",
- "G9tt98aYSznRk7jWsfuz9FnTdokxS6Brohdo9hSmjTRB": "PUFF",
- "D9paufRCehpk2YGRPkzJPEUDsvQjaTFKNyFDqgd4xqd": "PUFFY",
- "H4zej4MPNaxbLdD18yAkhWMPNYTB9FDve46mKV82kmuE": "PUGG",
- "PuLSHCKeLRxaB4qCdwZAoZFj297oTSgVh8SzYZtUfQP": "PULSE",
- "7LvJrVmmY7BYPA76EzATeRerjKbsfNUxkRzEtiJ4pump": "$PULSR",
- "2FWWHi5NLVj6oXkAyWAtqjBZ6CNRCX8QM8yUtRVNpump": "PUMPAD",
- "7vsKatZ8BAKXXb16ZZMJyg9X3iLn8Zpq4yBPg8mWBLMd": "PUMPAI",
- "F5QMUBvNupauQScbyhc6WNcmMGRdw1bM3a6oAtxspump": "PBANK",
- "Eg2ymQ2aQqjMcibnmTt8erC6Tvk9PVpJZCxvVPJz2agu": "PUMPCADE",
- "pumpCmXqMfrsAkQ5r49WcJnRayYRqmXz6ae8H7H9Dfn": "PUMP",
- "5TfqNKZbn9AnNtzq8bbkyhKgcPGTfNDc9wNzFrTBpump": "PFP",
- "H9G3pEdKuRdyAg7ytxexJ1o4nTnyem4JkC1w6AsSpump": "PUPPET",
- "Vrb3u5yd9R9X8utxyBo2TKqdGpzU9RzkzEjd9Tupump": "HALLOWEEN",
- "2RBko3xoz56aH69isQMUpzZd9NYHahhwC23A5F3Spkin": "PKIN",
- "9Eufcq8yqukb4A9eUTAXrRpzB7aKTdAuUnqe75ttpump": "PUMPKIN",
- "7TffjPhjJHMoqdtoA4CWoRyNxwJsYJe1ndGURAVgpump": "PUMPLESS",
- "FcUdd49bfuajzmVKxGDkyFWqZp7vXkh1fpsCmtYApump": "PUMPLIQUID",
- "DhaLZtprNqwpUYqhrTrtnCGSuxsdnk489UqSrZj3pump": "PMV",
- "PumPRGmZ56t3Vngxo6fCP7ZJQ14oUg3biKxXrEyQBSf": "PUMPR",
- "AU1dQQhLho6M5YuyRvhvofPrQWt3sRiB9FmsXtW3pump": "PGC",
- "NV2RYH954cTJ3ckFUpvfqaQXU4ARqqDH3562nFSpump": "PUNCH",
- "Aaku3Vy5m3eBXXcogGQzvhKNJzWEGMcfosQUVyiN82LF": "PUNCH",
- "GnYufMbTAMz1DzkSN2DmwkBzjMTLkM22WvQuN1VCbonk": "PUNCHY",
- "WskzsKqEW3ZsmrhPAevfVZb6PuuLzWov9mJWZsfDePC": "PUNDU",
- "EG1Y8goUGa7y4iRYRgLgwBmSHc4Lxc91qL35cdDNBiRc": "PUNK3493",
- "8UKuetxWnpC9Po9Mpf3ptT2wEvkqg9GxZWnnx4VPhpeD": "PVT",
- "AyPNhxMEh5n44T8GhFCCzQzUXh2tTRagpQduVYeEpump": "PUP",
- "8shTEDxbwvM2C9ELXNHsh8pmkoWovzJ3xgazQFWFapMx": "$PUPPA",
- "PUPS8ZgJ5po4UmNDfqtDMCPP6M1KP3EEzG9Zufcwzrg": "PUPS",
- "7EW5dDD6MYJK4PcZ89MGApJQwWeDEeNgH4NCVU4qpump": "PURCH",
- "AScrhkW2GohYy57rek2YVRc4J9UyXwmbAbEEKkoFpump": "PUB",
- "HfMbPyDdZH6QMaDDUokjYCkHxzjoGBMpgaUvpLWGbF5p": "PBTC",
- "HBoNJ5v8g71s2boRivrHnfSB5MVPLDHHyVjruPfhGkvL": "PURPE",
- "EmofuHSiLiuDasHV4eDKKP9LeoZkG7HmXYdn2FeqKHeC": "POSHI",
- "BBG3vpXVCm2uPBD7LUr7yfP9XUXVNJRHMtiMG7q4pump": "PURK",
- "3BWH8cDy6djTDhf6FZrMkXBxdbMuidV9wmNW5zPQbonk": "PURRCY",
- "28gBfdqoTdbVJnmqZK4hg9rZ7RGJk4Ru37VrbA15pump": "PUSH",
- "F5RyYFSXMuTXPjcLBTDr9ihy7ZUw93f1b3gLn1U1pump": "PUSH",
- "HptE1m1U5DanCEhhttTmPpG32KepPoaC4AfdkBiC6UZG": "PUSSY",
- "FWAr6oWa6CHg6WUcXu8CqkmsdbhtEqL8t31QTonppump": "PVS",
- "CniPCE4b3s8gSUPhUiyMjXnytrEqUrMfSsnbBjLCpump": "PWEASE",
- "6GjTpbuTx5AWAATbUhE5QHC295fj2gzjYFfNtqSBpump": "PWOG",
- "CtqwBpgVcY9kwBi6YvtoQFpheAKXWoq1f9WKPodUpump": "PYLOT",
- "FW5GjN29j5ZZCXe1on4HFiS1xvQaChRdfgbfQ9iF12Ua": "PYRATE",
- "14qW8bcMkmHQtgJ8VohkR4FXiuYWqvLy4AtpGbuDpyro": "PYRO",
- "CreiuhfwdWCN5mJbMJtA9bBpYQrQF2tCBuZwSPWfpump": "PYTHIA",
- "HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3": "PYTH",
- "57vRMpAeePeuEiEPVtwZv4uXYTLkHeWa9Q5KoGorpump": "Q",
- "ERKbvKU1Md4AXNyzWQbagRJWpGE7rwUxGep9ESaxpump": "QAI",
- "Aeu42GYcQZyzLiBjixGY9BDbyUyhHPsXrYrUZNcaYdBi": "QEEA",
- "mtQ5jWgCqrgBiSut29b4HV19RkMBGA6vidwTMqhNmyy": "QKA",
- "EMg2QkFZ6pLvgckVGj8X6nmyrkiuoamYnTdoxXN8pump": "QPAY",
- "96hj47MzSpZgVcT1v4nwpbQNEU59f6ys48PArGivpump": "QSTAY",
- "4dqYzXnTfNrbwMdJ6uum2FbPC1LkmHtSAbXmh2pfpump": "QUAIN",
- "9WfEyNqngVzbvdcpWD7e7TFhgv7T5afBRVHcMw3jmoon": "QUAKK",
- "ExnNnP5mpv4MwMUM8QrYbG5PMyGSq7GcU9SrhVnabonk": "$QUAKS",
- "hrmX7MV5hifoaBVjnrdpz698yABxrbBNAcWtWo9ondo": "QCOMON",
- "2qHqHd1YXSa77DP7XqWvuUPVJbWMmZfbwr1QFtH1pump": "QLC",
- "qntmuw54sn81ZawbbA7FwHZZQygBnfXUyHJeCCix5ag": "$QNTM",
- "BbtrrZ2ExfCTzrndFBCx5iNDFXxuVxNMdEZ14BZxpump": "QGG",
- "F3hQ4u4AsNMSXkhWSRFcPkVbEZwGoSJurviLdbcxpump": "QUANT",
- "quantoL84tL1HvygKcz3TJtWRU6dFPW8imMzCa4qxGW": "QTO",
- "5woMJykwmESL5N2sR9vYyAjLp1NJXZFxwJ7ejF1nQntr": "QNTR",
- "GovbzFQAsXk8rGy5SL54u5Tw6rGaUGnqEypSUDfwswrm": "QUANTAGENT",
- "G2ygAeUVpYUhpNsmrpvd2BHTWazyDV72kRpsQSEcbonk": "QX",
- "qbioCGDnUBGX5qcK1Fc4zg19GaQEPmxHFMPMZQm4LZ8": "QBIO",
- "DPdNMhjBnftREwT82KXytQBk7zd5RBkRrG41L795pump": "QE",
- "E4YowrHx5wm4RtSjfuvTqtNH3Wf7NEj5tYZGD9Bondo": "QUBTON",
- "2BAKjB47KpQD64m3nWGWrNjC2ZTwWpumYakJVgavdXQa": "$QBS",
- "7F9bK2Gj7X5YY3dYfojoWVQYerFYcaGCni6Czt8Xpump": "QOAT",
- "AvMdYR4dVLatpMa3YecWhDrerXp5Wx7sNLNTyiA3pump": "QTX",
- "E1XGEP1nk3BLxpnkWfqVnpVTA13RYzpY6Na1XD2Kpump": "QUASAR",
- "QB1TPvpNUd1GgYeEkdFDDxHx9rjKRfM3VWRzYtkKTwu": "$QBIT",
- "8MGGDLtSKi9R9ZoBEDWsrhXetpdWrykRucuVMw7mpump": "QUBIT",
- "3MyaQBG7y3SHLQZa282Jh2xtB2TZKHGzNp1CuZ4Cpump": "QUDE",
- "HjDYQUb4VfaRkYa34Mya6uNoZ6XdCu16qQGz6RVZpump": "QUEEN",
- "BeqAgjEajRgfh1FXggjX3p9iWhNsnrhKR5VjLj1Zmoon": "QKITTY",
- "FWaRpuDUhNbDxKgacKBht4mP85LVaohty6V2WD1XShrX": "QSHX",
- "4v7TVrzCQPp2nNHn9twrf3eyHQqcy7ieVSLY4xE2hqV": "QC",
- "2xaPstY4XqJ2gUA1mpph3XmvmPZGuTuJ658AeqX3gJ6F": "QUP",
- "AUuCEHQ7sm2i5GmaHrpE961voWcTY8U6mgrkhcV7pump": "QST",
- "5xcRDXCC7CGSMyiaiL127GsLGt6vU3ChK1KWFtRhpump": "QWERY",
- "qJVmZgRBaK2Cycm1KqVKnoQeh9bVBNJo4uXq49Htime": "QWQIAO",
- "9eEwQFkS1tSTCHqTHdPHa6R9broq1NKdyubReMP7pump": "RABU",
- "Dc2XfjTGQQSL1xF9m7hCoUF7nVAGvfG4rZDQPdU7pump": "RACO",
- "CzFvsLdUazabdiu9TYXujj4EY495fG7VgJJ3vQs6bonk": "RADR",
- "FVFZxEewzrXooU8n8PjGPWKHHzouDjPfW6rzVaeXqGvY": "$RADX",
- "CEv97t1Qp7FB6XX1PH5ohyrzUCeKAQbCpAjxegJq9HW7": "RAFF",
- "Ak1ZjuCCQbNEjDhe9xwELA9iDX6VPhftcVSzRbibpump": "RAGEBAIT",
- "fZD6VmBpiAmgjUbgwRkxzyuXBy7x6XE5d3reX4CeWjC": "RAGE",
- "GvV7sFu6FHJsSVXfpG7xqFnWar3c7YkcC74rqe7Bpump": "RAGEGUY",
- "G3FoXHoQDuGkEG8ZqQd7riC9uB1N51bg7JuxJEPNpump": "RAGE",
- "CmgJ1PobhUqB7MEa8qDkiG2TUpMTskWj8d9JeZWSpump": "FISH",
- "3iC63FgnB7EhcPaiSaC51UkVweeBDkqu17SaRyy2pump": "RAIN",
- "7ES2bLatqiXAb1bKUGN24av6dSPgRNdWUwPe3SgEBAGS": "COLOURS",
- "j1MueUJvnJwRCKzgEQdJjSibhV5oy1uoLZDNsZ3time": "RAJ",
- "GQJPirLnGWTgJc4MtFTDiQ5G4y2Q8MjZW9fCpREyF41y": "RAJU",
- "G5grLASvz1xzgdh1c1GKy2q55mfuDDXhMQoXnDxWpump": "RAM",
- "B3zWuNcVQK9YVHngeDH7UFwsmudWnNhFn89T1AQcpump": "RANDOM",
- "RNGRtJMbCveqCp7AC6U95KmrdKecFckaJZiWbPGmeta": "RNGR",
- "F2uvr8qmQNMKsLS9KPrXcyqYVXeVS4Gu5iRyS2p2Bixw": "RCN",
- "Fw5jbh8eShWrWhft17HqN1osB7NG2rbi6D5s2Zhjbonk": "RANKFI",
- "GWaD6wcxSZFwXApoY56x6Cxiqs5sAvtQNdcUvz7Zbonk": "RARECOIN",
- "DD8SzmbfyWKTMzHvJb5pGGx8dWxNkiCwZ1r9ZtjuBAGS": "CUBE",
- "CTNzPwk2cxh6dFUoysokKU6umNwmJobYx7SYgwJZpump": "REESCOIN",
- "D9aVAWMB1wpRbg1t8zeupprqcnrxcBwvnXtcodafpump": "REM",
- "B1oEzGes1QxVZoxR3abiwAyL4jcPRF2s2ok5Yerrpump": "RASMR",
- "3vJenGaGsuKG5shPhi7rjnuy3MV6xjmBTGjYqYzXpump": "RAT",
- "ratioMVg27rSZbSvBopUvsdrGUzeALUfFma61mpxc8J": "RATIO",
- "FFXsbx4rPwM8CyKKZiPU3YS9xFFirww6QEzb6KCCpump": "MILTON",
- "6hsQFV7DsSyyVmu6sm4UkvYbpHTJhiUyB8fr4DdhSmkg": "RATWIF",
- "DEJiPKx5GActUtB6qUssreUxkhXtL4hTQAAJZ7Ccw8se": "XD",
- "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R": "RAY",
- "C8wvVNuRPm237bQqqcfRxas77GTK3RzzoBCkWgrGpump": "READ",
- "FQt7749yicQ9vZ2CA8r4ghq4MCPJpsVicT8gNkAjpump": "SKILL",
- "HKJHsYJHMVK5VRyHHk5GhvzY9tBAAtPvDkZfDH6RLDTd": "READY",
- "Cy4DSbZW4CE6cG6HDqQFhXxpHTdm41SY9hBB1JG6pump": "REAL",
- "Cy8hMjvArwXKjM7K7oe8peoay2cWjWkW82J1gVjQpump": "REAL",
- "8Aq4fWMgPqJbF3w8w8PnLDRVUAFe4mzsCvPKxAArbonk": "REAL",
- "9HBLhDZc2hyuDL7avTo14FEVcjs4fQ6yA5JuYL9cbonk": "CHINAWINS",
- "3SkjMkrpkqngCCMd3sVU2EuKMVRLTfHEykbzTyrVwBLV": "RECC",
- "5Wd2ALxQfnpgQKCyH4WL9giBiiuuLuJs84CJxfQccvmN": "SPEED",
- "HELn8rSM1rp8vAjNH4NYXzX6FvCbwWMGqLfaMgiBnZFV": "RIO",
- "EBGaJP7srpUUN8eRdta1MsojrNtweuHYsdP3P1TRpump": "REALIS",
- "6WVA2BBmNhbHJHcK6JcYczUc2L6omgAhDk6yJhuopump": "REALIS",
- "6zYgzrT7X2wi9a9NeMtUvUWLLmf2a8vBsbYkocYdB9wa": "MXNE",
- "5UofhCbmro2tGB7Ji49SfqFag8j7ymrRyCmBTCZXGQQa": "SMURFCAT",
- "EArkn8uVf8YLfpF2eCdkCvDaPYpQuJzKXxaCnyxXc2P7": "SMURF",
- "G8aVC4nk5oPWzTHp4PDm3kAuixCebv9WRQMD93h9pump": "RWA",
- "EWQqHFoS7FrDp8Fmj4sN5qV5YKpV3cReCFjiFGtXpump": "RWW",
- "AD27ov5fVU2XzwsbvnFvb1JpCBaCB5dRXrczV9CqSVGb": "REAL",
- "8mgM8w9BDeZvL1pm86xPDvPw9XHL3vwXkFBqU693pump": "REBIRTH",
- "97jof1XfY7h91P3uVfYLocXDVHQseQzoL26n57Tzpump": "REBO",
- "DF4zASfiDBr3uuAz4s2Sxtsjo7tDFZiQ2nLeKJGfBAGS": "$RECAP",
- "A8Z4uv53e6PS6CYNVNd7HceRCZMHecqpuyzuMWp9pump": "RECON",
- "7nZuYZYZnof9gF3zr9QhdnxpQ1mTM8LN3VaJuhrGbonk": "RCON",
- "HqKu2gbkHyG1o1rs7d7FYkoES7g3wgfsar5n8qY2pump": "RECON",
- "Bmivfdqqbua26hHKJsmBuq89Rhk21Yr7CzpiJYwCpump": "GLYPH",
- "GoPffEZ5yuWNnBuUCmwx9idbH9D63xATkrGa6E9kpump": "████",
- "3QGGLYLu251jE9Ra8jkGtuHb773xYciXeqqvUgNTGimE": "███",
- "HXFrTf9v9NdjGUTnx4sojR3Cf92hoBsQFUxKTN7ondo": "RDDTON",
- "DCgZjb2LN5r9Ck5VZAATh8x3sTUHyTzEguThGqh1pump": "ARC",
- "B4f5Tj8h8xSoF9zGHxhL1fLQwvgKWcEFhbTMyVhXJ4ch": "ROP",
- "C1YT4fbjCkwqodUVLryYVRs37vmvYnihAJjVDDeupump": "$R3D",
- "Acud16jqA9j1Hc83JrHYeiN2BpK8LYYQ1h6FGnYrpump": "KOVU",
- "7zfnQC53eGtn2H6AxW16sGCmKnnUC8ajCwBVZwd7wtY3": "RED",
- "FXXYCLUw6iGDgyRts3HwzcL6MXDeZLfid5EiYqZApump": "REDUARY",
- "E6KSaqjvqe2HiUpbEweRxLK4RimQddigm95H9Jaondo": "RDWON",
- "4ABXJEK62bfKqPiCbSsUtmb4nfkCNPDGtvLhwQcAWNjc": "REEE",
- "uKV2rALePzYtrTayv7nDNEfw3SxAa2boDPcJzwo6REE": "REE",
- "BsAEhPN1DKfpjMoSZ5UnDTL4impSYvT9ZpFjnBD2pump": "AIKA",
- "8gHPxqgHj6JQ2sQtMSghQYVN5qRP8wm5T6HNejuwpump": "RYS",
- "E86mX2yb3HLbJM6gRtZQ6dCYmLh6MSDZadu9SCPondo": "REGNON",
- "6HgJHzGpq3fSLmkepsaC8F3VtpUWfXcG4hmUaf4Vpump": "REGENT",
- "DP4omjjY94NRJrECHBZyUQSpGrjtukoDyUbqb9Zzpump": "REGRET",
- "vQoYWru2pbUdcVkUrRH74ktQDJgVjRcDvsoDbUzM5n9": "REKT",
- "HtabxQjpBHTKVoiKBhbUeCJevYjnnEkTyTuqcRQnpump": "REKTOBER",
- "5AgHPy5UojpGq6TdtQCNobCZ2tkYmZz4d5p1cqr6pump": "REL",
- "CTkPYPMrehsREdzn2dBMCwNxbP9ExrEnoQHMgswYpump": "RELO",
- "9XgfFWPxPU6hyDyGtfhC9D6eyRE3RUSgAYKHRznWpump": "KITKAT",
- "8wZvGcGePvWEa8tKQUYctMXFSkqS39scozVU9xBVrUjY": "REMILIA",
- "remiG7sGaHWgrY7o6SXJW5CYi5A7kmKutyJz6x6hUsp": "REMILIO",
- "HALHrqgt8WX3Zi6PjJEBBDiJWMbPxfGEBkjavoCQpump": "RMT",
- "rndrizKT3MK1iimdxRdWabcF7Zg7AR5T4nud4EkHBof": "RENDER",
- "5MxQUFdPisppdVfjitL6hs492GyikCFnsBWYtuAqpump": "RENTA",
- "8x8YipfqZctyTadL2sETH8YbMtinZAXZi6CYFebfpump": "RENTCOIN",
- "7hB4AgnZp7RiThvtFTGMedkrU3G8X34fwHzy1vQjpump": "RENT",
- "3DK98MXPz8TRuim7rfQnebSLpA7VSoc79Bgiee1m4Zw5": "REZ",
- "ezjtoE6PYVnWkbJJYEsGHgR3rXgBydi9eeB1YHP8cVg": "EZJTO",
- "ezSoL6fY1PVdJcJsUpe5CM3xkfmy3zoVCABybm5WtiC": "EZSOL",
- "M7tBg3eVTm7L1nMgoQsREF2KjBaWW6pmv2C6MUUU5i1": "REPLY",
- "7VuQeZKwthC6LiHb8U8fFNibnasiWKSaP9KQmdNLpump": "REPOALYZE",
- "6RVA2CGzsonW94GedAqy9Y15teSZADw72wA1JE6wpump": "REPOLITE",
- "DUp2qMMGuACziKeyZRtH9cuKyqtYpqJ24iZg6tVLpump": "RDOG",
- "EAefyXw6E8sny1cX3LTH6RSvtzH6E5EFy1XsE2AiH1f3": "RPC",
- "8CZuGZ2eneMy513c8759sHWh85NjMRk9UjUR9j8tHL61": "DAM",
- "Ejqkht2dyN1BaaEtK92zBKY6S8HbVH8APB5sDK9Rmokt": "RUSD",
- "85y3AuomcSaUv8tBkxDeoB2GV7HhJrkvxr37PDu8pump": "RESET",
- "bzSoL4Ehh4AsaPdVD2ndkeHy9nmKnP8YRwVt3TfaJQq": "BZSOL",
- "7G5DM7Jy7TMWKgH313tA3vF6AqHpbHP4TWZzpTVLWv9c": "RTR",
- "FDXJWqqhdrKh6TmpVKGVmHk9qyLrizzVfYd6SB7drug": "TROL",
- "He2EL8hzZKZEQPZw3TvHCRoBeuh4rQzCBxvv3uCCpump": "RETARD",
- "FtTSDNLD5mMLn3anqEQpy44cRdrtAJRrLX2MKXxfpump": "RETARD",
- "RAPRz9fd87y9qcBGj1VVqUbbUM6DaBggSDA58zc3N2b": "RAPR",
- "EwcVckR7G28Hzzg4XxBnEC3uEYjgKx9kyLQBsbLHpump": "CHICKEN",
- "3Ksxijyb1vgCE6hvxqGejdRrQnSTKMXKDSMKki8Apump": "REFI",
- "C3DwDjT17gDvvCYC2nsdGHxDHVmQRdhKfpAdqQ29pump": "RFC",
- "7RrLheV7dSecVka3MfjYb4Wa6Z6uegNyzhpFeERsfFZP": "RETARDIA",
- "6ogzHhzdrQr9Pgv6hZ2MNze7UrzBMAFyBBWUYp1Fhitx": "RETARDIO",
- "3Y7uP2UhEE68dpyAmWfXc7biSQmQqQonCiyDp6KYpump": "RETARDMAXX",
- "3Rt9t4vM1KShncfMgya69ahrktmKewnHz11FUhdapump": "RETERD",
- "HXkbUADfocGyz2WrzJpjEfry8qyNDm5Kwiiq3Mz3tTi1": "$RETIRE",
- "Bb43TPQQh5TaoCtFLGjfwAhqcLumN6mTUmCy2ojjpump": "RETRO",
- "FmJBuuQ5nhsbAZ5mA41fQn7AtAQvTMFtMMYc5mjBpump": "ROOTS",
- "1ugKvQBmxESGM8RX3RmBNVEwwko8i4jRaueYz9kcyai": "REVAUNITS",
- "9VxExA1iRPbuLLdSJ2rB3nyBxsyLReT4aqzZBMaBaY1p": "REVS",
- "2eu1K3wvfPC7gVj1CK8ohv4ggusdN6qxyxpjHyTCkjZT": "REWD",
- "CNKEXXypBC66cZ111Mg3JUxyczXS1E9T6MWEufzQZVMo": "REX",
- "J7cENeeQs1XUgfruGNTEjXAAa54Rut8VYdDuMmmBvirt": "REXBT",
- "AcV2T3mwLUqMiiqcsafVm35zwPQkmLrfRtaW3716Fzvi": "REXHAT",
- "3uxMtF7dT2VSvRFkrLf9Gqm4nDDy2J5RBEXCQpjubonk": "RT",
- "Gh8yeA9vH5Fun7J6esFH3mV65cQTBpxk9Z5XpzU7pump": "RHUN",
- "65nTNuJGHme4PQvKQyJykKp1bJAkK4A8Q66sd2yBWugf": "RBT",
- "Hrh6QCmnGjtq3gqg4xZzncXS7wAWeVmu7SCRfQ4N5H6S": "$RICH",
- "E4WZzxRB6hc1Pd6qZAq6QnYemfFT3iwUydqPjzVaPJqE": "RMC",
- "9HGziACBczM3VorD3B6ZYtj6BA595jq8erzsSVtUNo6N": "QUACK",
- "9ncLaQhTpKCyq542mH5fWeW6cL5BNmiCsToCcJyVpump": "RICK",
- "JBahfY5TSFaBooJ5N186Zd9JNvVgm9iHRJSUFT5KqNxA": "RICO",
- "GJtJuWD9qYcCkrwMBmtY1tpapV1sKfB2zUv9Q4aqpump": "$RIF",
- "jUpa2aDCzvdR9EF4fqDXmuyMUkonPTohphABLmRkRFj": "RIFT",
- "AAeENcfHbTExuTvs4q7r9Bjax98Dg6BGX3aMph4bTLdK": "RIF",
- "HjBMk5rABYdAvukYRvrScBnP9KnN9nLdKSbN2QPppump": "RIFTS",
- "H4kzQgCg24JyDNBVEgQy3VZXUorBuXkwQuW5bx4ypump": "RIGBY",
- "dwEPNKQab3iwRmjGvZPXhAmws1W5NsQGwuXwi8oondo": "RGTION",
- "6wUfdjiBtXjiWTfwGabBqybVTCAFoS9iD3X6t9v1pump": "RINA",
- "3diwvdrQGJ7zaCeCrxQenK9iphmxdKgrFhaW8FtLVBGA": "$RING",
- "i6f3DvZBuLpnGSqS8x6WPeStJ7jNe5KewD6afD5ondo": "RIOTON",
- "Xs31mE5EiqjSHEaiX9QDKCN6NvSGCqpJ6f1FNq2wri5": "RIOTX",
- "FJLz7hP4EXVMVnRBtP77V4k55t2BfXuajKQp1gcwpump": "XRPB-SOL",
- "F6eLNTprbtUmo2hLk7GCPmawJapADSfyY3xWJ421BAGS": "RISK",
- "93bVs9o8Nq88zxnLWwUAVfN5PXBhCcnV5sfs6AFLno8q": "RIZ",
- "AXRsYFt7TXNQ3DcY6BkvRgPV6VsYMURyDtaeudjondo": "RIVNON",
- "2uWZLXzbbtmPbJVZjMpm17CPnfL73RFrfvHntsKYpump": "RIZE",
- "F2WVwKFRPqE3gMKw22swL5DHgkbdwgEfvhKCoicygcWB": "RIZZ",
- "mMKSMNrRT764ZWNgfZyFXxHe5WuTa6ee3peD7sbRiZz": "RIZZ",
- "9isJBF9KGWNGga6D4Hbz6H2Gj99ra9JYNxD6Csxppump": "RIZZ",
- "85cQsFgbi8mBZxiPppbpPXuV7j1hA8tBwhjF4gKW6mHg": "RIZZMAS",
- "8dktTBKseLSsLPpfBYhoKzaAGTAwKqsp6W6UNFtxpump": "RIZZMAS",
- "F6zgVJ1Kj7DBa8RyCsPPsgpXJ35z6MDG88cwqA1Wpump": "RIZZMASEVE",
- "2qpqweHfSKUvZFGQL3D7aadD5i5dDN8kz9xdZGraGAxC": "RZTO",
- "6Fb84TUdMNAVgwRinLeTgLov8dJnk5yhNt41Xq2a6s4c": "RIZZ",
- "FNu1NKrgyZQjhaULhFH5phXqUwCPBAMkzbddjdBHfRAV": "RIZZYEAR",
- "F4YXmo8CDLRvWGnXyxVZ62wwc7oWcBam7tu4G5kGSaKZ": "RKEY",
- "7i5XE77hnx1a6hjWgSuYwmqdmLoDJNTU1rYA6Gqx7QiE": "RNA",
- "2fUFhZyd47Mapv9wcfXh5gnQwFXtqcYu9xAN4THBpump": "RNT",
- "1HE8MZKhpbJiNvjJTrXdV395qEmPEqJme6P5DLBboop": "RDMP",
- "5tB5D6DGJMxxHYmNkfJNG237x6pZGEwTzGpUUh62yQJ7": "ROA",
- "RoamA1USA8xjvpTJZ6RvvxyDRzNh6GCA1zVGKSiMVkn": "ROAM",
- "8SZ4EsABY82RMNm3Ce2RtKFdA9BPfb4NaoMyCQ7Y3cYT": "STONKS",
- "EKEWAk7hfnwfR8DBb1cTayPPambqyC7pwNiYkaYQKQHp": "KITTY",
- "G6haJithfeUgSghVpu1rDPCq2NFiYcJFHNpHEANbpump": "RM9000",
- "BVdXGvmgi6A9oAiwWvBvP76fyTqcCNRJMM7zMN6ondo": "HOODON",
- "XsvNBAYkrDRNhA7wPHQfX3ZUXZyZLdnCQDfHZ56bzpg": "HOODX",
- "HrevFGePRXFXXqhssyvteG6y9HU5by1MUegJ1ot5pump": "RUG",
- "Xss5RAku5EH6UViFdvW7ss9xQjwQLsrs2opPMhb3k43": "RBLXX",
- "CTaQCjEs7UHscQmX4f5r3NqyiMFMxAHNgyNxxXhgpump": "ROBOBOOK",
- "HEA4baiTauugXqWzSVVA43oaZhQf7zoUg1kuoSfqpump": "ROS",
- "pZHpptKLqcx2ykZu4pbNx4kQHafD3hv7EB3K2wgpump": "ROBOT",
- "88nWFvwiLeHTh46Qtb5wTduuAi8tfukaXThJndPxpump": "RI",
- "EigAfZW1sYAocChRJXV3FzT8JuhjaSYNWW5CkKdpump": "ROBOX",
- "5KxnfDmsXVBNkVHYhW4kztV7ZCCCbrkYxBVrqLWF3G7J": "ROCK",
- "E9VQY3VnrpVSekFByzRmfeK1kxgM3UiKCoVVbdUondo": "RKLBON",
- "XsKSh3QDynp6oms9yHjZXbZo3pKzUBoqUFKPHS2g9Bh": "RKLBX",
- "A2orqVJJVhSTr61dUvRWciTduc3TaZMZADJxmK4UWfGJ": "RSLT",
- "4icEZCrEYNop2ZaMMCkRHaNzkt6xG9BpijMCQV7mpw6Z": "ROCKY",
- "BVG3BJH4ghUPJT9mCi7JbziNwx3dqRTzgo9x5poGpump": "ROCKY",
- "GdbyLsNKHKLXTZVEo8QrGKVmrexEeZUYvhpSfuZ9TdkC": "RODAI",
- "5CieaQybZ4m2iMofcSxJZxJ9wKnc1WyE7SWTtqsUp1He": "$ROFL",
- "8hN217wBBgRkDiyzabLmSuS95pxX5PFcv3HEM5Ha4ZEv": "ROGER",
- "BCQjsvdsoqaSKo8iwgmfnzMV5S2rC7XR3i2K7Ep8BAGS": "RAI",
- "4mTgtpb3sgo2gr3uWfa31n9WdG2esfrdgY3URdcApump": "RHUB",
- "8hCYPHGC73UxC7gqLDMBHQvgVmtQ6fryCq49tJMCP55D": "STAR10",
- "HjDov9j4ByNX9MMgD4w1LhU4DYLB5xABYh7SXLuszqU1": "RONNIE",
- "Ha4oiA7TJtoE1jPk8m6r5GPYm1ERmT9oKU5CZAGTpump": "ROOKIE",
- "8yev7nLen2PFN2uYGhzsUbu243wMa9z4ZrCwuXs6DEQw": "RBTC",
- "8PMHT4swUMtBzgHnh5U564N5sjPSiUz2cjEQzFnnP1Fo": "ROPE",
- "CtaVq7fp5xwYFenGQypqdK97LJhTD72GgRsY8e4Npump": "ROPIRITO",
- "6FDJbSkiySbetXaELZYaL9im8mAyCkMfHB7rtDt9p3qp": "ROSA",
- "BVdMM5Fd7MxcTExnokXZzmCtiLvd2Es5zZQqRLNmrzSy": "ROSCLAW",
- "878q23iKgdEWa1wyqg8RCgVaj8CRCsFN82qJfHbmpump": "CATGUY",
- "6ZMu4PRVpNMxVHdzMDcGLQf4Qv9x73YHpsHrK6mepump": "ROSE",
- "9QSjVAg5rDfBZPhvKwZcB63St3r6bqohP3Adurkjpump": "ROSIE",
- "EkVYMGehJKAFowTQpGoxiCpDTRNEoGanwvNUYXhqpump": "ROSSCOIN",
- "FgQ3sxj54SmVzttkxuK4bdiEnUNi6kF9Hyx3ezKW72hn": "ROVR",
- "E3oEF6TZb5DssCqwyXRt31AUEnGqvcHeVcyGvLiqpump": "ROY",
- "D7rcV8SPxbv94s3kJETkrfMrWqHFs6qrmtbiu6saaany": "ROYAL",
- "7M9KJcPNC65ShLDmJmTNhVFcuY95Y1VMeYngKgt67D1t": "R/SNOOFI",
- "12BvLZtzjdssAycxPeBQUjukhmgQpULAvy6SroYdondo": "RTXON",
- "Bg9CZr1CmVoCn2uNWwj9f5rLbmfYRYvcVikCRCwawUwR": "KENIDY",
- "mDshrPRV32j79trDVEQjdRsfZ1zdzjwh6eQK9e9pump": "RUBY",
- "2VBDM27xPCiqWrFab5oREF4UWJVVXpxGCaTrBgb4bQcq": "RUBYCOIN",
- "DKqgMMtEiAMXR8iz4tpVXgnmL8Bgzbu4XPyUrZWrpump": "RUCK",
- "2rVgh6tcU1Hhk58XwD631E2D6iqLV28prSdpBXaLbonk": "RUDI",
- "AMKKkovbUqr5cxmsg22KxTgaRXq6z4f8umrze4JKpump": "RUECAT",
- "FAMfdnr3daYqxP7g9iaSa65RNXnzLWDD8c2uPENKpump": "RFLIP",
- "6YGmqZ8i3b4TrDDh5mqComviPUKpwGWTyfFNoWfctech": "$RUGPROOF",
- "Fh4oSZ6kn4CGgaojS9dP7gLXbG9KF5Dc9rAkgT6SBAGS": "$RUGPROOF",
- "2yHXtrPGH6G8H51nCeN5LbohemtAdgu4uWLjyGYKpump": "RUGPROOFV2",
- "HhVM9vHUxbAiRZ9chEecxhF6UdkzveaCG1NC1C3spump": "RUGPULL",
- "6F9XriABHfWhit6zmMUYAQBSy6XK5VF1cHXuW5LDpRtC": "RUN",
- "9fAT1fVVEKMEL6rUeYxSYU8ZjQ5dSiTzAZYTdiPvpump": "RUNE",
- "DvWfXV7MeLjKk3Xec7TQNsBHfQkRETBkuxSH3MFGpump": "RBN",
- "M1NEtUMtvTcZ5K8Ym6fY4DZLdKtBFeh8qWWpsPZiu5S": "MINE",
- "2oGLxYuNBJRcepT1mEV6KnETaLD7Bf6qq3CM6skasBfe": "PUPS",
- "b6LNCreRaHRJ6xa7JmVcPqtAW6NMogzyi4MfcQRuniC": "RNC",
- "FS4xcBxLJbrrdXE1R6zHvKw8no4zrQn2rRFuczvepump": "EHHH",
- "5mjbjHRb327yvcWUc5WPywhCbYi32pqUqxPUCtpipBLV": "RUNNIT",
- "DDij7Dp8updt3XSCzeHCaAoDoFTSE5Y27i2EQ9qjMQtr": "RURI",
- "XsbELVbLGBkn7xfMfyYuUipKGt1iRUc2B7pYRvFTFu3": "IWMX",
- "6vhLsGaLCdcxkdx5R3cftVB7KS9uzK1CgGtN1ZZ6pump": "RUVIEW",
- "H2814bJjmr8N6VrNAQkTsBscN3BSvDn4HDgSceTcpump": "DRPAL",
- "BC2CWeUZZvZKniqn4MedxFh12jNjSMLke2Hp2puTXutE": "SAAD",
- "Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1": "SBR",
- "7Y2TPeq3hqw21LRTCi4wBWoivDngCpNNJsN1hzhZpump": "SACHI",
- "91act8ejuXSvR1qEahRjziCPyupDMnUqcm5NL3NDpump": "$SACHO",
- "Fntdgqhz4tbX1RNKKk47uEBrhnzvJsMYi4DHCu9utJu9": "SAC",
- "HS297WZTnktHXk5DDtaWVQ2AKS4HsJ2CfYTLYVRapWpK": "SAD",
- "6btQswYZNDs3g9rn76zvDMcsmMJNYrcQQ6g6VcAYwLoq": "SAD",
- "26KMQVgDUoB6rEfnJ51yAABWWJND8uMtpnQgsHQ64Udr": "HAMMY",
- "CQcjASdDAvTMJsybZTJJ3hvfdwbi4uTqmtd2SNqYpump": "SC",
- "ELPrcU7qRV3DUz8AP6siTE7GkR3gkkBvGmgBRiLnC19Y": "SFM",
- "Dc29xEisYZXfCV3WHgyhjnwPYS53fZ1n2YPGFEC1pump": "SKG888",
- "Gx5dX1pM5aCQn8wtXEmEHSUia3W57Jq7qdu7kKsHvirt": "SAG3",
- "CMe1QWsoDWFUi95GMkk7mCTnnjxBxtnJ3jbrEhQTVWL5": "SAGE",
- "8x17zMmVjJxqswjX4hNpxVPc7Tr5UabVJF3kv8TKq8Y3": "SAGIT",
- "4rWuWZei2iFNHYpnz5wjMeSvimsJcj5EgpSNvNS1pump": "SAID",
- "dWd8vyAH9pQMMG1bkQWiGnyx8LjjuTDHsk8qcsCBAGS": "SAILANA",
- "4vfcfjAz1tSA6tWe7cP6Lj7fR8y7VactzTKPxof7pump": "SAI",
- "B7e7WzU7pZvbMYFdMw8NSQN3XKfHVGDGesBCfjh6pump": "SALAH",
- "7D7ukbcnUNYt7Et5vtsDZhAy28MKu9pkHka1Hp9ondo": "CRMON",
- "XsczbcQ3zfcgAEt9qHQES8pxKAVG5rujPSHQEXi4kaN": "CRMX",
- "GKHgTd6tqvycgG3mqcZraSZDFR32hXhRgo6sZQtudMsC": "ALL",
- "BWWWurbodjGbovFetc3FC6oSbqkdoE62E1XqZ7X4pump": "SBAE",
- "ENjwcWn1uUphWtvuP8ypjakr1jMHY9vnznXXrnMVbonk": "SALT",
- "4BBjpGwLgGmUxtT82YFK9xMhcvyy3zgf3HpxTRip1YoU": "MUNDI",
- "FkbWN4dcFQym2PgCELfThghQqLuA2e2jThMJyhZjfG4M": "SBF",
- "DK29axm8KpWExKxxBapPvCTERbwmLsLXpw3f7SRKpump": "SAMDINEKO",
- "7ifX7okDF3Q5equtyFo5BkwZyeKY1hGcZCmkZQ5upump": "SAME",
- "Ac61nmCxyvqTLzFcPXJQjLsJYFXYRVKkyxWN4kiqcDmF": "SAMI1",
- "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU": "SAMO",
- "53yANribNp1WzRsciY6upAN2VPY85waZEtADTeJhtQGN": "YUKI",
- "5dpN5wMH8j8au29Rp91qn4WfNq6t6xJfcjQNcFeDJ8Ct": "SANA",
- "GQz5ThKHNcuAvMKA8rCPSdoFUoApk9Fi8qB9m3Gqpump": "SAN",
- "CLoUDKc4Ane7HeQcPpE3YHnznRxhMimJ4MyaUqyHFzAu": "CLOUD",
- "EJmUVvDqAdfH5zEohkdS4234bi3c6iunqEMobjmondo": "SNDKON",
- "61yG5LCoeoqzBdopXPy6BsVPTGdRXht95L68hj5ipump": "SANDY",
- "2EgpQxxRy6SSsXG2YDx8fEM1Z8vyDRHmPAEzSowVpump": "SANTA",
- "EhzVcKKmGjLk6pD5gLT6ZrTg62bMgPgTSCXXmANnSyQA": "SANTA",
- "7S37Wv8v9BLQ7bCBTSmCgpCHEb7ae9ZVV7YGwDSepump": "SANTAHAT",
- "HruKkLrLJ7t1kL8E6HBccSpWdUpnhGmi3SVrB9Jjpump": "SANTAHAT",
- "F9mWjEo9y7KqreRTb1pUL7UZHQXLfoUJpy431jx9imR3": "SANTAPEPE",
- "4KMGg8YFKFewZsNuRrfqgDLuR15iVtPxEPe9GyFzpump": "SSOL",
- "J8uZpXLyrmaPawRFdu81byzRSLqnurTvhQ9nd2ZLVQvE": "SANTA",
- "8NQ2HcFBw5oY9wQVrPVnZtQvmeH1atWayH72ErLP2Dcc": "SARAH",
- "SarosY6Vscao718M4A778z4CGtvcwcGef5M9MEH1LGL": "SAROS",
- "BiAQHYo5Y1umMRbuupdoksKuk6pVbQEHs8fJf8UYpump": "$SASHA",
- "EtQE3GREPyFBCU3yUXc5nWs3wRtLYuMmtKAFAvXD1yuR": "SASHA",
- "9avVfYKaWV56qnoRpe2xyDrBB3ANkHynG38VrZDhwTbE": "$SATFI",
- "tSATdGGSLYBVCrm3pXiib8NmzKcB1iUdjRRseNGssxu": "TSAT",
- "E8Cn4QEmZSvr55ZeAJwyo2r8kAX79qzdtQdFudDaZJCV": "SATOSHI",
- "EWnSZW86xhJ91nvxPjdZD3g1SqhHj7q8eqY6DEUKpump": "SATU",
- "GxihB7J6xfiLDq7iMdgj39jKugt69QoHGDzXqFYPk2zQ": "SAUDIPEPE",
- "SAVEaeeqeXNKYb4Lyx28DkUms5gyZ76vGa6fCfdzWfK": "SAVE",
- "5eGSrcRv3aXLQDfQhBFrLWU7aKvUD5Zra1fn2oSq6dns": "LUCY",
- "2HHgCLfKA5Rd1Fn9xAxfYzS3XoR5NnuxKDYz2EmWpump": "SBR",
- "8FA3TPf84h9gEZAxDhiLkMN4vvZcdEUZxmGadbo12auh": "SCALES",
- "9mNjA6BizTwpvd4DS3o7BjwZ6aPM9DC2jLHS7JFGbonk": "SCAM",
- "3XktN2eZiv5g62qSQ3bbTjTefSxrPjde4PyKDtcRpump": "SCAN",
- "8sWKTMrh9bWUrvykK4H3jzEzGbEqvJNpS2f7joYKpump": "SCHIZO",
- "7x92Nt2kegSizDxoXvU6ApciGyGrtqp9ykyhUWoppump": "SCHIZO",
- "m1nd2qK91tpBrmX7yREJBc6D2fJ15kfiU9cdvxsSN6x": "MINDS",
- "8ELspwRkgbz122WrdaX6pfHspHnLFU51jAKuP15cpump": "SCHRDNGR",
- "4F5VG4QNMMhbZURpqdvjVkKERtD9KSuf7kPEbAd8pump": "MAYBE",
- "XsWAnFM77x6YvpdaZoos79R12o4Yj4r7EVkaTWddzhU": "SCHFX",
- "DRVM9vP5coW4WHsNv1kajhn55duyuua4cJ9NGkSApump": "HELA",
- "GxdTh6udNstGmLLk9ztBb6bkrms7oLbrJp5yzUaVpump": "SCIHUB",
- "2MaFszzCmpJqYPjVXsNytmiHfgckWbtBVq4WSoxjVGkf": "SCI",
- "4TcqMXdZBjxirf2vtYikWt1ix3YoHJoFAZwrqe39pump": "SCOOP",
- "J4fQTRN13MKpXhVE74t99msKJLbrjegjEgLBnzEv2YH1": "SCORPIO",
- "GLPdQwGtjcynj3RLraenPeR9v1REnpdyuciPBpVipump": "SCOUT",
- "6naWDMGNWwqffJnnXFLBCLaYu1y5U9Rohe5wwJPHvf1p": "SCRAP",
- "3GEznP41VaAGv9yRdBiuYdA8zkffNc8b7DzNJgFbH4Kh": "SCRAT",
- "7qBKePC5SqZKDRNsbNhqD6Y6S8JW2CM3KoRv3ztDpump": "$MAMA",
- "4u4w3Ey8ewYw7pZWyUH6kaGf7pUx97KYLp3tnFcEpump": "SRC",
- "Gwf6QBR2aFypdUAfGzRnog58YRyQgeGtmyx6FBFUwLfu": "SCRIPT",
- "E2WYCGJJtWBodVLy1NKcN8ve4UAtsJJBU2mdErbXxP8h": "SDOGE",
- "5qKDWkBejLtRh1UGFV7e58QEkdn2fRyH5ehVXqUYujNW": "SCOIN",
- "EXtprP1wzrNo2bByrU9JyzqEg2hQMSCVJakeHHYondo": "STXON",
- "4p564NQcgjNMyvwjeqivB3XGYtxqHCxvAsyvxybMpump": "SHORSEPRO",
- "BKQwzUrcibzZsm1Sm9TVgzxA9G7bAYszCaGJcALMpump": "SEALS",
- "Fxgdfsy1Z5Mvh53o69s2Ev6TGxtAJ1RQ5RJ5moCpKmQZ": "SI",
- "9n7PCZLVMG9sEViRwz2cmaR4eM72R3ekWuBdEzZppump": "SEAMANIA",
- "5MVAy3tHAi44mY2tz4ghqs9T6XRZhDwTMjhdNtjtpump": "SBTC",
- "GFJbQ7WDQry73iTaGkJcXKjvi1ViFTFmHSENgz92jFPP": "SECURE",
- "5Kh2xc7X2qfRig2DZyGkuEXw7jeXUXoei7U6GBjfpump": "SEDUX",
- "6xmo7F4DgFWd2q5xqn4vRqnmP9qSe6Ar3bsNM63S4exn": "SEED",
- "FYt532fCsCuoHd9aaX5QN7pZLUTiSXwEjhBmZijgBAGS": "SEED",
- "Es6h4XKewn9Mr7V44VqQ5cAUPRY6uV5hhD4vnEZhgoQ6": "SWORLD",
- "SKRbvo6Gf7GondiT3BbTfuRDPqLWei4j2Qy2NPGZhW3": "SKR",
- "HEojcy5TMAYZJkFy4zhSMYxwYKd22vya9y5TPrWLpump": "SELEN",
- "9WPTUkh8fKuCnepRWoPYLH3aK9gSjPHFDenBq2X1Czdp": "SELFIE",
- "SENDdRQtYMWaQrBroBrJ2Q53fgVuq95CV9UPGEvpCxa": "SEND",
- "4dPW2SdbKcTEUiHpQRTWspT78zgS98v5TMhVpGPoPLzq": "SENDOR",
- "F8tDt7QRAYicWQPK5LTh8kZR4zKJPdTiEq5dwCcVpump": "SENSUS",
- "CXPLyc3EX8WySgEXLbjhuA7vy8EKQokVJYQuJm2jpump": "SENTAI",
- "J73VLpgUiWxooiTwbQyae7h5e29kGrC5RqrbicW2pump": "MEMETIC",
- "SENBBKVCM7homnf5RX9zqpf1GFe935hnbU4uVzY1Y6M": "SNTR",
- "8GrhA85mcgnaMjyXZ8Hdicayu7byXxbKyEd5UjLnpump": "SERALPHA",
- "H9PPCeNYmUZVRQgDtBLnhGoSxCTB4CsJgKvyL32gpump": "SPT",
- "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt": "SRM",
- "G7pTVoSECz5RQWubEnTP7AC83KHUsSyoiqYR1R2ondo": "NOWON",
- "8d4D4FGUrbtTDucywowRD4AnizRKCr1YZaYQ74bRpump": "ANIMAL",
- "BHvPQ9dFAiZJUSYJFpEmdfMmgz48iLohyxyixBfZjups": "SHACK",
- "E514tLEAdmGFkxwnTA2WMxpMTpqmXASqgRRsrGwCpump": "SOS",
- "3c3SsHJnfqCs3WnbM2dBJeNFowcVJDWBfpJExumbmoon": "SOH",
- "6WEsL1dvUQbTwjtMvKvZZKqv4GwG6b9qfCQSsa4Bpump": "SHADY",
- "R6jVVLcdfpZ7tPLHQXZ4uZRFhBcE2L6aQoPgiJuV7j9": "SHAFT",
- "7f9USKiLfbksTfNt6yrF2z6bxNDQ4FRKni8rSEd4pump": "SHAKEY",
- "8D1nUMJQam54o34Kj2knFhSTaWoehEr4mBc7LfiDdCqq": "$SHARBI",
- "E6Eg7Esj5tfSwkbDGdrzhrotqptv7ghJNarLZ9rbHDSG": "SHARE",
- "6D7NaB2xsLd7cauWu1wKk6KBsJohJmP2qZH9GEfVi5Ui": "SC",
- "6U48jtR53ZK3E1MozLrpwJDTrtj74uuFhMGNzGY18YPu": "SHARKI",
- "6CRayr4GnspC1GUDLs693oPk7AoDSXLXSx9kskgupump": "SHARK",
- "H538xSX3ZzVWW9gq9d2Pz6m5eumPwDGvGLarKc1Hpump": "SRRL",
- "SHARKSYJjqaNyxVfrpnBN9pjgkhwDhatnMyicWPnr1s": "SHARK",
- "iLDu2jjp2i3Uqc2Vm7K7GLiUj3hR4Un49MtD7c4ondo": "SBETON",
- "XsEoih2x6nZuUjFwzGoba6MFmtzCkzW2c4YAm6baQbq": "SBETX",
- "2G4RMDbXu79f5Yff6fBjKgXknuGvrFCr7iYmiTKy3fVc": "SHART",
- "GtPhXAYvP3hmPJ1QSkn4Nu8ajgnuh2RXMdZYugHWtime": "SHAWW",
- "Efrq2YCpuB6HdnTSbNQRnNoYXW2xLYhV8RB8KJ2RY5Cn": "SHED",
- "9hdynudAhhWzuNFAnpz7NjvdKMfh9z8mcZKNYHuAUgJQ": "SWIF",
- "DhteZLhKP6xPNcHVtdYvcE5FFcPN5smU7pxJw14Cpump": "SHEERLUCK",
- "D3RjWyMW3uoobJPGUY4HHjFeAduCPCvRUDtWzZ1b2EpE": "SHELLRAISER",
- "9F6VbPeM8xR9Nkntyjp5nPY52w9YG9331bLuyhe3pump": "AKA",
- "836AY1nD2RrtbYYUqoj39JPTzCwcehrq4M5pvFiPnKEH": "SHIBAAI",
- "CiKu4eHsVrc1eueVQeHn7qhXTcVu95gSQmBpX4utjL9z": "SHIB",
- "BhPXDQio8xtNC6k5Bg5fnUVL9kGN8uvRDNwW8MZBu8DL": "BANA",
- "3UYS3XXYC9yWvNyBWFKqqb5w9YQfX65RQzoAKd8jEUCB": "WING",
- "J7Dx5yPbPD5e5BmrSvJyi4n4XRUR2kWqWYaxaSWdpump": "BILLY",
- "7wz31sC5z979UMtiqrtxsYYQ6bJzpjUTgPsZvXuZhso": "SHIB",
- "F6qoefQq4iCBLoNZ34RjEqHjHkD8vtmoRSdw9Nd55J1k": "SHIB",
- "EWqZaPfYg4iGBdHMGYSUDyTgrRrqZhjTfm1DoZmTpump": "SHID",
- "42ZFYwLMMbC5fNbbH641PgXeaEym5cJrmnAVho5Hpump": "SHIELD",
- "8K7EdeRNW5YbmmCKvAUn4qa5j7Ggz4iAAZbhnoHJpump": "SHIFT",
- "2NUEQdSpFFGhssmT9LFUn67gAucyajmgscT7zsizpump": "SHIFT",
- "4Q7UJpgqrD51Y9DuJjeKuVnEmanJTbqPRGazVsUZpump": "SHILL",
- "6cVgJUqo4nmvQpbgrDZwyfd6RwWw5bfnCamS3M9N1fd": "SHILL",
- "2xP43MawHfU7pwPUmvkc6AUWg4GX8xPQLTGMkSZfCEJT": "NINJA",
- "D8FYTqJGSmJx2cchFDUgzMYEe4VDvUyGWAYCRJ4Xbonk": "ROCK",
- "7hhAuM18KxYETuDPLR2q3UHK5KkiQdY1DQNqKGLCpump": "SHIPYARD",
- "FuJkw2vgov82x8DXbhPfmH6S6ZSJxvtjj1DQ7TsMpump": "SHIRO",
- "5Xf2LX3aVf1EAwZzEp848qox1PRpjALpYuVNar4KK3zG": "FROGDOG",
- "wzpeUomX2VNiswbyYMLqYsdN4nNFZSobNs5xuR7shit": "SHIT",
- "42PZx7bPF1EMnP9L7vcjihTx7Nryxh81GG9Xs6fdpump": "SHITCOIN",
- "CG13NMFvwJcDY5hzkpBDpGeB9HGRsLz21tk8vkA9pump": "SHITCOIN",
- "D3kLDyQRt1QcGi2RXchzKoBuZXm2L2MUjrmNueYGpump": "SCREENER",
- "4nswj3o1Lo9iWYvvRJxUD8vbCy9ay7QQoXYcncHNbonk": "SPSC",
- "AFbJW5rdaGidnF6o8ZqTtkDBpq3fotSBdJN8fGRN3VRS": "SHITZU",
- "EBCqxfSMVSJPDGFLcf2yAfQoeLJRD1z8VbEUemZSbonk": "SHIYO",
- "7WASM3L3bkzh1yKSTepguojBFAdmK8ucQjy4DDH5JF97": "SHMEEGUS",
- "8XVXzmsMMw7ufa8RC21fHcDP6TGti5y3ZidQinnYurqr": "SHOE",
- "H2c31USxu35MDkBrGph8pUDUnmzo2e4Rf4hnvL2Upump": "SHOGGOTH",
- "55KDFPScqeshiKrRENKvncD238n3k1SZqLd7ne1Upump": "SOK",
- "ivdDracs2s7jCP698dJXKSEQdVrNj9hasJL1Uq1ondo": "SHOPON",
- "AEDEBKCEkxHvFx69vKD8EmZ7VqmhAqobubfgMt32pump": "MORE",
- "7YFs3oLBEqJffu5VjByokYUTJYRdFrpEFtRngji4LyxS": "SHREDN",
- "BiGwCbrNetFGJYZMRJiPMEo3vf5XnLp7ibc1CtmuQGW4": "SHREPE",
- "9QMwCyTFDRvPZF14hFHUP7fdiewf1a3PQeP4bewYCLJV": "SHRIMP",
- "rrNNJPsVnmhgHR33oXSEstjsKx9mfb4Vim4MuDtpump": "SHRIMP",
- "H7ECjS1wfWoPCffZR9KVo5cvYbYdnhaBQoTwdXhpump": "SHRIMP",
- "xyzR4s6H724bUq6q7MTqWxUnhi8LM5fiKKUq38h8M1P": "SHROOM",
- "Em8WF6pg9FmKDy1dXkWhXxpgmfhj5Bes3ZCE8PCCJSHt": "SHRUB",
- "GN78Djb7J2xc2ZLZaJLoGoF8FU6x7DnK3kUJFsnDpump": "$SHRUB",
- "7d1vpt5eri79nETcL74Punhp3mGkeBgUkMdPWep6pump": "SHY",
- "EjWe2SsM67WzK65xQA6WNwmxZjAnHKLzHFzG6boLpump": "SIBERT",
- "7c1GCNc23CmoYVGcETxR2UN6F4dfsHh2WmCEBLUTdNrp": "SEC",
- "ERpDpYmuifJUKbaB1Dv9hnJ67RM21Jujmxz18JCeDzbr": "K",
- "7JcJLMzqaZNrtc3E2YCp7L1txL2kkYHv5soRTsU4pump": "SIDELINED",
- "9Xi7yxDt5oxMG7b66nvbSiNvf7EaA4M3RGjzPmcRvgUk": "SIDELINER",
- "8ggbc72zhyA57NdToPZ3DikcXxkS8hnJfdfZVtwLpump": "SIDEX",
- "5w3wVdJaESaJKyLmStM6Hv9UyUkmZ1b9DLQquAqqpump": "SID",
- "5SVG3T9CNQsm2kEwzbRq6hASqh1oGfjqTtLXYUibpump": "SIGMA",
- "4N5jkEmddTxtZQzjb4XowDJvHDzcxkByxMAf9Xa4bonk": "SIGMABOY",
- "5ad4puH6yDBoeCcrQfwV5s9bxvPnAeWDoYDj3uLyBS8k": "RIZZ",
- "D7qqKEr7JFpAd82m9nvJL2psdPmU1oW54g1LHvDUYFAN": "FAN",
- "J6Zh9N6AKkFySTpQD3wMbpoetPpwohvuq5YgVWKvpump": "SIGMEW",
- "Bzr4aEQEXrk7k8mbZffrQ9VzX6V3PAH4LvWKXkKppump": "SP",
- "2QRjZ12c9JDeoP4LRK1RnWYNeaWFXVFUYag2x9iGpump": "SILKY",
- "AXMmTn2bGH6RWdos2fUmXsFLhN4LkPjGv9V4BdJdAync": "SILLYCAT",
- "7EYnhQoR9YM3N7UoaKRoA44Uy8JeaZV3qyouov87awMs": "SILLY",
- "GRFKaABC518SqXMvBpAVYUZtVT3Nj4mYk7E7xU4gA5Rg": "GOO",
- "GtDZKAqvMZMnti46ZewMiXCa4oXF4bZxwQPoKzXPFxZn": "NUB",
- "4iipXQQRDGSYcMXa3rqpn5qmxNXEiY2XoLixaVEsGqDp": "$SILVER",
- "DVguBpgnixDwVcM654YiaLCMNiY2cdUYJXJK3u9Gpump": "SILVER",
- "eQoHHi5TygX4sQ28JPtGM1XpVVvczyVs4bpdoSPpump": "SILVERCOIN",
- "7C56WnJ94iEP7YeH2iKiYpvsS5zkcpP9rJBBEBoUGdzj": "SLVR",
- "FFqwoZ7phjoupWjLeE5yFeLqGi8jkGEFrTz6jnsUpump": "SIMAI",
- "EMeugag3yfyvKqNKknGDWAudNALafZjbv9ByzCE8pump": "SIMD",
- "6Nf3nFbyQ1p1CVQYtEZXfeM89XyvkFPyF2JosxdriH7S": "SIMMI",
- "5NmDofUfjrAydmLGRyXrbiYRDZ2LhvdEG3jLWHUTpump": "SIMON",
- "3joMReCCSESngJEpFLoKR2dNcChjSRCDtybQet5uSpse": "CAT",
- "6zsNXPkpGHaf8p71wThVTxr5fhtG8yKHw2TrkiKqpump": "SIMP",
- "Chsqyzk3S4uaFdajsQNMp2FnJ4rQMzTd3ykvwyycbonk": "SIMPLE",
- "u6VCRrFvejYX8cTnc1ptZT8UqVGbPXPmE8kvcGnpump": "SIMSAI",
- "G9FwFW4KzzNGzA18BgWXxmiXfhFTEjdKHCt6bGWKpump": "SMZAI",
- "p1ZwX2bBUgojd4CQQRC2RL4wof9xxWaXqguTQFsSiNX": "SINX",
- "J1rfosSdRqBbpSegRpCtMQDxDoVsYR41zMywoXkNYiKB": "SIS",
- "51XMD1jprfRvd1dbPZLkBuef6xMduwjrmSLxyYiqpump": "BEETLE",
- "8GobyUWTAhePKa5Pxrn8qivvRXq1pjtBzRNERRtDpkin": "SIX",
- "HqLRjru6pD6GFGnQ7TwSSGQRuPhF8UZNey9T4yCsZzuq": "SIZE",
- "4Qur8tvJG195EXmhsuPvpa3qmMiAugtbDaoGwVGV6oJD": "SKAI",
- "9v6BKHg8WWKBPTGqLFQz87RxyaHHDygx8SnZEbBFmns2": "SKATE",
- "8NKJze6oUVRpbpk3TaYHv2se57fv54qMS38bRtnEZqYM": "SKATECAT",
- "12MFXb5CGJ65S3mP3s4eMLaosGp6xGnQe3PxQD38nfJp": "SKIBIDI",
- "DPaQfq5sFnoqw2Sh9WMmmASFL9LNu6RdtDqwE1tab2tB": "SKBDI",
- "7crBW2CjnJGm56UVS2VRQydPSUyAcKkhRbM1F9kDpump": "SKILL",
- "3DFnwGLJUfxc4eMxDgQwW6oWaeKBrJ1iwA26YjTfpump": "STKR",
- "3F4aTvvQBdtWj672kNYRenMtMG4jwQE63redg2cN4tCm": "$SKOL",
- "79EhLJ14QzGoN1DzKzMxG4DcZeQ6H13AXVLvYxuLpump": "SKULL",
- "4fVm6TbqF9SUhVxWr2S49UkNTwUgBjQPQG95K9oeKSKY": "SKY0",
- "95WzV2CsTRFBjPCBhQRR4TGVp5kXo8f8qZVt7iVwpump": "DRONES",
- "EH2tRrNn2TfD2c1vNLMrNaxa4wskzEnzb1Vo5YDRpump": "SLAP",
- "8npbXTu4oTNw3xrMGY1aTm4CtB7cMPVuRUCh3Wqj3fSW": "STACKS",
- "Bk6oLMgBNGJKFCCELjjydMqQ1igunsS7y1ZpDDzGbonk": "SLAY",
- "5mXL4MPYzSgbKe74Ufpw3xgxtzPmch54wSdYUR4dxZSi": "ZZZZ",
- "4SngaZ3N9ELjCqh6P3MeA3r4Hi2Dx1MDn2H4ijcDbonk": "SLEEPLESS",
- "7BgBvyjrZX1YKz4oh9mjb8ZScatkkwb8DzFx7LoiVkM3": "SLERF",
- "9999FVbjHioTcoJpoBiSjpxHW6xEn3witVuXKqBh2RFQ": "SLERF",
- "7okHmAi1re834jSp2kAdduML9a1RfZ5fQJfQ878k8y7g": "SLINK",
- "TNh4HphGRorrjLFztWq1ekJakVeWPmLnzymGCE2pump": "SLINKY",
- "FqvtZ2UFR9we82Ni4LeacC1zyTiQ77usDo31DUokpump": "SLOP",
- "A8YFC9X61bz9SCbmLkccitqM7mXqqHKN2hBZx1Y3pump": "SLOP",
- "AkdtuaKVDpsZyeZ8LvcVf4G4L3nJ1Jmd7npmF5mpbonk": "SLOPANA",
- "HephxhDavKo6joaqQe7ELo4cu7r636f8RXFgg7evBAGS": "SLOPCRAFT",
- "EWWDzCwq4UYW3ERTXbdgd6X6sdkKHFMJqRz1ZiFcpump": "FATHA",
- "HQ7DaoiUxzC2K1Dr7KXRHccNtXvEYgNvoUextXe8dmBh": "SLOTH",
- "C3Tqmrgp7oKE6x5TmZaig5nVV4EPnQcw2BZyVRXboop": "SLUB",
- "Dor8frTyjvgrok3zg95PzVHxnJTKyUP7tmL2Pvo8pump": "SLUG",
- "EPpeesRbnZSpe6nJaWSQNyhqrwyjGJPh4GPrzBvkpump": "SLURP",
- "7jFfNTP8gBEaXjXoZt3ejJfiT1W87Z9e3mkeYNcEpump": "TOOTCOIN",
- "9dzSzFvPsKDoY2gdWErsuz2H1o4tbzvgBhrNZ9cvkD2j": "SDEX",
- "55PbiW5TQ9QqcyJN4rUcZsigBhAkBwV1YcGfyAjSpump": "CASHTAGS",
- "6gdDALVM7FrTnXTXo17PpHnLtUdnaAtokCBzPUZKA2rx": "SP",
- "HPePUpxriuXvUYkm9qUn1CaQeN5Z7yNL46XUTytWthvm": "SMRT",
- "6tVZVjcppH2BZ9Xj5yFU1Zt34m2rYcyDqqpSeMDZpump": "MIHARU",
- "FS66v5XYtJAFo14LiPz5HT93EUMAHmYipCfQhLpU4ss8": "SMOG",
- "GiG7Hr61RVm4CSUxJmgiCoySFQtdiwxtqf64MsRppump": "SCF",
- "GPqgnQ5xD8oPGT2aN3bZ467EHmDbEt7aRhJuUQGLpump": "SCF",
- "9EL3CHVQS3nwUFhyVT7AGbttRsbJ5UE8Qjnw5ZAtkUhr": "GRAF",
- "7XdCaKpqLmKE2K7yr9xaeWB1H2CVZ1oGwxB6hmd9pump": "WIZARD",
- "E43qU77tnWDwN11o7TtaGMNpxCAqz8RZEZ7PcTCUXSim": "SLO",
- "GjCqkMr8uvYibgummgXXcrD7jtxUQ17Ljtr8uo4zRULC": "BUN",
- "3aTpfof6xw6GZAxKXFdX4fGn5BBK2MXdPT8rS4WUpump": "$DOD",
- "9Ttyez3xiruyj6cqaR495hbBkJU6SUWdV6AmQ9MvbyyS": "SMOLE",
- "FhJkSagsyn2mfXXypYJDB9S9CiYXfzMtaB5bbfevpump": "SMOL",
- "Zc4uJVrHC2APe9qKwBD11Gg4BbvQr3naM8f7Wiopump": "PEP",
- "8D9CZBsMocuJ8bdnpegGE8auHdFQ1Ez5F66wWAFv3WcN": "SNAKE",
- "3kM6vNo8WeCd7DY3EZBjPuFQ9h8gi3Bm5T8rFPQq1WBt": "HISS",
- "FuvFLtx68uGjhr4GWET8JTskC7s3R7MM4Feg8toyzFvf": "SNAKES",
- "5EdKas4QsHaa71QS1X98wiCTgJCCVMjw5GhY5QMKpump": "SSSSS",
- "ELnAjNJJRBaG9MnnZqUXLsbBjkVA19szcduNeD5RCqdo": "SNAPCAT",
- "4G86CMxGsMdLETrYnavMFKPhQzKTvDBYGMRAdVtr72nu": "$NAP",
- "a2cXfonVgQ6cKB4Lm8YZsPry39VZSA562bwmRSiondo": "SNAPON",
- "8oCRS5SYaf4t5PGnCeQfpV7rjxGCcGqNDGHmHJBooPhX": "SNAP",
- "CraBDNXPbbJtfPKzmCnWt667pueqCEqSuWYaFNm8JSX8": "SNIBBU",
- "4oaV94McVveRosSgdZTn3jkMpr1ge7SQZjwBZ7xG6oA7": "$SNIFF",
- "D9mFkgnZHnQGRtZKvnJ44yvoLtJmfBZRahXiUKcAzRE4": "SBABE",
- "5eEJpwFtBJTn7n9f6ryWmHjkPUQQghHt4YjvtMSjEEwj": "SNORT",
- "Gbu7JAKhTVtGyRryg8cYPiKNhonXpUqbrZuCDjfUpump": "SNOWBALL",
- "8uYjdP5spMX64Wpy3i6N2W93R3v9rPiL8Dvx5Uhkpump": "SNOWBALLS",
- "JmFLCBwoNvcXy6B2VqABg6m784ubkXpaEx3p7S5ondo": "SNOWON",
- "EBUVekfZ1fbqgY6dXXSEE1KoX82mu3qgGBqaQJJLpump": "SNOWMAN",
- "8vSwZHKP5WJ8ov6awAntB31Kuyh6NYVwi3qmyZsiivRE": "SNP500",
- "4juFfEmgZDMQ8vPECCaoxvAZGt7dBs8DMXXeveu9pump": "SOB",
- "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm": "INF",
- "EsXKXmYAHgmTX1QTf7vL6V9XNrVEJz5KGntwMEmrcBLV": "SCRB",
- "DghpMkatCiUsofbTmid3M3kAbDTPqDwKiYHnudXeGG52": "EURCV",
- "DXi3Uu7TC2tzJYmnFAgDKnU3p8t6qSafPcLgGaQipump": "SINU",
- "FbJpd8yhrGGkWVL1Ujf7qFvTw4uD4675k8CYk82LEKvZ": "COMFY",
- "9cC36bMZCt9fF53eLBQCago1czw5L9GRHZBL5adWEyAu": "SOFAC",
- "mqL8yXQpeSvc7NgrAtLLPtRvUiWyLoG5RWLv16iondo": "SOFION",
- "6wYRTqoERmtRrWmsSCsTcLjNavdTMgxjmVhTEuM3S2tW": "SOFTCO",
- "GTc5QQbZSf7W3CpvwqFkWXjPwRhYds8R8iJyR3e7pump": "CODED",
- "HsnyqiEdMVn9qsJaj4EsE4WmEN6eih6zhK6c4TjBpump": "SOL402",
- "B5UsiUYcTD3PcQa8r2uXcVgRmDL8jUYuXPiYjrY7pump": "SOLA",
- "8agCopCHWdpj7mHk3JUWrzt8pHAxMiPX5hLVDJh9TXWv": "SOBER",
- "2NiJ4Jn3xBFczAqnYFKc6hEKdAmp5xD8BeBVCB4Tpump": "$SLCE",
- "5vXq6Pb2n91W243XLSARY7GtUMcomr7TwfKPRY31pump": "ZPAY",
- "HTPHknF5rBNCuZ1qK3muJA6Yo1HEhZj722oSESJnPBiw": "SOLALA",
- "AVLhahDcDQ4m4vHM4ug63oh7xc8Jtk49Dm5hoe9Sazqr": "SOLAMA",
- "CUwif1FiX5b3bwwb2n5Bm35AixvnR8LJjGUVmEwNZNgR": "SOLY",
- "B4iCbe1rhMWE5VhH8nEEfgfyn3FFiNmnGahPVqw9ZBpp": "SOLAMB",
- "5c74v6Px9RKwdGWCfqLGfEk7UZfE3Y4qJbuYrLbVG63V": "SOLAMI",
- "A9fcjKEw9r4e9b7ATbM6Bk3LbX5jGeZt3WxrmfMRnzDw": "SOLIGATOR",
- "Ho2FQgg65oM1zpYuEnC8fULpBnWtqRCTrXRP56AeyCci": "SOLANA",
- "GbbesPbaYh5uiAZSYNXTc7w9jty1rpg3P9L4JeN4LkKc": "TRX",
- "84Y6h6XoaLAD1zxoQ2CDhcZYRpNsSBKsXULCnpjXpump": "SOLCAT",
- "2BeGjx5eYHbGqT2kUZ7K3TvsNGBc65xvorcMqL6kgefQ": "SONDA",
- "6DSqVXg9WLTWgz6LACqxN757QdHe1sCqkUfojWmxWtok": "CORN",
- "DEADsWJZaonaiZPFkrqEEBGf43mzA5uHeHpwgy9dW666": "DEADS",
- "CxGSt4aa83QQcxjpP9oi3pc9roJYJCQcH6UEczkxREKT": "REKT",
- "J3mTHLJ3GMcz9ycfvUji5HzeuTvmUQjQSdzChsS5pump": "SOLBISCUIT",
- "HUBsveNpjo5pWqNkH57QzxjQASdTVXcSK7bVKTSZtcSX": "RASOL",
- "GWcAPiF2cBf5de8E1eSERcnVdH411NqT2peG7zDJpump": "SOL人生",
- "9vHizhLqqpTEhVduy12qL6goNMa4GDguLhhiiDKRpump": "LUMIO",
- "ELm7r7k1ZAZX3up6gus1p2s3mon845rdVP1aJoN9HfEP": "SOL10",
- "B9r1YcdKPg6AmTb4RaFJtucjocozVKJ3gpAcRp7PQ6kE": "SMG",
- "BVJJWHJuRLQtv7J3Qn5hMxtFYjywZEgvqorS9ZWngem": "LOOP",
- "SNS8DJbHc34nKySHVhLGMUUE72ho6igvJaxtq9T3cX3": "SNS",
- "6VHL2vMKgrF1YQFSv29Rs1pj9VCRK29bD11NtDqerqHA": "SSHIB",
- "H4phNbsqjV5rqk8u6FUACTLB6rNZRTAPGnBb8KXJpump": "SSE",
- "FLJYGHpCCcfYUdzhcfHSeSd2peb5SMajNWaCsRnhpump": "STORE",
- "4fUuhtxuqpkonfEAChooeLz4SwB3qqbKebSgLZXapump": "USX",
- "2EyNf2PCNT7eQ9ag1RDXw3qn3Cy22WdTA9T6HKDebonk": "SSX",
- "C2KG3gB395WfE1P8ZhUvoT5ZUXzQEJst4FCgLAYTGACz": "SSB",
- "6BQjp7nPMZNkstxdw2UFH1gf76cGmNuR3bTmSbgxpump": "SUMMER",
- "HDa3zJc12ahykSsBRvgiWzr6WLEByf36yzKKbVvy4gnF": "SOS",
- "De4ULouuU2cAQkhKuYrsrFtJGRRmcSwQD5esmnAUpump": "SOLANA",
- "BHDkUqS5cdmjnXeGPWvbsfMoRbqPeDr9gPf1yK8xyLiG": "SOLWARS",
- "2RfXjaiepngcBuGgPLtdnH22g68eetpgzCDX44Hnpump": "SOLANIANS",
- "xxxxa1sKNGwFtw2kFn8XauW9xq8hBZ5kVtcSesTT9fW": "SLIM",
- "6AiuSc3pYM5rpbKPq8JfSQoMoUsfDpzvP5PmMSEKpump": "SOLANO",
- "6Qd6mmFR84jzg24S3851TWNGeTTFrfPko76UiHyRMDMT": "SOLARBA",
- "EAwP9LGNjTkQ2YeKE6CGKqBYtrJ6APFvRe7KCMmondo": "SEDGON",
- "7rhhtc2DTTAsPr9P3ZRqUjYZESRj2B29L6qrEXG4VLkh": "SOLAREUM",
- "3RfQPYVJgJbwyB3BzqqypCEWWryxjTfFDAcXQsckpump": "SOLARIS",
- "8EZqVPJdEWt754S17nghfa4Y4jQJ7tigBwsGbo1Tpump": "SOLARIS",
- "GNJrBUuUnExsQYBAFy22Hw1qSmSJdWEgy8VawAn3uzUb": "SOLAR",
- "SAX2cChnuhnKfUDERWVHyd8CoeDNR4NjoxwjuW8uiqa": "SAX",
- "SLAYg2S24PSaBc2Bs916E4PPbpiwNz3YmngLG6EKAc3": "SOLAYA",
- "LAYER4xPpTCb3QL8S9u41EAhAX7mhBn8Q6xMTwY2Yzc": "LAYER",
- "sSo14endRuUbvQaJS3dq36Q829a3A6BEfoeeRGJywEh": "SSOL",
- "susdabGDNbhrnCa6ncrYo81u4s9GM8ecK2UwMyZiq4X": "SUSD",
- "25p2BoNp6qrJH5As6ek6H7Ei495oSkyZd3tGb97sqFmH": "SOBA",
- "2uRFEWRBQLEKpLmF8mohFZGDcFQmrkQEEZmHQvMUBvY7": "SLB",
- "BLZEEuZUBVqFhj8adcCFPJvPVCiCyVmh3hkJMrU8KuJA": "BLZE",
- "4nFwuKievw5wcpcXtUDdfxWLyXsEdvgkpENzC9M9Y5me": "BOOK",
- "8a5NY9MAdY3NjKsgPUYfqoZcmGKdZkotrjWgZM1dpump": "SOLBOX",
- "b6tCZBBD21dFxa1R5tULY1BdJkxCserENFyvseWpump": "SOLBOY",
- "DLUNTKRQt7CrpqSX1naHUYoBznJ9pvMP65uCeWQgYnRK": "SOLC",
- "SCSuPPNUSypLBsV4darsrYNg4ANPgaGhKhsA3GmMyjz": "SCS",
- "A2TjztayKEavSCR7deVs6zkKGLP155pQv3j8ByVJ2WLW": "SOLCAT",
- "3WKzqdh3ZW3tP2PhAtAuDu4e1XsEzFhk7qnN8mApm3S2": "CAT",
- "AMjzRn1TBQwQfNAjHFeBb7uGbbqbJB7FzXAnGgdFPk6K": "SOLCEX",
- "947tEoG318GUmyjVYhraNRvWpMX7fpBTDQFBoJvSkSG3": "CHAT",
- "CTRLb9PmyRL2fQZ4amRKw6ydJXbTLc5LWvw83RqyjxBk": "SCTRL",
- "gr1qPTo3tpMAxt59BftQo2uSfRHRuUZJaWLhR8ADtwz": "DOCS",
- "8ymi88q5DtmdNTn2sPRNFkvMkszMHuLJ1e3RVdWjPa3s": "SDOGE",
- "3FG9DAv3CDBEh1CQJhRM9BYe5thUMvP5GmW46524Qahv": "DRAGON",
- "w131jbryFvFEmtqmZvx42Meiuc4Drmu3nodTdVgkREV": "DRIP",
- "GUhVUdAgT2VPaDL9EtCTqBptX8ENrgs5WqR3c8EJpump": "SAI",
- "SLNDpmoWTVADgEdndyvWzroNL7zSi1dF9PC3xHGtPwp": "SLND",
- "2wUGjvMqXusgfzYP3Vj149bSM9MwTPLS4maxkdGfpump": "SOLENG",
- "TuLipcqtGVXP9XR62wM8WWCm6a9vhLs7T1uoWBk6FDs": "TULIP",
- "BjBzvw6VX7UJtrC7BaYLG1dHBiwrXP1T9j2YfDEdP4zU": "SFARM",
- "948H4FquubpPQxgeYxoo8kiKU12qtRuon8ccnD9r222a": "FILES",
- "CrUT8HNd1wi2hPqjTkADC7qUgijwNFDDWR9CW5NsHXvv": "SFLOW",
- "BLiUhfaUFbSoMVeRqq3QYTA1eJsTsB3ZDEYtUsGGQ9em": "SFG",
- "9HXewqNjkHz22AKds3JUzFBNguzhoH4cJ4h1EksZyPGH": "SOLGOAT",
- "3fcZGkXf7xK4pBAxiyK13DXTC9x3cPxHE998YUbGuS85": "HIVE",
- "METAmTMXwdb8gYzyCPfXXFmZZw4rUsXX58PNsDg7zjL": "SLC",
- "SoLiDMWBct5TurG1LNcocemBK7QmTn4P33GSrRrcd2n": "SOLID",
- "BQo1usUXscfXrECeYKp6PxaMfvjns1XxFSwRnu5HK1bu": "SOLIDE",
- "HBB9ZWZb8CFLrTB1ZV4xFuvmubwsCPAjZSRzFuVPpump": "SOLIDENT",
- "FUW4poh6s7uychceF8u1mo7NS65vzjX5vmS7Yi7GYQnz": "AITECH",
- "72Sp7QibTt8vWoHzvJQ6QA1Pp6UuNjCtRDBdioVSpump": "S100",
- "XLqNprqfebg1Qkn9ttjHv7rM9g5JkvZoyvo5Lx9pump": "SOLITO",
- "2AFzzF7EKDygNJ2VthGWNSftCthpSkTmqSg9p8bFsend": "SOLJAR",
- "8RZnGj4hdcai1HB9KMr1ZEUwPpWRPKQDduUxLbnnVnmq": "SLN",
- "Eyc4ozMWwUxBUTK61MTjzLBjSWWWNqqc8sjTF3Gfbonk": "SOLLE",
- "36CEGUfsUU6XXPHPXi62NKXoQ438qN8o1EZM1dgm6DFP": "SOLLY",
- "C8cNX2D1y3jqKpMFkQhP1gGbfvTEdeckZXLBKSN5z5KF": "MAIL",
- "FEhfph34VeoCfkuiNnv89pEGPiGPukWfhrKtLko66mvj": "SOLMAX",
- "BNT4uhSStq1beFADv3cq4wQAVfWB392PjAaxTBpNeWxu": "MEDIA",
- "7okSdfc6YKv8ouWaWdPEyHJcNBuJZw4QwPzrah8NNi8h": "SOLMON",
- "NAVsy3R5W6WzhZxKzPc8PZ3r4hmjTd9XBYyfYeUrMNL": "SOLNAV",
- "DeaKMzAeZja3Mh5okZE6WUvygLP3Lfuvm6Rg78HqXTz9": "SOLNIC",
- "SoLo9oxzLDpcq1dpqAgMwgce5WqkRDtNXK7EPnbmeta": "SOLO",
- "B5PucY1LAe9WA6Tsp8ACnqw2ofWbDxyKZxiin11ha1QU": "SOLO",
- "Ex5DaKYMCN6QWFA4n67TmMwsH8MJV68RX6YXTmVM532C": "USDV",
- "J8cKU4pD2NTSovvV5XghWHQiJy5TTEzgSyozorxz6ax8": "SOLO",
- "HJSnJaQv3u4ZyvPXiQPTyBsYJpggWsZvVH8yedjBpump": "LOTTO",
- "29xJEmh5sMo2DqapmcK7UardZP4B88qJZCZ2BGwa3mJ7": "SOLPAC",
- "GfJ3Vq2eSTYf1hJP6kKLE9RT6u7jF9gNszJhZwo5VPZp": "SOLPAD",
- "BDHqX9YfJE3M6caox3obUX5YpWHz2cjnGFiZJtRghdCo": "SOLPAKA",
- "4MeqZ8v3XbNVVX6B69XxXaymoTX6DbK8iZgaGngCbonk": "LOLA",
- "3VW31dwix6k2EdzhDgZ2zB15J7FbHYQwAUqXgktRcJEX": "SOLPUMP",
- "SLRSSpSLUTP7okbCUBYStWCo1vUgyt775faPqz8HUMr": "SLRS",
- "SNApmcWQqj3Ny2YFkQmkELQnNgaXRu6KmnYSPiFZcLn": "BLOB",
- "EYw27YGciv1KYbt7nSpJJZMYmg2v7vgkWpZbC4Pbpump": "SPL",
- "3ThdFZQKM6kRyVGLG48kaPg5TRMhYMKY1iCRa9xop1WC": "EUSX",
- "54jVZGHyWURX5evBtZqUsJjwoKzcZJbVokDU93AUZf2h": "STREAM",
- "HRNDGEd1vDAQwgAU5XftdFFmbRVWSnJBp8rKvAvpump": "SOLTAN",
- "jk1T35eWK41MBMM8AWoYVaNbjHEEQzMDetTsfnqpump": "SOL",
- "2x8o3hA5S5fBxCSE9hzVTf3RohcMWHqkDNKNEPuzprD5": "STBOT",
- "2qT8JVotQ2C1gKbqpuqNatkpSBWxiKHbXkCyTqH9pump": "SOLUNA",
- "SoLvHDFVstC74Jr9eNLTDoG4goSUsn1RENmjNtFKZvW": "SOLVBTC",
- "SoLvAiHLF7LGEaiTN5KGZt1bNnraoWTi5mjcvRoDAX4": "XSOLVBTC",
- "SoLvzL3ZVjofmNB5LYFrf94QtNhMUSea4DawFhnAau8": "SOLVBTC.JUP",
- "7aWQoyfAxXUD5Not1Fc48TJAWs876NUvKh6Vp8WSXcNR": "SOLX",
- "7UN8WkBumTUCofVPXCPjNWQ6msQhzrg9tFQRP48Nmw5V": "XENCAT",
- "9g5UvB8iR7Fe9VekHXytWTAXTHgY9Gem9g2x3SBCvRs7": "SOLYMPICS",
- "31iQsahfa4CMiirU7REygBzuAWg4R4ah7Y4aDu9ZfXJP": "SOLZILLA",
- "79bqt5R9YKayWA3iXXeSNSAid6J23a5rddqhmoHypump": "SOMA",
- "9NrkmoqwF1rBjsfKZvn7ngCy6zqvb8A6A5RfTvR2pump": "SS",
- "B582oxHHy41ijxaGem3GksSWAVBfr2fJxNKrL7mpC1z1": "SBF",
- "354jgbb56NmBnyd647sPmj8S1md9cBeiCPPhT6pQbonk": "SOMBRERO",
- "Gz7VJWyQW6Uqt1Py5S2ZvtYNEFbP4Thmi31n5mx1pump": "BIG",
- "8SCLpKVehUzuFBkqnF1qZu5LrodQDRCEoPVpCsrspump": "DUMB",
- "GBXFsey6um16Lwfafo6etBCynU3iEST5e4Y49YMJjupx": "S0X",
- "sonarX4VtVkQemriJeLm6CKeW3GDMyiBnnAEMw1MRAE": "SONAR",
- "BZ5ZaPicPT4nik6yNV8yhrmL7No4ziLbGKAofEUYTbWG": "SONIC",
- "72h2cpj8YU7aUJW3NFMjxfqGTh6hXnUrovMC4gKqyFPM": "SONIC",
- "SonicxvLud67EceaEzCLRnMTBqzYUUYNr93DBkBdDES": "SONIC",
- "59u8qAD2S2gEtsY5Vs7dJ95YspnHavyHEtRfzCEb9F7G": "GOAT",
- "9YYoJ6NaCm1kY76oYNF2uAWTRnJ6nFc4Q5MujeyNo28D": "SONICWIF",
- "H32RvrcA2tHipbXzaiEt8Dyr5u7GfnME6RcFDDWgpump": "SPQR",
- "4eDf52YYzL6i6gbZ6FXqrLUPXbtP61f1gPSFM66M4XHe": "SOON",
- "6NX2MWBuJM2Fn63K4hUgMPivLXHV8pwsU1yTdmjKpump": "PSOQ",
- "E9qT2T2YHfD67X7VKXZ7PWGnhaZ1nYdEBGbx9xbKpump": "SORACLE",
- "89nnWMkWeF9LSJvAWcN2JFQfeWdDk6diKEckeToEU1hE": "SORA",
- "3gh9ofmjD7acmNpMo41UvyRqoQvaH7N3mypHScziUSRY": "SRY",
- "49jdQxUkKtuvorvnwWqDzUoYKEjfgroTzHkQqXG9YFMj": "SOSANA",
- "2FK2ZY4EYfeUtD7gnh4uNdWf2uQjqBJ5vwn5ja3gpump": "SOTER",
- "Agentfk87X48g37uPprEZaQtizDvnSQVeTqVjAtmbhd3": "$SOULS",
- "9doRRAik5gvhbEwjbZDbZR6GxXSAfdoomyJR57xKpump": "GRPH",
- "FsXJHch6cj9TyZGm1kfMwt8S8oATCEr6ccqWFp3Xpump": "SOULGUY",
- "G3ukjeHBrDJ1zUFr6KandnW4bPcjmvK3qL2uATRb3F63": "SBOY",
- "FNj16zAMFERd4w2nKfjfVn51aW38m56jcfNHzpVQmoon": "SOS",
- "J4ywFdm8H7hjwKzCaEQujhkDRfCnRviVnHMvFNDAoLNQ": "SOUL",
- "vE2qArmjto6VfeMngyGAnzp2ipLYeXsxiARDnnXondo": "SOUNON",
- "EANjzFjj3nPXHdzN5CE3Z8LLVn69Ce77FE8X4cvondo": "SCCOON",
- "aKzjn2ZdWySSGPSSDTY2HUpcSCmemSahTXihrpyondo": "SOON",
- "6tWuipcDv4CiHtXid7JctDbtLLA1VdkTwSDupK6UxzJL": "KOREA",
- "4G3kNxwaA2UQHDpaQtJWQm1SReXcUD7LkT14v2oEs7rV": "SOY",
- "AkwneToXzViQHQekpCtNW9sBn9oEjTwqT4JYwGgSpump": "SOYJAK",
- "2uic5Siiu6kwPoHZDHnhvH1MySx1vmLkVmzUTkc3pump": "SOAI",
- "AVw2QGVkXJPRPRjLAceXVoLqU5DVtJ53mdgMXp14yGit": "SPYR",
- "XsoCS1TfEyfFhfvj8EtZ528L3CaKBDBRqRapnBbDF2W": "SPYX",
- "wPGmsXKE3csuioed4362kcQsrxGvhnGXGgA4RhBpump": "$SPACE",
- "9fLGtf1rRkYd6Dy93hvYh2r8T8Wy2EPa6WHC5ibgpump": "SPACECAT",
- "HovGjrBGTfna4dvg6exkMxXuexB3tUfEZKcut8AWowXj": "FCON",
- "PreANxuXjsy2pvisWWMNB6YaJNzr7681wJJr2rHsfTh": "SPACEX",
- "8uz7r3yQq8xnwBfWCoQGAftyYKgUz8wMQWod884nerf4": "ESP",
- "BMMWMuy1ZFBtDEzzdBvtrNvMZFetcGUfkrdDAYo3pump": "SPANKMAS",
- "G8FMb99PyHSvW7uQvdRCMfkeZgcGBwexR6BiaMxfpump": "SPU",
- "SPaRKoVUfuj8FSnmbZmwAD1xP1jPEB4Vik8sgVxnJPq": "SPARK",
- "pC9Wo6oHLJx2Vwrvrtpj64mRHQPFYwvGSr4eR2apump": "SPAWN",
- "hWfiw4mcxT8rnNFkk6fsCQSxoxgZ9yVhB6tyeVcondo": "GLDON",
- "k18WJUULWheRkSpSquYGdNNmtuE2Vbw1hpuUi92ondo": "SPYON",
- "Bm8MHt9vwK2RapFFZLa4AWfwLCzXAqCxanRj81xWBAGS": "SPECTRA",
- "5TRsf8t14xpoBYnzfUQyjk5SExCYqYzapEc8f6fEnU9k": "RUN",
- "C7K4Tot6fnnNwhWpqw9H277QPcP56vHAEeXubRHDyCo9": "SPEERO",
- "97SWAaoH62g1fYXphiLh3XczSBZeF5gBQBz7spNZpump": "SPERM",
- "JrTYw7A9jihX5TwpRStYviEbsYf2X2VJpZ13719ondo": "SPGION",
- "XsTuW2zaiPbzgrnQ7b4Z99zeULMM7gPxppE61CtpyDj": "SPGIX",
- "SPQkEcsdALLLn4MqCb3XH64hYTmdD4fZZk9CF5LiQV8": "SPICE",
- "AT79ReYU9XtHUTF5vM6Q4oa9K8w7918Fp5SU7G1MDMQY": "SPDR",
- "BX9yEgW8WkoWV8SvqTMMCynkQWreRTJ9ZS81dRXYnnR9": "SPIKE",
- "sPiKEYAqoaGYYBAnPxro8NLSYLu93sr56n352jJRLN5": "SPIKE",
- "spinezMPKxkBpf4Q9xET2587fehM3LuKe4xoAoXtSjR": "SPINE",
- "VaxZxmFXV8tmsd72hUn22ex6GFzZ5uq9DVJ5wA5pump": "OIIAOIIA",
- "9X2jTh2SPKBUBWD5wYuTBs1SsCJXbePYB8yfiVCvpump": "BUSTER",
- "8Nd3TZJfxt9yYKiPiPmYp6S5DhLftG3bwSqdW3KJwArb": "SPOODY",
- "FdGoS1Dok5CLnS8fVSmj5A92uY1yhzdTC2ZxuLJdkwgs": "SPOOKY",
- "8bdhP1UQMevciC9oJ7NrvgDfoW8XPXPfbkkm6vKtMS7N": "SPORE",
- "AhpyRU8g4kva6JAcqTcNRBvi565a8g76CpG8ocY8oMoo": "SPOT",
- "jzCvs2Pk8tDcfsFRqnEMjurgaQW4iQfEkandUR8ondo": "SPOTON",
- "AcfKwAf4UQLA5DLRQD2eQxW6pLv79VKzVso38WMfTxGZ": "WIFI",
- "9wyheK9Eqy92cRPM4PBGmtZseizVJ4ZpZgF8Jcswpump": "SPQR",
- "FRVCEaJuS8cuBTWR1JwVu35pBsKmHmt9n4LjSiF4pump": "SPRED",
- "V8LRV7kWjrx6Prke9oHEHNUiR122BVtyuPciTCTondo": "NIKLON",
- "JC6NduxxLvvV7X5Pb9agHQTRpHTecB83HhGK4VZHpump": "SPRT",
- "XsyZcb97BzETAqi9BoP2C9D196MiMNBisGMVNje2Thz": "IJRX",
- "8HJ81sHVsmJMzm6XBfTgywWQXwQTmVdmXaQHm7htGPH2": "SPURDO",
- "CuWmZpqoVgJQuo3YVQqR6zrV3eojQfXuRmuPtQUzpump": "SPURDO",
- "J3NKxxXZcnNiMjKw9hYb2K4LUxgwB6t1FtPtQVsv3KFr": "SPX",
- "23k6Jiahmd11DWBzE7jpprsYzgs3m3LfNtw2XkwBVfmG": "SPX6969",
- "CsZmZ4fz9bBjGRcu3Ram4tmLRMmKS6GPWqz4ZVxsxpNX": "SQR",
- "SQUiDbpt993WzEa1WLUEgYJRtKxsQAKjoELH9xhMs3v": "SQUID",
- "9bWCY9nEj7bGpaLU12RSEpBUKkuWTYatWakHVepJpump": "SQRL",
- "nZuEp76CPtVFy7SsRh9DhTin2uCEPceEnKbLaWcpump": "$SQUISH",
- "STBuyENwJ1GP4yNZCjwavn92wYLEY3t5S1kVS5kwyS1": "STB",
- "4AjvPXMn8YZG9saAVJvcWspg73oTFf2JmU4in4Xgpump": "STABLE",
- "DBAzBUXaLj1qANCseUPZz4sp9F8d2sc78C4vKjhbTGMA": "SBC",
- "8mYyeBom52k3V7qcQWkpSPcD6gPHmP4KK9Uf7DJ6zREV": "SC",
- "AcUZXCspGisFM9pBWQZg5944uJv2dHyqph979ve51to1": "STABLE",
- "4qnVjPG8DxoYYJifS83iExe3GWnM4JK4b6mBZRaR4gs9": "SD",
- "7hUdUTkJLwdcmt3jSEeqx4ep91sm1XwBxMDaJae6bD5D": "RSOL",
- "8BMzMi2XxZn9afRaMx5Z6fauk9foHXqV5cLTCYWRcVje": "STIK",
- "FrMU7uzwoTwad8E8aLBtHbQcKesZHaT2sJkZFwcKoDua": "SFY",
- "DUSDt4AeLZHWYmcXnVGYdgAzjtzU5mXUVnTMdnSzAttM": "DUSD",
- "5yptSfbPdg16eKeGQXfrPVC5muVkjQWnbNcx7VDVpump": "STANK",
- "CQSzJzwW5H1oyWrp6QhfUKYYwyovbSiVDKnAxNfb1tJC": "STAN",
- "2dPkLQi1WLkrbQbBAS9d8GHARF4oWQXFXrUbMq7bstar": "STAR",
- "ATLASXmbPQxBUYbxPsV97usA3fPQYEqzQBUHgiFCUsXx": "ATLAS",
- "poLisWXnNRwC6oBu1vHiuKQzFjGL4XDSu4g9qjz9qVk": "POLIS",
- "iPFqjcZQTNMNXA4kbShbMhfAVD8yr8Uq9UtXMV6ondo": "SBUXON",
- "A2GHnfpZvyeZX5Pr63jdMmo9uYbpaaKqHHuPD5xD2n6v": "SC",
- "FZnSMd1hPu5MVgttmtfDZUPN5gcuexvrh3CB67UuQshb": "HELIA",
- "7MiLCuSZfLoTAK7S7CztrLV75kC3rfJULEmDNUx5pump": "STARECAT",
- "FsTc9VgMQoHAc5o8DdeAFv1RphgNjb4kZTxx8JQSpump": "STARGATE",
- "FAJW358HjJ2mHXSHbHyxghfVGzX5SBoupdjRr2y9pump": "SONNY",
- "HsRpHQn6VbyMs5b5j5SV6xQ2VvpvvCCzu19GjytVSCoz": "STRK",
- "HCgybxq5Upy8Mccihrp7EsmwwFqYZtrHrsmsKwtGXLgW": "STARS",
- "A9v1uzDFSon5X7TgGYqd2HFpcioJntkFfpozzLCdpump": "STARPAY",
- "2GZcmRHmKFWPqkJ9Wm1XAf5kLwFxcYG5cTiTGkH4VZht": "STARRI",
- "GHtLF7drbYXGTHX73uSxqPKkJUzDqcBNe2M9fzjJzr3j": "STSHIP",
- "97PVGU2DzFqsAWaYU17ZBqGvQFmkqtdMywYBNPAfy8vy": "STARTUP",
- "2QjmbYxzxD5twLHWDhXWQnxZsRF7igyBfs3VNEdopump": "STARTUP",
- "EWMfSJgDCE7CXDAYz3hbCaA7NsFHTnddySXx3shco2Hs": "STASH",
- "Dn5cVZ9AvJVzk5b7za9YNkzkCMbrXkPvEbC4wMBMpump": "$STATICKY",
- "AbktLHcNzEoZc9qfVgNaQhJbqDTEmLwsARY7JcTndsPg": "MS2",
- "3qadpmJCfs6RxKPxpofA3CyEj78RKcjVLyoyVY6xpump": "STEAK",
- "BUfMXdTHqKGVztQjYRB2b4v7EKAv4cheMg8Uu16Npump": "STEALTH",
- "StepAscQoEioFxxWGnh2sLBDFp9d8rvKz2Yp39iDpyT": "STEP",
- "7i5KKsX2weiTkry7jA4ZwSuXGhs5eJBEjY8vVxR4pfRx": "GMT",
- "2s8AT36jzHfYDnkT1rTTFZti7EkVHhXon6ptAi8cpump": "$STEVE",
- "4TafVse4Sf35tLXQkKhJ8tTrAMCLWVBWvg6CK2xwjups": "$STEVE",
- "HrqHpE4NQbSTjVtFSTm9i8omFfytggsS9UkccHWHWntx": "STFX",
- "FECuKNNnGAzhF8LJMV5vGZUj9psDfWsu7WCNUBW7MXqo": "STICK",
- "Ehxi6CznHg8VnnqTRdRkiLT7cuniYaVS3f4wK5Dhpump": "STICKBUG",
- "3fAddCWnFZnVfHRaDf86sVDAD7jHXq97NULrpo4GGkth": "STICK",
- "G1jydhghPMLBXRFPR3wyJ9HbpKPR3Rv7M8Yakfo5pump": "STICKMAN",
- "9ZWmgaewdaH2Ljfi3iE8A7umcJcxJz83ZakkfEPApump": "STINKCOIN",
- "8jVcgXXUReoiFCDzDMEhftCvA7HWqLX6rNmZ6AxLpump": "STOCKCOIN",
- "9KczPhWgTxeNMgqe216Q36u3c3HTQ5WihuAmT5AKe3e1": "STK",
- "8TzfHZa6ZnvvGsQfnFC5wGrCiqbN9nD2KMjyabfrpump": "STOIC",
- "43VWkd99HjqkhFTZbWBpMpRhjG469nWa7x7uEsgSH7We": "STNK",
- "6NcdiK8B5KK2DzKvzvCfqi8EHaEqu48fyEzC8Mm9pump": "STONKS",
- "27U6sAYSDUJLpeCTTL5gW2wSwLGNRZRZKWJEqTWGbonk": "STONKS",
- "8P6WDZ59qwMrTgXWaxFN5J19dGwvY2XEavCyRdA25PNm": "STONKS",
- "AHnZ7VyyQ5jHXbitQL8tuN7ciGG66EvCnU7eKoKX99fz": "STOG",
- "AxriehR6Xw3adzHopnvMn7GcpRFcD41ddpiTWMg6pump": "JAILSTOOL",
- "2tuw17xp9dBxCW72HFvRAhpawMtc5Lcag3GGBktCpump": "SSL",
- "CofiHxizezmiQV1r85eV4Midefb6BahAyVeQQQxVpump": "STORAGENT",
- "DtwN3PHiKEpK1MSekViVC8QifdRJCkML6HG16sXHpump": "VAL",
- "STRXzrUKLEpXTVN5oyXaSZgt38MUcWN8VRAZUAVFX3j": "STRX",
- "51Yc9NkkNKMbo31XePni6ZFKMFz4d6H273M8CRhCpump": "SMS",
- "GUdXKe5B35QBcqa8VrPQqn8LCQrK2X1aecCQSJs3EVrS": "STORM",
- "33dhma9QA7xefhVpA7c5vMrN826xcHanSHruUEKF2LmW": "SOS",
- "DpxKNEi3XVeRByaGqYKvz2w6E2PhPgBAqdayLcQEpump": "SOS",
- "BpdHpqznEgYPXZNrJVRZvBhdWoafYLVVuLxTQo34pump": "SSR",
- "XsaQGz41BEQkS9xAB44uvUtuXcdLJAXEU1dogEzWMZ8": "STRKX",
- "Xs78JED6PFZxWc2wCEPspZW9kL3Se5J7L5TChKgsidH": "STRCX",
- "B8GKqTDGYc7F6udTHjYeazZ4dFCRkrwK2mBQNS4igqTv": "MSTRR",
- "9BpQUsVpGSBXX3fwi3U5Re12pufkiooxvVvoDCitFbJ5": "SVM",
- "D2tztvQKcmo7PUof8quQWAu3qXKwtiW1pLjvHLsUakv5": "BERRY",
- "2EYvskXTncMS11vejJcWHh8fPaCFy6bzDcVnmofEpump": "STREAM",
- "3arUrpH3nzaRJbbpVgY42dcqSq9A5BFgUxKozZ4npump": "STREAMER",
- "STREAMribRwybYpMmSYoCsQUdr6MZNXEqHgm7p1gu9M": "STREAM",
- "5Qw7bkvj13Atg1ftzUKrQu9p7YrDiQmJTrhwchM1pump": "STREAMGUY",
- "FNhcY1cwQvQqaM8CUjXSuoGKJniwC4maBRLqNRLipump": "LOCK",
- "986j8mhmidrcbx3wf1XJxsQFvWBMXg7gnDi3mejsr8H8": "STRSZN",
- "9eF4iX4BzeKnvJ7gSw5L725jk48zJw2m66NFxHHvpump": "LIVE",
- "STrikemJEk2tFVYpg7SMo9nGPrnJ56fHnS1K7PV2fPw": "STRIKE",
- "9HCRyuqrFDt1kUrwuUF7xjb2eqCgFmC5433MjqJ3STRX": "STRX",
- "strng7mqqc1MBJJV6vMzYbEqnwVGvKKGKedeCvtktWA": "STRONGSOL",
- "GWdFcYSbpQLywCe5qQkBPeojHGQHmX3L16SQM9mq9fCt": "STUDY",
- "4zUDFduzd6dWisjkrS7d7VSEw3EdrV3t7KkYPznZpump": "STUPIDCOIN",
- "9RjwNo6hBPkxayWHCqQD1VjaH8igSizEseNZNbddpump": "STUPID",
- "w6iohhdC6zbq2DP1uwtmvXPJibbFroDnni1A222bonk": "STUPID",
- "ERYH7V18RFsXhq7XGbojkpamb5dw6Qyto4kd1Ripump": "WLFI",
- "HswqmpB6is4ih9pPLNwYCFnG7YbAdwKvdZXW18aKpump": "SS",
- "G2pMCBjRQHHCkE79r9KAESvdhUCieWPZvX5GRFa3jCLg": "SUBY",
- "9X2RHtKrBzw3SLYe9E88cBd1kz5RfU1f4JTSn4aRH43d": "SKID",
- "EA6zg6e9RcqWDgUpkhRu2YZn7LamGTNntivL7h5qpump": "SUCKYP",
- "9wBNNCXg8pb4SZpTY868CEr74S25Qy1JmGHFwo9F37dC": "SUGAR",
- "CmRWGQAdDgDb7dPyDqUZNagLg2s4hn9tUeEiyFfiQgjZ": "SUIDEPIN",
- "55bfLJQeYwPdUui7W34G4Ka4BM6Pg3DxZNPZfeJJj3hz": "SUIRWA",
- "XspncLEk5B19BMLwvC26DqNtJxKWWxuBKq9phbCG8ff": "SUIGX",
- "4DxUsKzkzPEsPd2QFrba4VYK5wQFKTEQia6TxpkFnubm": "SUKU",
- "AKtixLfY2z51yT7G4yxYDrdjL786dz4zXynUGJUbpump": "SULLY",
- "FnLsoqsoPckvPrSCVX3HZwN95jjRH4JSLnsPKyxhMhhT": "STOSHI",
- "AGkFkKgXUEP7ZXazza5a25bSKbz5dDpgafPhqywuQnpf": "SSU",
- "BmjaULzZoEKnGpwGMfdCSEeTio3giS1qgbGBnU5Gbonk": "WUKONG",
- "C64cB3Ji5RgyeLz3YQmbYTzWRQ2w8X3jxW1B9V7MpxjC": "唢呐",
- "zi87E9xtFPRQ2o9qqerFxUDQLZgEkHrhpHDxxZhYi9a": "SUPA",
- "5TbDn1dFEcUTJp69Fxnu5wbwNec6LmoK42Sr5mmNmeta": "SUPER",
- "3oNLZjLuqdTAS9iUEbUNdqTP7USvh65EVvdtoDabpump": "SUPERCOIN",
- "4kVZLRtcPvzngu23oxXqH4MyyRMaFyh875N4g4dWpump": "CYCLE",
- "2G8LH53fcr3aCrEsmAo73eunbZRbyjKrGH5qmur6pump": "SUPERCYCLE",
- "GcmsHHG41giJYACYKrdxZp3kdKMZfg1UB7LaYzCzPxLJ": "SUPFRIEND",
- "B9QxfiMd6tjSGnJ8nzFK3XbtuQNPKCNkQeehMqgxpump": "SUPAI",
- "jLca79XzcewRuBZyaJxVxuKpUHcEix1X4CP1RP9ondo": "SMCION",
- "HmLspvjpQtQEnArUyJoBSFGS38gNJwBuxAeqSV9SZ66K": "RARE",
- "SupreByajmUdeJGLzvUEUm8W4xv1gF8JBqwYnvG41Dp": "SUP",
- "SurfwRjQQFV6P7JdhxSptf4CjWU8sb88rUiaLCystar": "SURF",
- "Cocouo2otHPBSov5KCjqGmqQC4MvxY7iZ9qWnu23y88o": "COCO",
- "3z2tRjNuQjoq6UDcw4zyEPD1Eb5KXMPYb4GWFzVT1DPg": "SURGE",
- "9mSsEqTCDEyFnPvJVdQ6K7uapfsvHahqGEyPV7zApump": "SURREAL",
- "NLMYNpjYVnYnq8rjwC9rKXgpMhg5MtQUUmwVBiAbonk": "SURVIVE",
- "6Hi2PPiqkwYBY2vxbn1oasbTknvsWRZvNL3PjKZnpump": "SUS",
- "ChVzxWRmrTeSgwd3Ui3UumcN8KX7VK3WaD4KGeSKpypj": "SUSHI",
- "ABDoiSudvFjjJ25rtXn8V2b6QGrH59KN6thAbsPvpump": "SUWI",
- "FaxYQ3LVXP51rDP2yWGLWVrFAAHeSdFF8SGZxwj2dvor": "SWAG",
- "JBSVUpKgYNHt4GLtNebQxTJmZgftTMWENQrziHtGpump": "SWARM",
- "Hjw6bEcHtbHGpQr8onG3izfJY5DJiWdt7uk2BfdSpump": "SNAI",
- "APbVLtq66bKBpUUdncHtVSab9TM1UrcqZ9wodXzmpump": "SNAI",
- "74SBV4zDXxTRgv1pEMoECskKBkZHc2yGPnc7GYVepump": "SWARMS",
- "9gyfbPVwwZx4y1hotNSLcqXCQNpNqqz6ZRvo8yTLpump": "YZY",
- "NSG17kiSApMumWjLbZ4BLx8biPaAxTk9tDCdy1Fb9ia": "SWEAT",
- "5SwxhEunuUUcWe4ojybdDwky6dpLxAehNmF4AA71STNh": "$SWTS",
- "6rCYcfDe7o51YRwfkCMBTR9tgMRUhkehDZBsX9gApump": "PLSR",
- "3dQTr7ror2QPKQ3GbBCokJUmjErGg8kTJzdnYjNfvi3Z": "BORG",
- "SW1TCHLmRGTfW5xZknqQdpdarB8PD95sJYWpNp9TbFx": "SWTCH",
- "7R88oQWwoFwMqb2ryrozDMvN3jNnWqrMB3ytKxNybonk": "SWOGE",
- "GAehkgN1ZDNvavX81FmzCcwRnzekKMkSyUNq8WkMsjX1": "SWOP",
- "CUzSRjBvqFFq45mg6j9oyQrDxyUTHEKM2xqKzDkZpump": "SYDNEY",
- "2ocYd9f3564zUL1j6zUi8FR6Rn4Yo76BvXoZwLYASYFR": "SYFR",
- "DuidnHq4WKSeJx3m4QKf7xSfXXa7H9ocT39hFjMSpump": "SYLVIAI",
- "Fu4jQQpUnECSVQrVfeeVPpQpXQffM75LL328EJPtpump": "SYMX",
- "9txCZaqYaQ62nFVcEWhosWx3vTMcJMFP5YYXQ5yhBAGS": "LIFE",
- "HfJvxwLQeHeiDz8e91RWSwMm3R1pLh1vyjLoSr5gpump": "SYNAPZ",
- "yso11zxLbHA3wBJ9HAtVu6wnesqz9A2qxnhxanasZ4N": "YSOL",
- "yUSDX7W89jXWn4zzDPLnhykDymSjQSmpaJ8e4fjC1fg": "YUSD",
- "SNSNkV9zfG5ZKWQs6x4hxvBRV6s8SqMfSGCtECDvdMd": "SNS",
- "FnKE9n6aGjQoNWRBZXy4RW6LZVao7qwBonUbiD7edUmZ": "SYP",
- "8a3sEw2kizHxVnT9oLEVLADx8fTMPkjbEGSraqNWpump": "SYRA",
- "H1jJwQTgcAzUZjAKhxS8dA6FY8VZyTBxKxUyv3yCrYA1": "SYRAX",
- "AvZZF1YaZDziPY2RCK4oJrRVrbN3mTD9NL24hPeaZeUj": "SYRUPUSDC",
- "CqMLnuQ8bVSiak5crmhA3PCrwwtKi7R5VzcxJDKArfYN": "TAB",
- "FNFKRV3V8DtA3gVJN6UshMiLGYA8izxFwkNWmJbFjmRj": "TTT",
- "AY1emMxqWLJnHE2HkQvLdLyVpZdsLzq4S3tx5whCNQoC": "TADA",
- "4ELGifwr2jHtEaFZUXXvQLAYiE6W5bvpWYZbJTRSpump": "TTG",
- "keybg184d4vyXeQdFqs4o99YsMg7xBthxTJ6Ky3ondo": "TSMON",
- "4AdDFsG1xzz1L7zKGo2fbiqv256Z92u8uCcJCgYuTBLo": "TJRM",
- "4mE8keRGoGskVfgkDwXLvADNirsav3sUWTHyTbHEpump": "L",
- "RTb54gpqAx6RpLAHRGnqQ3ciQ845CHqhg21ZzEJondo": "TLNON",
- "3xUK7cHo3Vfh7uQCTkS2GUhJJuXhg2RXgApNYKHZ1B5R": "TALK",
- "H4EkHReWbjJpqNUiUeYNNZbNKLqLfH8Jt9MkceXGpump": "OBJECTS",
- "CwZNvjtai6E3z8mTH31wNLqjdDfepdQYppYVrsVpE7By": "AGENT",
- "tptmXt82GmGnoE4qDRgHiTGKMBCh4fCdxjjCBYbgpZV": "TAMPON",
- "BvvhHk7x6jXgwWXnBhtXMuDCWyoNKoWSp9bMSiixMDok": "TANUKI",
- "GUUFsneDFrEgYwV2ngpvpMdAmwFjhFknA5eL7ehkeFf8": "🦝",
- "7dLJnm2NzHPMwB7mJL7azhyMLqs4ZzKYkkhr3ob72Gwo": "TAOLIE",
- "6MMdrc39L3rMZkshRP9WSKe3trSdcbx5ywJmzJBanzqw": "TAOSHI",
- "CdZuiJEgdwQVZBWZrd6MvYwZshsT5HvB6tJYAjzuUTAP": "TAPS",
- "GdRUzaVTvJpxtovLoiNjKhAcAfrnmBz3YaZK2xEipump": "THL",
- "DTTLrCGbqn6fmNuKjGYqWFeQU5Hz153f5C3pNnxepump": "TARDI",
- "4vTkpiA8Ti1YsScbCWy8x3zkGGahJUVwgVCPgPvVpump": "TARD",
- "GNeXbKnKuVRL6nYQP59GHXcsBjL5pR4b2tM3zVYVpump": "TARD",
- "XsjXR5jf4d4GNpJXwLvEBTMwK3ZYro2qZGgvUCzyJrx": "TGTX",
- "51aXwxgrWKRXJGwWVVgE3Jrs2tWKhuNadfsEt6j2pump": "TARIFFCOIN",
- "Hax9LTgsQkze1YFychnBLtFH8gYbQKtKfWKKg2SP6gdD": "TAI",
- "FKNfAwb8TmjYkj11V4NiTz4TgrLWTWgm2NRwAD9epump": "TASSHUB",
- "4oERTdtSCns3Zrxv2HJ8fw6Y6rticaRcu8GVGTgXpump": "TASTECOIN",
- "LX2mJPsutHkUc6iXNFgumSC6LVKyc66xpy2zDTZpump": "TATE",
- "EjkkxYpfSwS6TAtKKuiJuNMMngYvumc1t1v9ZX1WJKMp": "TAURUS",
- "8rLcHLi5UARNbWhKh6YNUB7NFuLph8Dv2qWXHxaHoPDq": "TIFF",
- "TaxhxvQdW5WwxDtxmyDnXfJ9eJV7wacbgow2kDEpogX": "TAX",
- "F5z4iCEsgDU3V4xdvQDykffjoDnePNprvVCjhbDVCDg6": "TAY",
- "CPjDhhBpwEsLygNuczKcNwBPgMeni1xLomD48x51MyYU": "BENJI",
- "XsqBC5tcVQLYt8wqGCHRnAUUecbRYXoJCReD6w7QEKp": "TBLLX",
- "6DNSN2BJsaPFdFFc1zP37kkeNe4Usc1Sqkzr9C9vPWcU": "TBTC",
- "Hg8bKz4mvs8KNj9zew1cEF9tDw1x2GViB4RFZjVEmfrD": "TDCCP",
- "AMNfeXpjD6kXyyTDB4LMKzNWypqNHwtgJUACHUmuKLD5": "TEAM",
- "527rGhm2iBD4ogEk89MX7SA3NdpCwyBZ3fA8pKaoHg6E": "TEA",
- "9mAnyxAq8JQieHT7Lc47PVQbTK7ZVaaog8LwAbFzBAGS": "WATER",
- "3BgwJ8b7b9hHX4sgfZ2KJhv9496CoVfsMK2YePevsBRw": "EPIK",
- "GGV2LcQsvJc2oFZFESnWBVW5AFoMknNX9r31wS2Apump": "P8BCI",
- "CnfshwmvDqLrB1jSLF7bLJ3iZF5u354WRFGPBmGz4uyf": "TEMA",
- "2gRVFdNHXnDZwCusjRQwCVuhuZFGQxFwqqUPjjhrd1kg": "TEM",
- "CNQf3F7QLgWZ8367V9Pbw9hALutmvB23ZqxK7bsGbonk": "3022",
- "XsBgbNRDujfznQq8P4NLKEkRTbPxUVt4v1xwkDzMMtQ": "TEMX",
- "TNSRxcUxoT9xBG3de7PiJyTDYu7kskLqcpddxnEJAS6": "TNSR",
- "HHoXk7WursT9DLBBhHzBWBbuQkfvvoNyHKpJi61mpump": "TNSR",
- "exYfSJt6Fgfhfnp3bAD4roYy97hLF9npjYaLyEXondo": "WULFON",
- "XsuwUbQSzCJN2wZabD1Gxf1MER2Ypa7hMzVMYB2WawJ": "WULFX",
- "PZkZdFmVQbP41q2JKDim7ytnUzTscrvBz2zMH6fpump": "BARON",
- "9MnKTgwFyXJgnZumHGT9NdHuzm98ACjkNwpLniLhpump": "FUN",
- "BBSAW49Sru7jiSajWVKTSWs39psrjjHbMMtWGWTJBAGS": "TERRA",
- "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i": "UST",
- "GrLvp1v6SGUyDZxUDxy69cTibyTQkNNJ6ukePW4Tpump": "TERRY",
- "KeGv7bsfR4MheC1CkmnAVceoApjrkvBhHYjWb67ondo": "TSLAON",
- "FJug3z58gssSTDhVNkTse5fP8GRZzuidf9SRtfB2RhDe": "TSLAR",
- "XsDoVfqeBukxuZHWhdvWHBhgEHjGNst4MLodqsJHzoB": "TSLAX",
- "TSPXcLV76s6V2zDiZQ18kBfcbnjaE2ZzNT3ga2Pd99v": "TSPACEX",
- "HdvZF538TerjMWc1cmtWVKUaGkS8d77sGH5QaDCCpump": "TST",
- "4TyZGqRLG3VcHTGMcLBoPUmqYitMVojXinAmkL8xpump": "TESTICLE",
- "A5nvoNHLmJ4ydL5KroxphCX4umFwcn8VWb4kXm7L6sXn": "TEST",
- "GrgjbSENn4rVi8onexN7gKg4u6xt85f1kTcbtiSDtime": "TETHEGAMER",
- "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB": "USDT",
- "AymATz4TCL9sWNEEV9Kvyz45CHVhDZ6kUgjTJPzLpU9P": "XAUT0",
- "Dn4noZ5jgGfkntzcQSUZ8czkreiZ1ForXYoV2H8Dm7S1": "USDT",
- "8i51XNNpGaKaj4G4nDdmQh95v4FKAxw8mhtaRoKd9tE8": "TETSUO",
- "81xLFvCzFaUM3KDxSHC75pXu3RPCeSeCbmGBY8aondo": "TXNON",
- "8tdzC7mFKhmfPg3KdSBafHqH7jgi3CvKomfj3Hhupump": "TGMETRICS",
- "6qqiEkw2vz4xoaFehAtrkF7mtxfT7m8BS2gSrvMrBLPS": "BLIPS",
- "7yn2PRbB96TgcCkkMK4zD6vvMth6Co5B5Nma6XvPpump": "THALES",
- "CrNchbhLnu4CzEjuc8uoxwFcaBgAYvY7RCf1vSm1pump": "UNICORN",
- "DAtU322C23YpoZyWBm8szk12QyqHa9rUQe1EYXzbm1JE": "FOUR",
- "HmMubgKx91Tpq3jmfcKQwsv5HrErqnCTTRJMB6afFR2u": "9BIT",
- "EBGJEG6tohUxLWqfoo4c2qdYkEcrkTEWwXpq8LA1pump": "TATA",
- "HuSyZB3ChbYngnQPSBWtmqceqKDUzghHCqppVf1Mpump": "TADC",
- "51akgSdiNy3UvFqSu82wL2TNYPtXZJ1yWXGENp9obonk": "DREAM",
- "766ivvadp4arnHKQ13RB3cD7PyvRDL42N2j7RCoMpump": "TAP",
- "3We1AmjjZvNqvcL96zjyoQSNaWuejrbksaf7w4XXpump": "THERIAN",
- "9cYXqd1ggyMTjwZFWnbDuf5EfLEcLuumMG67jRkJpump": "TAO",
- "47b3pp5G7ZQJ15U1nEgRmorUfVTwrotgsFeyfdhgpump": "$ANTY",
- "6rQFEuFNLZ6YdURoVmA1Np9ueNHr7jkTMYWnnsnCpump": "APE",
- "6m2SeubvmKc1MGqGxQToy9i7tdbkxhnMxqgEhtgFpump": "ZOLA",
- "FDQ77aHDgV6ozbv1b4WM5oXuHGV1cMnjSXpxvgSzpump": "BAGWORKOOR",
- "DexxZWtZd8hdmeth9gKYXgTWa1VYdMVrWFBZ9RXXXhBn": "$KEKEC",
- "AJqpoLhgr3rMpXAPHsmnKashBZVrnuo9HPd1Sa3Gpump": "BASILISK",
- "8ruqZuRQJDHoMxCiCSqm6P41YSxRL6JNNKYiigKePVnn": "BWE",
- "Abub8cRJviGWsv1qWjkR1wHqNdYjRenoaZxroFxbpump": "SHORTCOIN",
- "EKwF2HD6X4rHHr4322EJeK9QBGkqhpHZQSanSUmWkecG": "BIGTROUT",
- "BPUDuDxG2xyeKyDQ3bqDyPvTmCjXado5ETcGKV1wKhhC": "KILLA",
- "dTzEP9JU2NRDPuWtM32gaVKip2fTHBqjheU1APBpump": "BITTY",
- "GQKEw7RyqQKnLmwo6UwQ1x2pd7BYQSC8Fzz9aKoGmUV2": "BITCOINWHALE",
- "28j8MCJqvhaW7oAuzfWJQ7SB827A3EHXwrfLexjGpump": "BLACKFISH",
- "GTbWsjDBiAs7NtmqsaQZ4Qfwdnwhsf2HdMKTaha4pump": "BPENGU",
- "4rbQrrtXcBgK7ohsy83Y58pEbybt2YywGcTT8vpbpump": "SHIGGA",
- "8V29cUbz7MeF16rBJhkuGMxByZjfjDxcuqQsPb8AchmG": "BLACKSHEEP",
- "FzLMPzqz9Ybn26qRzPKDKwsLV6Kpvugh31jF7T7npump": "BLACKSWAN",
- "8y45AJzCUBSZL1UDFQRzCKovQBLQFudBrpPeg5yNpump": "BLACKWHALE",
- "7uCHQdxAz2ojRgEpXRHas1nJAeTTo9b7JWNgpXXi9D9p": "CATF",
- "9V7jznWgdN6tjMaJ6Bq11ZVQMkza6Zh45atgXbVmpump": "BLUEWHALE",
- "3pKf5xsDUU5BTWzDUaS3XfiGPi1ihcvoP68pXpU1bonk": "PROPHECY",
- "7qzGBsStxpQ6zBCzpFbfFBbtmmpgqdyk42vJXgzApump": "SCRIPT",
- "3G1yVFfKzZxsvTnAnJMQzZBtyTpfWUTY6G7685nRjups": "BUBBLE",
- "GdCN7rQA5egc8SU2Bc2kKB2kMwELneQZJVSt8gGBpump": "CAGE",
- "DRTeDJXZYYZxmq3tmgSPvLi3ef5E51cRH1KzzwXvC5M7": "THECAT",
- "CuM7jCNGFLQpFfnV7ZeUUbBpRWnCsPgTaNj6fgq4pump": "THE",
- "21CnrFRqvEVkQZUTFmTXjcsJTLZhRY51ohoaCPwRpump": "DOG",
- "DzMw8nmA5rnoRTTXGHCZaRp9EkMwG2anqY99XxiXpump": "$2",
- "DcRHumYETnVKowMmDSXQ5RcGrFZFAnaqrQ1AZCHXpump": "VALUE",
- "B9u8h65uM1oifqmP82VyUDb68iG2fKfZiyubmNMtu3h7": "DOG",
- "4JPyh4ATbE8hfcH7LqhxF3YThsECZm6htmLvMUyrbonk": "EAGLE",
- "2BUZ19fT8TYvPzhuvtCCp9ceu9eNRCmY11S4vSATpump": "EAR",
- "29TWWr9Lk9wr4yhzNvJb7qgrmftTzvHgG1C5AKwspump": "EGG",
- "93s39pnRwp5NUxvJ3A5zDWoXxKxqW4RCVzMuNsKZbonk": "KAPPA",
- "DD1Nxg9KZ9C2rBk96iMLkfJryttzK9U4wV936C4Qpump": "SHITCOIN",
- "BqndqeBCNSEftBKmbTbLVx1RX5zd5J3AGL9sG55Jpump": "Q4",
- "Bg4M3QWtpi416fb1njZrXBmusBNav1XsDRc6izxXpump": "FIRST",
- "4LK277DuJkKta8j41sXHdnvhmH3LLYwMjezXJE6jpump": "1ST",
- "6NhHMW7cXLJAhxXGfP3FAuvEdbrwguZY2tcPJfCPpump": "TFIA",
- "GbqbsRyBHVPHEv7xLEsikXmdpPPiApLTJesDBbL5pump": "GIRAFFES",
- "DkETzNyP4oST2NMU4mmnZwxerh3EESaxtfczk3n3pump": "GOLDENWHALE",
- "5AJELeDo5ZYwMbt6kRPp6hZ2xrcomwd7LuPXR8wmpump": "GRAYWHALE",
- "2FduXi5zPSyxWpvcxBNsu9NcukhKmXaRpy4RLv5obonk": "LAND",
- "LdRSv8xtxhykB4CehiHB8QG6iyQdVVj2PVS1QCUbonk": "TGE",
- "7opAGer4hk78N7VtYjk2bVif6SzvPkBm8PzQAvzspump": "REPLACEMENT",
- "AkgVdEH24cWSdzTf735SWESjsz4Y13m1u6AZcEmfpump": "GREATWHITE",
- "CWsrReZdBGUxwVzLrZZ5U6n6ofzuGdJQ3B9pRXCypump": "GREEN",
- "9CrY7PsMPx8pHaFKFV1Ty9CBp5GrvVT4dAanZoJHpump": "SHARK",
- "6kUEk2u5oosdNaxabkUj4zn5XtbQ2L4vutozucXJkKmR": "GREENWHALE",
- "6WUbAGBQd51XFQ3gagp3vJRsaz2Euo4PsE7uYvTLpump": "UNBROKEN",
- "J9cEMoiv88SgZHoUdBqg3TxKbXZZzajJEqJ9hTqNpump": "THGUY",
- "CuPrcDMz7CmzMeH8oGpmPXCTQfDmit2pgEE9UM1Dpump": "IMPERFECT",
- "EbtkxtLroYojLHZbpvnsd8A83FnMZD5cFyf2iZfxpump": "GARRY",
- "8snfTBHqzDEFpUuTjfibEnj5RnsAYUNh6o9tYHPAdjks": "INVESTOR",
- "iGG7XyyxGKSR6x5j365S9kcSy6o5kDP3XdqkuayGex6": "IGGT",
- "Ai9JQd8t7PdD3taL59kvfSttL71iuJeU5T6cND7kpump": "JAPANWHALE",
- "4hqxNjEcyaPfyjQQCtc9JDWaGQ4M1nDScCMZ9TTwY4AX": "JUPCAT",
- "D2ktFF1jxG52XgnoNL62veTvEHPkui5syBifjJeapump": "KNIGHT",
- "WchjLJqbq8AY283hoYKLs7ikBVYbnxUD8aHZf5upump": "KRILL",
- "5JkXrk1UV9xox6giRrFyELB9HnBv49QQXYUT5eHMpump": "QUIT",
- "zGh48JtNHVBb5evgoZLXwgPD2Qu4MhkWdJLGDAupump": "RETIRE",
- "EoP9nKZMtTFTWVjkJVJEQQXAgWoFZwgVgoKspkrVpump": "CHUD",
- "2Hpd5tfRdF71sERDoSKtjGGti9nPiCNEBi7Q2f1ypump": "CAT",
- "8NfK7b9u1RvMpHJnAnZki4mNQwjhvzrVZs7bRQatpump": "LION",
- "tAjP8NfsUJDp4LcqmAPMRzhhD9BRpesGvuosSXypump": "ENGINE",
- "A2vb8eA7HiRpb19fA2Dxz3XT8Mb1XxuNC6Su4aThVeLo": "PUMPATHON",
- "FLeuXXyxKqrDU8MULuxLSPPWpv1TLroMSHM6XsG8bttN": "MEEK",
- "tdzUKGeAchLRzpYBzmBWEGaoP7E8EQ8hPv8Eqi8pump": "MEERKAT",
- "BfZm2yBtQFYnV7fLFboEJZbVDGcp29n685qVmgf5pump": "MEMEGAME",
- "FBjp6EWSurnP2JX1h59waGwdnukLn6kik7fkFotSpump": "GRIZZLY",
- "BERrTba2FLMEzxzgcu3XiuZ9XopVdPKmDmEnmZUfB6B7": "TRINKET",
- "2ChusVZzi6pUqRyHnNWq27EczqUTacFYjSPg5RiDpump": "MISC",
- "3V5CzXmTyyJPHDr6fYGv223PkWgaSddXPbsqrH5Vpump": "MOGGER",
- "7TBD7QD9kyzwADErHusNtVWzSBdtG8j4aYJuXadNpump": "MWHALE",
- "85ioZLv1JYA7z8YxAQ7PXeSCFbQWfn7J5L1ftbxQpump": "EGG",
- "GASfLqDbE8c9w8mjKknxaHeDMmdy9usGwM1GwzVJpump": "MOUNTAIN",
- "GRzrGzVmsx42j8o1TDmQ5uNAf76TQYb24HgvKaNwpump": "NORMIE",
- "DHkguUzSuKRAZQTQ394tfQpa8CqrFoKSGggBr7XsawJr": "PRONUT",
- "3dYXT71bZn3JAmpzAYfJsDoyM16pfXFVeUPFDK9Ppump": "41",
- "BndKr3tLyEYvbarxrJNki72CnaFmPKYCSdLpDGuepump": "42",
- "9AvytnUKsLxPxFHFqS6VLxaxt5p6BhYNr53SD2Chpump": "67",
- "fmGLjVuQfBLbWPo5zxc8sSss3ixMW3u3bRP95uGpump": "ORANGE",
- "9qY5Bu9qLnrddN8cx7jtQim2Sx8ywUszatUp3E4VJn6a": "$GOLDEN",
- "D7fdJwFg9Ykf4tL9GgiSAugxvbEXcFZRhJ4FEgr5pump": "PENNY",
- "2Pp6ebUvEL9YRTauUTmGTwYZKRfyQXGM9jE4S8WPDtEy": "LAB",
- "DNnzSTbL8z4x28ji2dDmZKnYAbLf8zcmqiG9UjArpump": "PROFIT",
- "5dggsZWR3YpqkWbKmo8WsDpTvmrxxokscNmnayXABAGS": "CULTANIME",
- "F7Axwjz9fA8th4EUB6NbvaeJY5iVpAnrkzeztSxupump": "WHURPLE",
- "9jUb38tuMqsCe328tM7kxFEm3wRpbo3MbXPJoFiTpump": "LAND",
- "3CZNYQMF8wJdf37FGsjgwVWrRCKVbfZDSZy9LSXrpump": "BENJI",
- "Faf89929Ni9fbg4gmVZTca7eW6NFg877Jqn6MizT3Gvw": "WOLF",
- "7nY1cY2zoAeXmtk3bsQgmy8eytkAkd5HrHAGP6zxpump": "TOOOM",
- "HLRGoPcK1n4fmkowVyBNkVHRoiiCUL2qyneNqTUNpump": "RETIREMENT",
- "Be78Ld3SpYMif5YgxM4ipJx2eGSDcAaaCkHUzcV5pump": "42069K",
- "GUxKzvR7QmvA5M5j2LufNynVMa6hxjWkERDM7Vnpvvii": "SIGNS",
- "EVGzmSnoMSg57cE73kPZHTf1hkp2n7CUSDtybJhiTWBS": "SIGNS",
- "5dfHpiBxagAKGUMLpCM246qHb8i8gADE3xdpVnDKpump": "SHEEP",
- "T699bgtXQw4CJ59rQ4VzLsupVQUzoL5RmuhHnKrondo": "TMOON",
- "Xs8drBWy3Sd5QY3aifG9kt9KFs2K3PGZmx7jWrsrk57": "TMOX",
- "2UfBjNeDwzZsoUnr3hNKF4vkzAgiGmBNYCAxLq72cPa2": "THEROS",
- "2e4hookwoJmyAReeSRcTP5dE4myMnwfVvPSztDrjpump": "RUGGA",
- "ETe1Q2t6xRWeuv2s1PMHMHkN9UY8kbS3NTnZMDTspump": "TUTU",
- "4nBQGUjd3oRSEQCkbRuBVsz1QA2XuJuXJwPWvG5Cpump": "SAME",
- "49c7WuCZkQgc3M4qH8WuEUNXfgwupZf1xqWkDQ7gjRGt": "SAND",
- "AnKdvsKiZSCVWw67AcuFcwBmmftG8JjhAgaShXnopump": "69",
- "4HhWcsfjaWYKJtjaxd4EyGSAL4Ky8C3DvqAWPHnrpump": "SHAPE",
- "2zrHZZGwouwFtsh7KrGe2p9gi97Wb2ANtPKJbf4Wpump": "BELUCHAD",
- "2TAi8XLzDJ8btNTQp7WtCvhGuMnWzkFddr1PhYf6pump": "SHRIMPS",
- "7ZrGwnTE5Sg3nnTWoeLCykEDwipDqMzJjUvEMsPLpump": "皇帝",
- "4btUt5tQrN9MSfiHzZMdHf2ognjQZrWErjSJ9aiApump": "SINGULARITY",
- "3GXrVnWfE9zggQdNtAVtzaKSiJZUzYPcudmPGhBvpump": "FRANK",
- "7wUwkXo8Qjt3cYM8BaHHHeyfDY7ZSn7qvod92pNupump": "SL",
- "Euoq6CyQFCjCVSLR9wFaUPDW19Y6ZHwEcJoZsEi643i1": "LAIKA",
- "8zrgK9eADL7fc5GSn8seJ4n9E22bn5a4o5JiAptVpump": "SPELL",
- "4xxuwsjvynx5CrudVpY8DaHjGQDFA2QkY4oQqCrwpump": "SPERMWHALE",
- "H8xQ6poBjB9DTPMDTKWzWPrnxu4bDEhybxiouF8Ppump": "TOKABU",
- "4sTZPBPzKuk4n6QqBSmPJLKpvucSts4hnbZv9dTppump": "DOSE",
- "HjjmgBxtnu7soQfbyQAi3ZJAo8MPAA9rn6EPN2K9bonk": "DALE",
- "ABTZw146nJeRBbsxHqxtZasNnwMJBKaYrfxVk6zSJGip": "RABBIT",
- "5CqfXex1knfRiozwDtgFFNaiGR9TsmSUcWDNUTUGZQru": "THOG",
- "2kaRSuDcz1V1kqq1sDmP23Wy98jutHQQgr5fGDWRpump": "ETH",
- "8xHAL531iDVW9S2xsrWAFFEr1Yz71rR7RL7qPWGgBAGS": "TOILET",
- "4z7secBe41i5Svtotp4k2FsjMVV6xykEVnrD4kdFpump": "TRENCHES",
- "8RR17XBRY8v9tA9vuuFwrFyFEK5Z5X55Yj7AfEjv7RzL": "GREAT",
- "ChHeuhbXXZ1bdewMmMuZaAQ3WnzEtVsDcoY2hon4pump": "CHARLIE",
- "vSoLxydx6akxyMD9XEcPvGYNGq6Nn66oqVb3UkGkei7": "VSOL",
- "Aj1mSpD4vJDN5r3xptnHsjHQgGWDLge8bRQi2W6pump": "VIBECODOOR",
- "2KK4YMi24Tqo6tDn8mzYWkNdGjG3ufdXBjmLv7Fapump": "VOID",
- "EtL967sgMgeDDSUrNhtQrbhe4T92idzqf4VuA6H7uGfQ": "MAYA",
- "3QrGcwFSKXiKetD5ixzZa7H4zHPuTg8grrH7s5Mzpump": "WHALEGURU",
- "2tJU3pMh4HJjKa9HN6HngdopfNqqaeEytFqW98Kqpump": "WHALEQUEEN",
- "2Ci4XBmr67JFoS5YPrE8hmJPN9QgkcUab7xd8Vpipump": "WHITEALIEN",
- "HNHNHcornzS5NsMegJA8wq2Ao68xVmKrHDRFif6pump": "WHITEDOG",
- "Pz7zD359jya1s9jzp72inqfmKF13ziuJv6HzVfkpump": "WHITEDOLPHIN",
- "5X61PKDGt6Fjg6hRxyFiaN61CDToHEeE2gJhDgL9pump": "WHITEFISH",
- "3KDkph5Q9Cm3YUTmm39NgEDgX9jrRCHqkyNT2kMEpump": "WHITEHORSE",
- "a3W4qutoEJA4232T2gwZUfgYJTetr96pU4SJMwppump": "WHITEWHALE",
- "HegMoXeaVf8sUsHsqW8KEQtTzwHGZKuK5y8sMSCNpump": "WIZB",
- "CbUPTbC4K7zdAEWxfa1nad4468xpX3LpWPhZVnzybhfN": "WAIT",
- "Em9zr2tgSmGgRbz3kxyQeRXjRi9oc13wMu6cKam4zWFW": "NAMI",
- "N9vEHC3EF5GxfPRAKsmpM62ubWGLCUNVdJnS1cBsexy": "THIRSTCOIN",
- "C4wpLGTqMyAuaW7MUsEPdiUAgMo1WxpS8Eifwz1Jpump": "IMAGINE",
- "9YJ2XM1KHYDUR3gnMQbEXtWyz7ZXTF1UtPgG8Hu5bonk": "SCARCE",
- "49QYX4XDVyoyG7u6gYaktXeN8tPwx2RhA7wgiPvspump": "GLAZE",
- "BdTEJq3yEp68SNmeBfqBbDDy7nbSGftkDhDkVef6pump": "FARM",
- "DnPA3vTmXVWHzUV4XcFsRK84Af9XmZfcCdB8eitjpump": "TISM",
- "BgpZ9cXE2dRMTUPhroffbMQm3q8QTLpRorpHYeJspump": "FINE",
- "DocTwz3QhCgKy1CJJMruEAFEG5xTGoC43vPMkC41pump": "DIARRHEA",
- "GZ6YjHeeUEVrtUo25LMqBCgX51MeUHHU46Dpeatwpump": "ALOT",
- "DPfEwwrcWvc63PobzdcDkDbkY5FgWn7zCxEkXGGHpump": "WOMEN",
- "D7Z2fUrxECBh91chmnou8u7E9Yaq7inzzcjg9G1Apump": "SALARY",
- "EKCW975DWdt1roK1NVQDf4QGfaGTcQPU5tFD1DMcMe9Q": "THOL",
- "3dQugtW8ne2PHcjoGFek2j8Ht7o87jKqaSPNWuC2pump": "THRT",
- "GfCSfsnVE1jnS6NnSMoYqXWJV1ZgPug93J79byxYpump": "3",
- "4Njvi3928U3figEF5tf8xvjLC5GqUN33oe4XTJNe7xXC": "T",
- "BdNKUUo8vnvdhwi1Ejn4PXNfeeQF2374hCK3m91ppump": "THUMB",
- "HUWzPAUYLgAMWbP8MiQctEUDjqgp5dzQDVw61xpA1Xdc": "TICKERON",
- "YXUpFaULqhrLJS79JmFtAsNZQ2JDTnPemmdVZEFpump": "TIGERSHARK",
- "DYUjm68jHoQFHMHzuRqomrhRcog9mc4TNrCWHpufpump": "TIM",
- "ED5wbeyAYtLM4WRGnohPxJEwniaikEFioVmJyZH6K31m": "TIME",
- "9LAjk5F4rFetELE4CygcBbZ5hYc2QhRrbJjfm5Q26jWM": "DAVIDO",
- "BxXmDhM8sTF3QG4foaVM2v1EUvg9DLSVUsDRTjR8tMyS": "TIMMI",
- "a788oktKgqmoZUQvLyxPN95sDWE7Wpu7hyPNmGDxfun": "TIMMY",
- "FFMBajrDXwRwUw4j5D8XDN14Jp1Z72mnxjAoh34pump": "TINGUS",
- "5ZMUboLJUeneKouqrqu4jeLE68vX68ehE5qprV3Upump": "TIRED",
- "4WzLp3sV5uReVvxatfYmxoJWH7fY65QZBbcSAF76pump": "TIRED",
- "2qqJLwt3DyYCjMVPKbfEmXSrHJqaVvaR4AbgfDXDbonk": "TISM",
- "He4FyrMqmDBP2yUk3UL4HLmgeUkcfhy1gcXuZPxtheBx": "TIAI",
- "FtUEW73K6vEYHfbkfpdBZfWpxgQar2HipGdbutEhpump": "TITCOIN",
- "AfyDiEptGHEDgD69y56XjNSbTs23LaF1YHANVKnWpump": "TKNZ",
- "HuPspkki5Qdnf5WAU7jtEThkeMhni6XQ23tunZRkZWUi": "TMANIA",
- "3QTcwugiAGA7HnzcNf7qaHt7XakdscMxJ1TE5Wnspump": "TMC",
- "pDY4GPJfZcNETPG7myXeafQfgJqqVkn81bMYDyfondo": "TMUSON",
- "XswCi2U1G6Ppbw1QhG45yKb8UKuR1FKLJrquv2FZSD4": "TMUSX",
- "FViMp5phQH2bX81S7Yyn1yXjj3BRddFBNcMCbTH8FCze": "$TOAD",
- "2xMNNityqHbafNAgNBF95phKcdx97qahJMwkUh4Bpump": "TOASTER",
- "feR4zPDDZzbPyAdjkj7mzDFyobX21HRtfocdTszpump": "TOAST",
- "HPueqQjSgaSatMBKrvBvAnRmc6jnr51cPM1EjUJVpump": "TOBI",
- "2k2Smcn2CNygC4gocaipRUMzeqnqPtGg3S6e72j13jBM": "TBY",
- "CwjWKarykhGRoBHpeKJDRCo3Gsp6woxCQEaM8uSbjupx": "TCG",
- "CK7UwtyYTo4CmBohCF9RhF6mCNDxnLMcZsCqouP9pump": "TODD",
- "4T54PGF4gAU75NL9j2GHvrVbR6u5zjyJE4zGuJbkpump": "TOGA",
- "Ch2veYHxMWBDgw77nxWvJeGz6YjBD2g9cm21fNriGjGE": "TOKEN",
- "2zMqyX4AYCk6mgy5UZ2S7zUaLxwERhK5WjqDzkPPbSpW": "TGBP",
- "3vZY2MKBzRMoT4nGUCWYzXPTES2jLaLNMV8Fn5cKpump": "TOKEN",
- "HmjCoarLh5duURfJ333DwfFiPyTCgFT35pRSAoP8pump": "TOS",
- "3Ws5Z9ZVWZFBFPQtmUqSbL1pg1LG4jpfpMHGkUWK6UGJ": "S",
- "Dhu2cTaaCFnws87gh1hBMPcsANKoThjHhCBxcjgAjups": "ILY",
- "ToKeRoWpbMa8bvCTDtyuJtVo7Pos8tgcnM9sVyDBmBS": "TOKERO",
- "3SQSwa5PXDWoBjCGi5uXCgNZ7FDCD8gG8Ai5UkLppump": "TOFI",
- "5C8LMqZ9dbQ3RWoe5pFk5fJPhgiBQtBYdMnzekfJpump": "TOLI",
- "GgJJRwLg9NzFQ97o1CJLGLp1KLSUMBwFc6eQNVEr4fbW": "TOLY",
- "GwyxednWbrhgT2K6iPUsbtadErA7TBGqsJjyzAody2mv": "OPPIE",
- "JCeoBX79HfatfaY6xvuNyCHf86hwgkCCWDpEycVHtime": "TOLY",
- "9ekm6h4pxZcNbdyMw5fWkEnqAStjQCSzZ3TEfZ7tpump": "TOLY",
- "totuNukof5QgTjr6vW3pNUG669kSuEoh1zVf92eArmQ": "TOTT",
- "55USDUivJLe4L1kY64XK1nDPAqbphG6nRpTjk2iZ5PwG": "FATCAT",
- "FiBSKnRpjNHChN1BANpr3dsVFQuuHhETMen4xUDgpump": "TOMMY",
- "3Jam4LGfFxPZJAQEzruiBTt28bi1Da64QCaxdLaB7o4g": "TOM",
- "5wU4tUcAbds7d5cmnGK2otHa9gbayYsD2mhz1reR6c91": "LUIS",
- "2XsexjLapEenZobsrqXWZsDga4nNU7XmoW48NgWoGzht": "TONIC",
- "2DSFvQtdoqv7DjPgXL5tjTYJ3ABBnoBeTfAJTXNdbonk": "$TONIC",
- "XscE4GUcsYhcyZu5ATiGUMmhxYa1D5fwbpJw4K6K4dp": "TONXX",
- "9EYScpiysGnEimnQPzazr7Jn9GVfxFYzgTEj85hV9L6U": "TOOKER",
- "8NH3AfwkizHmbVd83SSxc2YbsFmFL4m2BeepvL6upump": "TOPG",
- "AxGAbdFtdbj2oNXa4dKqFvwHzgFtW9mFHWmd7vQfpump": "HAT",
- "AqHsVVzWuu7e1de1j7sGJ4MdJ74xUvCeXf19Y4dLiM3S": "TOPKEK",
- "4mWTS6KztDEoMu2uqsnbgbeGRh6chjq7Fbpmbr1Ypump": "TOPLESS",
- "5YqckGEkWHJmp9LW5aUF2uJrdUbMJaHcYnGjA8M7Ebw8": "TORSY",
- "8WzDFPNjUSV7ZPpNiqKY8NcWH9J4tDSgSeifp6Kboop": "TOSHI",
- "6jfRbgs3B1KrhohSZ7KbhJckHZektQs1rRUSwWeZpump": "TOTO",
- "5314GTpDziP2ZdaANnt5KJEABGXy5Nn5Kyc3SFPYpump": "TOUCHGRASS",
- "5Ro9KjSUGYisjREz8K5uD1fMdXnu1Jfq3Ktqm4EQMc1R": "TOWER",
- "kbmF7ERJWMaaDswMprrH9gHSLya5D2RMBNgKqg3ondo": "TMON",
- "XsjQP3iMAaQ3kQScQKthQpx9ALRbjKAjQtHg6TFomoc": "TQQQX",
- "7t1T28iMh5GsW8oTMx52x3u3M3hDbaY8psbL3rZ6BMrn": "TRACKEDBIO",
- "39foCGC9zixPSXVzRZdCbKE6nmx5WyjDq5FJ3J7x4REV": "TRADIE",
- "F1n2Tn7Eb9jTbSQiqy2Z7G4VTbkreHGQqcRKKmwZv726": "CFA",
- "DhuNPyaMF7n8rYs9goo32bcptkoo5bPhWBF67ftLVjsW": "TDM",
- "8Y5Biziz3njt9NWc38cJuL76pdfyrvX6SnjtFPeDpump": "TRALALERO",
- "5ypxFmuJUTsSkAeKRuRs4xSxkb4vWbjMLT3GY7ckpump": "TRASH",
- "C7AxK6ZdbmN9RmLnmV95vE2MrmAU77ftQZz5RVhcpump": "TRASHY",
- "4Fr2LL7tJ52Y6a8g63nHzNqWDjy9Te1H55m8rrX7pump": "50STATES",
- "7ptr39shwummyaSku3i7nKkJtBT81CA1SYsvSYTyDUnQ": "TREASUREDAVID",
- "9zZWnw2DbJyxFZNa2Qhkh2a5zKDXmXnucdcTCyMkbunt": "TREASURY",
- "4GqjMwnXb4pm64CuFDfovFMg2RCo3nPbeFUfsdAupump": "TREB",
- "J7hX5qVuJuiUiuZ1AkqE7eVS3sjTJ5kgFnuJwR2Rpump": "ROOT",
- "D3jYB29ZjSRwry6c266VNoeVkQWH8fqSsMCy2F8xBAGS": "TREES",
- "5AzTQ5zUuWUNGetxaRpo9DK9w8FQXoPjn5a4ZXMMmoon": "TREEINCAT",
- "HLnTNCG5RD7jYVduFc1pMCHiuApoWGn9LveqEFanQFZb": "TREN",
- "AaWVpk6eZbgBfVbq1UfXw3EXBmAvw4QXov1xHuG7pump": "TRENCHAI",
- "GACpABn18xqiSJbD9ZEyArJDT9RHRMUut5nK9Z9Spump": "TRENCH",
- "E2KiYxrbfeBeajPr2kJAvwkzPr8p1hi81kFGYfB6pump": "TRENCH",
- "8ncucXv6U6epZKHPbgaEBcEK399TpHGKCquSt4RnmX4f": "TRENCHER",
- "BbbwE8rudhjK4husSRc37X54mYyDBRcykJ7fk5oHpump": "TBC",
- "EU1q1FfzCPG9QHZZQvy1fL7vmisWtBApMcaiaWsVpump": "TRENCHES",
- "BzyKa1FGjs2EUpu3GGDibY4xdygn5evAiRboKmETpump": "TRENCH",
- "t3DohmswhKk94PPbPYwA6ZKACyY3y5kbcqeQerAJjmV": "TRD",
- "3ADvYyTbmQcLMiqdFSo1m2KpQWxYg9X6wW4N8viRTNf9": "TRIAD",
- "DNJ4zTzuLbt1wXZpkBNwbgS25RBNaqdKHdKzFsQCpump": "TRILLIONS",
- "2tV44KtbRfYv9NyReESkVNVxenWJQQMHuWuix1eZGQu8": "TRILLY",
- "ArsdpgcBPYRsgjsC9NZn7ikQVWHAwkEMdat3AUhE3io": "TRIO",
- "9PMjLqd8zPdKkJUXarnit5t7tPL3cCscwHzy7ATondo": "TCOMON",
- "BLDiYcvm3CLcgZ7XUBPgz6idSAkNmWY6MBbm8Xpjpump": "TRISIG",
- "9eXC6W3ZKnkNnCr9iENExRLJDYfPGLbc4m6qfJzJpump": "TRIT",
- "5UUH9RTDiSpq6HKS6bp4NdU9PNJpXRXuiw6ShBTBhgH2": "TROLL",
- "6gTqf9JFiCK3wPg5pTBzWY3iMkH8z9SbuJX8R2vxpump": "TOBY",
- "5mMrEEDRyFutXr7GB4NdJLkhRDQzrK5VC9Qc3Tr8bonk": "TROLLGE",
- "492JGSNiNd3DvWtnej1raJwNQ6Qui1W2UaGtVUCPpump": "TROLLHOUSE",
- "Cqy3AkBqP866vkw7p7ioK6h6VTfQT6tFUW1dzUezpump": "TROLLICTO",
- "ACHEprPEhxibTS5URUtTb44NFA14wpb7vHoTu3rZpump": "TROLLINA",
- "C2i8WUjvkpZPXEBumF6dwFJakaDA3hTYCcBpfLMgpump": "FAPGUY",
- "Bj8yqpGGJ4izJrUtUoVG27vTBDVaUYkWGfhoqSwBpump": "TROLGA",
- "XsRrH4fDA27xfyDjpcwefvcBdHCXs34krUuaXGEXzqz": "TRONX",
- "Trove4jcQhE1dZGrjBwe8LUEAZizcFDZ35gUHezmjhZ": "TROVE",
- "TRUFoUAg3rKEtcFxxeeuVm6Dc4Er55McRXMSgPk3hZ4": "TRUF",
- "5jJNLgegAQV1CqzLLAXFPi8qzjFcQWvKaADLDdFkpump": "TRU",
- "HdHqKPz3n52e6FCJREKY3MS56TagyvRxsxVYG7E4rF99": "47",
- "TrUPjEqGpUph6sMJX8C3yYja9u4RcVUGTCkGG4xLrjG": "$TRAIMP",
- "HRw8mqK8N3ASKFKJGMJpy4FodwR3GKvCFKPDQNqUNuEP": "DJT",
- "7KuFdcfzbc3LLoRHNRWfW1dhbPNzuCv41hyYbfSUpump": "TDS",
- "HC2KyVkPK9Mc9NEFPUi43okhTYPa5fStk6a3Ci3cDbQS": "TRUMPIE",
- "QcNnhASrCxLpkqndMvLJmBu8HAkdViZzdipBAoypump": "SHIMMY",
- "ABmMqCr6ybUhSPoG2iT1JKaf9ix5dqJU4eqmaBBCUipJ": "OIL",
- "3nGc7DR6jE41W2iLfvPC3ctPEPzhqAMWuvZRKXNLpump": "BULL",
- "DueNdyyx5a1ZMeaZr5kSSK3BjM5ADnDmhnD8ya4R8pGE": "SHUFFLE",
- "6bda6LhSpg59yQoVSvw5yQ6rd3TRcFANQPjhTLfpump": "TWRAE",
- "2MDr15dTn6km3NWusFcnZyhq3vWpYDg7vWprghpzbonk": "NOM",
- "CckLtcfEtsYzg8sUrVBBrFKt16iExpvEurc1dhKmmoon": "T3AI",
- "HoZsDYnsna4LJJoQE7yqzrRTSj5eDhe4hFecqmawMeRW": "TRUST",
- "u29pRsBVi7vPmCYsaYmtJEghPZFiWUK545QZh56pump": "TRUST",
- "F5sc3CGLmKueyUqaCkwopo9u61HsgpmJc8Cmc9xibonk": "TRUST",
- "EqeEBGHQhQy6SqeaJcnqAsNs3qaG19sdF89Xsarpump": "TRUST",
- "6zBkvjLkLZQxRBqACM4nHPjjdrjYjL994eruJtTWGJWM": "TRUTHAI",
- "FMzbxgGBQp2DTqzBE5KCpb3srd7oo4sUQLLoV3kzpump": "TRUTHAI",
- "2GmUPhpe93kcTJZrC7NJ2keeDZRT5dBveUgegb13pump": "TRUTH",
- "HyVDEc81P8DGfNfZbBZwyntJPvjrSi7JEK1vgqbJmUq9": "TRUTHFI",
- "CZZSiF7CpqZmBrLeV4YbcdwDFUnf4vUF17PTTKuipump": "HENTAI",
- "XsafvsGtzFqqHgTnA3aPC83EAMkacU5mcGtcSayhpVV": "TSMX",
- "4mbdysBik3jmzD7mt6FGPDsMxnYcxExSQRFjPucdpump": "TSOTCHKE",
- "9yNykgy7xvXv9ij8TapMjXREArGCREjY38KoFtASpump": "TSUBA",
- "463SK47VkB7uE7XenTHKiVcMtxRsfNE2X4Q9wByaURVA": "TSUKI",
- "mntQLkYmUJ2BDw31ypEoAeE251uXBdPVTDVU9s2DvWH": "TTBM",
- "BsXmXxfwQWks6WHtfmo5q3Ji4mQieEx2WNWmUUe1pump": "TÚANH",
- "L2aKgxwNSGn6i5njrDqtFxan82uidsfjXHrYNSspump": "TUFF",
- "9fEXUmPnDJYAXpoZ9nWi1gQZPwzVKdf8g9fYXW6Epump": "TUKI",
- "GfLD9EQn7A1UjopYVJ8aUUjHQhX14dwFf8oBWKW8pump": "TUNA",
- "F28UWka8PSyG1jUtVZ2CfFdF1dkLEA4rw7GkFBW7pump": "SAHUR",
- "J8PSdNP3QewKq2Z1JJJFDMaqF7KcaiJhR7gbr5KZpump": "TRIPLET",
- "2Dyzu65QA9zdX1UeE7Gx71k7fiwyUK6sZdrvJ7auq5wm": "TURBO",
- "7Cx1fMabGWgm86xvv73WzSAcwtLppKf39Ywe8e6Qq4T6": "TMOON",
- "F14hCmEKjcaXobNE2fMdRX9EcetC2oNuiZVjpce1iohE": "TURT",
- "bZqP1p2mUd9ftH6AFBmoyQqsAFcG5mddMMh3Y8mpump": "TUTC",
- "8r5ZuzAt5c8VAHVSMpgUJNzpp88wHLnJCsLTLMdsf27Z": "INBOX",
- "2h6EQ8oYnDQK4ppwHqR3JgmfRVpL4L6ga7AhaPnxpump": "TWIN",
- "AB1e1rTGF8xSoYzXEwNWohuMHLCMrBoaSxT6AARmQksd": "TWOCAT",
- "G3RdswoDRpEbWFCm2GYGQz42gnFWFF1jW6q5aKXzpump": "TYPEN",
- "KJNeFW3kk3ycPjXpC6cbuyckjeYHacc2ekhtAi5ondo": "UBERON",
- "XsAsZLF4MmsvS1sDxRMrUz7REjHfwbC9UAMXSRBqgEB": "UBERX",
- "5JkQBPrYdRK7JsC39KPPbZi7r6uLx3ZuL7jjMf4zN4c": "UCF",
- "HH8bchogQD71iuLghP4cuvSU7vsGJoMJDBxvWTFu7MpA": "UCIT",
- "99myne1mVnsSv2kAkzZDfNnwf5Xb4SASJnaCRXdbpump": "UFO",
- "9enS2VasgRxzT2QVkhjfVJAtrVJGB9MSYTSvUpf2pump": "UFO",
- "jQxGhh5r78RVp8Q5yAcjoy6ing5tFx5BSHV2nprP3cu": "UFUN",
- "74Rq6Bmckiq8qvARhdqxPfQtkQsxsqVKCbDQL5PKpump": "UGLYDOG",
- "B3QLjWnMfFjjzaXj1WJ4JmUqgFPVEfKbuZmfeXnrUiui": "UI",
- "CVcbbU7UBmY64LCDz466GftBC6Ph4RRyQZ97q1tpump": "ULTIMO",
- "PRVT6TB7uss3FrUd2D9xs2zqDBsa3GbMJMwCQsgmeta": "UMBRA",
- "kedoobK2qe2f1V8ee5vDXFr3H7gKnhQVNJXA3Ltcyai": "U1",
- "3gV3t7Y9zsd7wNjGXXukn2RT81vfH46hA3oEcHgVpump": "UME",
- "8zdFumGcK2iF8AcqfSEjaPX4NzPuP3Tyx7msnvcsBAGS": "UNBAGGED",
- "Dza3Bey5tvyYiPgcGRKoXKU6rNrdoNrWNVmjqePcpump": "UNSYS",
- "GgzH3GfJaZbkRt8zDbeKK9XYERSgEQUviXK7av2g1oa3": "UNCHAINED",
- "FAnDkc4jfztmgXdxJmGP4J9HpgHqv2fZLbnk5te2bonk": "UNDERDOG",
- "71QU3z2DoYKYLfpshufm3MJAhr2UJYXJAKmVSXSkbonk": "UNEMPLOYED",
- "8MgghUHzWyCXSQb4ReqrYQZ9rL8cQNaZ84GsqWhTB4Uu": "$UNFK",
- "FArDgWGo5ojumaA5BqFvGjGosZT1KaQM4qYBBYXFWNBo": "UN",
- "UwU8RVXB69Y6Dcju6cN2Qef6fykkq6UUNpB15rZku6Z": "UWU",
- "DzN1qkcRdsxQRFb9yVvz73Fnu6SbD3f5oJgArVdx7Nzc": "UNICORN",
- "Bx3REmoo2J4t4K6JF83AbQTkY8C6G6sc7TyyaCe8surg": "UNICORN",
- "eL5fUxj2J4CiQsmW85k5FG9DvuQjjUoBHoQBi2Kpump": "UFD",
- "2iygm3ZBu3YRDiJREMrZTLayffBJBShTrhEe9iyYpump": "UP",
- "5JDtsBBzPdpYzTBXw7GPJ6KQvy95e6D89dWPKeWWpump": "UAP",
- "CkJgoT1YcPqWdjUbvqgPf5BDwvq2GeBX7REG9TCCpump": "GIVE",
- "EvsME8gdnEwPLbTnhrGVDwrY35zBuB8hEGCq59Hondo": "UNPON",
- "8FU95xFJhUUkyyCLU13HSzDLs7oC4QZdXQHL6SCeab36": "UNI",
- "7Zhxshgt7Ft6pHFYMrHE1epWdWre7sJ1Af1GhEUnitas": "UP",
- "kPBGL8vAwKN3UGmr9cjkM2dU79SC3nzTC9yu7F8ondo": "UNHON",
- "XszvaiXGPwvk2nwb3o9C1CX4K6zH8sez11E6uyup6fe": "UNHX",
- "CZEZmARqTUu4CpBcTupUNcLyDR7wnELpvn6cujQ4pump": "UXR",
- "rCDpCrYepyYffZz7AQhBV1LMJvWo7mps8fWr4Bvpump": "USDP",
- "8iK4qEEb41gkogyEUn4qjrnuj3vgvQEf1RcxXauWpump": "USNDC",
- "rpydAzWdCy85HEmoQkH5PVxYtDYQWjmLxgHHadxondo": "USOON",
- "3t1bNt1RoXZvrPDZp8SXEaaQarZRBFf7W6mi9Eb8BAGS": "UTK",
- "UNTyTuyNPhLufn4K4SMsW6BxbvfYEMgQ4qUT9orPapp": "UNT",
- "9psiRdn9cXYVps4F1kFuoNjd2EtmqNJXrCPmRppJpump": "UBC",
- "uniBKsEV37qLRFZD7v3Z9drX6voyiCM8WcaePqeSSLc": "UNIBTC",
- "5QmbJw7mM6tcCdXVy8ftc2bu8izded7Etc57TMA2pump": "INCOME",
- "79HZeHkX9A5WfBg72ankd1ppTXGepoSGpmkxW63wsrHY": "$UOS",
- "B6VWNAqRu2tZcYeBJ1i1raw4eaVP4GrkL2YcZLshbonk": "UOG",
- "G4cPnwTLd6oKA6FQgm5ckJmw3tEYapQRmqpQEnQYbonk": "UWU",
- "CB9dDufT3ZuQXqqSfa1c5kY935TEreyBw9XJXxHKpump": "USDUC",
- "CasqeWMxfdfzhohWNA7VHFGkmTxJ8jkv5foinUBZpump": "USC",
- "4EKDKWJDrqrCQtAD6j9sM5diTeZiKBepkEB8GLP9Dark": "USDARK",
- "7WXaHLjatDZBAZ7hyRiFpYpGpPbcKiyHf6HaxUzSbonk": "USD",
- "3vz82EWYv8xnc7Cm7qSgERcpMeqw92PcX8PBz88npump": "USDUT",
- "5TM2nWGomk9MmBNKmsFf8QAsHZf3S8hvtu214KhQpump": "UC",
- "59nzDoRyJ1QcLcFYFs4GVdeZ4qUEb16T2KNuHPWMpump": "UNTIL",
- "9iQBkyLKtqRXvb6ARGvQydt1LYgGcTtVe3PTDpWhdPze": "UNVAXSPERM",
- "4b1guAuV7xF5qD6Qi6AP8Buj15ff5v98RQNAaCGMjups": "UPRIGHT",
- "Dd917ev4Zzde2BkPm31FTLseHNHamJPPUwQgGAybpump": "UPG",
- "PeGV8nmE7BP23Ev5e3LZJ3muvRvVYAaYozQfHDSpump": "UPRIL",
- "UPTx1d24aBWuRgwxVnFmX4gNraj3QGFzL3QqBgxtWQG": "UPT",
- "F23fFqpRNsmWjuUrFpfM1pvoVvMSpLuN6hY978Y1JXLt": "USDCAT",
- "6vVfbQVRSXcfyQamPqCzcqmA86vCzb2d7B7gmDDqpump": "UPTOBER",
- "7VKG39KqGopTetYvgBA3WADEB7fiB3kMChqA6Lj8pump": "UPVEMBER",
- "EYo8D3cLdF1CDeGms5M5VHyU52HJYinkMZ1cqvYondo": "UECON",
- "32jSCpTYmLze3jj9ruqtLmPPBRtag9ud5YbsJwcfRcVM": "URS",
- "BFgdzMkTPdKKJeTipv2njtDEwhKxkgFueJQfJGt1jups": "URANUS",
- "BwTu5zJqEyLYawwYoGTWT7UxC85eLYQWRcta1GiEbonk": "URA",
- "9hjZ8UTNrNWt3YUTHVpvzdQjNbp64NbKSDsbLqKR6BZc": "ANUS",
- "F8W15WcpXHDthW2TyyiZJ2wMLazGc8CQ4poMNpXQpump": "URIM",
- "GACxkcy9WDWHhB15oKLHp3PPzQV4zLt2m7dcGPoZLkZY": "URMOM",
- "9j6twpYWrV1ueJok76D9YK8wJTVoG9Zy8spC7wnTpump": "URMOM",
- "FvgqHMfL9yn39V79huDPy3YUNDoYJpuLWng2JfmQpump": "$URO",
- "FMpA3eQbHFEPkkb9EYkLAddfs8TXZfz1Xq6Kqkowdaos": "USAI",
- "6P8ixuqGZpfyHAxyxbU4a31vsMiFiCQjBzVV58gPpump": "USAID",
- "2yFiCwdLiUfxq9PcNXQvu16QdgBFniCJP8P8gEXNpump": "REBA",
- "BAU83kqEqhyiexfAMQhZZE5KnGogSqh17fJc44Sondo": "BNOON",
- "USCRdwZP5UkKhJzhWuD7XjTUviHBtZJbLG7XpbKng9S": "USCR",
- "79cm2rFTnRSjJubaAx3V2anc7uKiCkvd58RkkDRFCUSA": "USD100",
- "USD1ttGY1N17NEEHLmELoaybftRBUSErhqYiQzvEmuB": "USD1",
- "usdsfJbX78ktZUnoRC7dwvvQz7xH3WdkpGne76gdUia": "USD+",
- "GPdJrAJa3Qrzwag5aKsM3bq6x3vFF3966QjTaSYXbonk": "USD2",
- "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": "USDC",
- "8smindLdDuySY6i2bStQX9o8DVhALCXCMbNxD98unx35": "USDCV",
- "A9mUU4qviSctJVPJdBJWkb28deg915LYJKrzQ19ji3FM": "USDCET",
- "72puLt71H93Z9CzHuBRTwFpL4TG3WZUhnoCC7p8gxigu": "USDGO",
- "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX": "USDH",
- "EJvBDsre5a3DbLmHZBw1YUeUqETJ3X9UkgR6TLiipump": "USDR",
- "BNgsQdjfWmjoy3cw8T3VXWswHfgCzEMyQzUno8gmzmRC": "USDM1",
- "USDSwr9ApdHk5bvJKMjzff41FfuX8bSxdKcR81vTwcA": "USDS",
- "8yXrtJ54jZtE84xEBzTESKuegjcAkAuDrdAhRd8i8n3T": "USDTB",
- "9ckR7pPPvyPadACDTzLwK2ZAEeUJ3qGSnzPs8bVaHrSy": "USDU",
- "9mfqn25C1nMVwn7YjxdJFvvTqichHFf8aR6vzNzPSodh": "COMMODITY",
- "HD3JBABeFkdZwUgKwhwJYqjLNrPWXEaDVfH4uMqRpump": "USEFUL",
- "D67BSPqECWv8GEozzFT4KCMtT9aFkswK5fC3oeBBbonk": "USEFUL",
- "Dz9mQ9NzkBcCsuGPFJ3r1bS4wgqKMHBPiVuniW8Mbonk": "USELESS",
- "CDUnjzbb1fqAwo4KZX3u9GYRsMdZUfhTLVzKhK5pbonk": "AILESS",
- "EJVceV9HmJpG6XAxnKYtTQFHf4S9ckgKwBsKMF4fbonk": "USELESSANI",
- "5NnL7oRMtVW3ZqAt95gJQs12Fbz2caCYh9rgy1kQpump": "USELESS",
- "Es2ipHL7qXBcLmZ4N7LP9PHBHaWaTMTAkxDwGGjondo": "UNGON",
- "USoRyaQjch6E18nCdDvWoRgTo6osQs9MUd8JXEsspWR": "USOR",
- "5Q8RSzXAybeLYkf76mMP5a5C9ikc8y4Qq9raJqKapump": "USTREAM",
- "6FrrzDk5mQARGc1TDYoyVnSyRdds1t4PbtohCD6p3tgG": "USX",
- "FPZsqAgtwf58GmJMctZGSu9RaXiGAmQLL6ZtKUUewm7k": "UTG",
- "FwrcPjGNdTbBXWBKktRvnNTnAfRNtv9nPDGV3gjgpump": "UTILITY",
- "HGTXnhgyast5fJKhMcE4VgyeEVWhYKEsHxpZtpjhrYqA": "UTCC",
- "9gExMiURmgzKZyq5PhGnxaLcFrt4hYcca87HK8VSXe4g": "UTT",
- "7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT": "UXD",
- "9raUVuzeWUk53co63M4WXLWPWE4Xc6Lpn7RS9dnkpump": "V2EX",
- "GMcThHFBnN6zjB2Mvbgdi19A2m35g81y7B1AKhgGbonk": "VCM",
- "5cL3TVJ7p5ZKqyx16DXwpdcNx5u19vQtWujA9vYindi": "VALAN",
- "5vSuxSJhyGXD4wNTrXS4P1gWmLUjCc3zLkE7rE8Pbonk": "VALENTINE",
- "Gs7yqXZpiPNMpQndq43dCJqRuBAaoarcY1uUbg36bonk": "VALENTINE",
- "9GtvcnDUvGsuibktxiMjLQ2yyBq5akUahuBs8yANbonk": "VALENTINE",
- "GX7jJ2E86ndix3B1V3Q2GVahukiDf9eUip2yBmPmpump": "VALENTINELESS",
- "nn944oFMxsHg9AnEuBHWxtBpGjRX3DRxx86PseuDrPJ": "VALEO",
- "growFDf9teg9gwVTTY3DgpPXU31qBrnbSQCqtY2vkR8": "GROW",
- "3wPQhXYqy861Nhoc4bahtpf7G3e89XCLfZ67ptEfZUSA": "VALOR",
- "7tKa2ui4KgDTG6KgggzrVYjnup9Eh6Yazdwi4UcRDMaM": "VALTORO",
- "9x5CLPb3SeYSBKvautqpJWPjX9TUCVcWTS12Xawapump": "VCC",
- "ucQ3VfWAx9pkCN4Kg84zE56FtB4FJN2kQH4ArYYondo": "CLOION",
- "DnvbCqRuUYssmKVRBRNwkUnptHitH4ZZTt1KVuZondo": "OIHON",
- "tiitb2Z1HtpB2DpVr6V7tdCFS3jmTinLeuGj9EVondo": "REMXON",
- "34mJztT9am2jybSukvjNqRjgJBZqHJsHnivArx1P4xy1": "VBILL",
- "F3dMJ9H137YUNc9cpN3gBWDSq4MSRbTFtojH65Uondo": "VNQON",
- "jCCU4GwukjNxAXJowG2S4KCrr5g6YyUB61WHYvGondo": "VTION",
- "XsEdDDTcVGJU6nvdRdVnj53eKTrsCkvtrVfXGmUK68V": "VTX",
- "KuiYLPVq65qixD9TgvxBC576C4gG6vVTCdbh2zFondo": "VTVON",
- "XsssYEQjzxBCFgvYFFNuhJFBeHNdLWYeUSP8F45cDr9": "VTIX",
- "66bHtzcXqmLgkn668EG4ETzHL3RLz5ybdckqvrPppump": "VANKEDISI",
- "GGd1WfYyQaJQZ2VNhqNcrQbXRnUYgTTWeG5gBLT8pump": "VANTA",
- "Hfm5LMEHXAGYuq2ofT1opYuDeE6Eg4wyTydL5wZfpump": "VANTUM",
- "2qmcZfyPpiFFx9kJPY9i7dM7Da6J5rVUvXzTsx1FJtfq": "VAPE",
- "VAULTVXqi93aaq9FsyPKgdgp6Ge1H1HoSvNC4ZbqFDs": "V",
- "BVLf4EqukZUKbnXkaDJgx7J15QfxCKkNtti7PksWsCQr": "VFI",
- "3YHnXHivm9DiiUtbHNr49mkBctBFy4ksX3PAa3AApump": "VAULT",
- "ASBwUuPEGRRgE6ZUChJvJ9zrkeQCmqqvbhc2gGyspump": "VEILRA",
- "BWdwwcAJarHt9JtgSgPgFJG1eEcd3vSn9j9DnQKqpump": "VCASH",
- "3xhezws6Lk7cMqoVEfZFXu3ry9GKymFz1vbWyQ4f99uX": "$VENKO",
- "FRpTyMBDavKsdYN1FQZcEeZ2iwGvHaZKFSkvr5izpump": "$VENTI",
- "4JFcUJ1HfFKz2F8thdu2frk558EjrLvKEmeMq1ZM2xBP": "VNTR",
- "5SXx7DqZAwnYwRxhBdkcV78RdJrzvCJjRxLmoXdbpump": "VERA",
- "igu1coP6n3GPaWmbd8J9Z7UAyLpV254uQFFNfydondo": "VZON",
- "DL7JgzgcJLudqJAVTXWyNizT9p9Rk5kxT4bWKUwcpump": "VER",
- "AiqBwm3CpoCM6rmsR9BwM6zNXns4YVwjkvpXKNdCmoon": "VDNA",
- "vRseBFqTy9QLmmo5qGiwo74AVpdqqMTnxPqWoWMpump": "VERSE",
- "FL7QzUq58pvkDxkftJm7RqRWgqYEFZwXuvAMsUnondo": "VRTXON",
- "MkN2TZSYTFBdMRLf9EVcfhstTwnazH8knd9hpepondo": "VRTON",
- "cPZp4Sk44ecqkwVtED3YPPudQMEe5MbZsavDiwBntAU": "VETS",
- "8yeMPJGVVJKRyXdsRBne4ncJekcC5Bd8MtTmJ4j7pump": "VETTR",
- "4TQzKV6v18aSVJqrCoxhSuQpFbH7wcQGMi1Wwg8dpump": "$VIBE",
- "HJ88bA3HJKgKfDUWEoTqTvvhMng5E6RSAMjwTetCvibe": "VIBE",
- "8tSeXYSXzFvaDX1nbWrEFFaFuPHuWqpzksKYxQPvpump": "VIBE",
- "DFVeSFxNohR5CVuReaXSz6rGuJ62LsKhxFpWsDbbjups": "VIBE",
- "7PzU4m13VqkdgWcserfBdxX4cAPQXaZuFNuKarnT1deV": "VIBECODER",
- "7DwehymUxUZgjBtPybVcDNw2QhDr7tNZxuVBEAVpump": "VIBECOIN",
- "5r6Acw8ms9VkFeaxrnFE9sxbh5AA2CG1k4edZmpcpump": "VIBECOIN",
- "Ed1yisBEAo8UXToSswvVFgzyJKpF48HEdq5kvz2zpump": "VIBES",
- "3nf8LgahHm57gEUx64cDNJf4h53C2MwqZCK6LGDTsend": "VIBEY",
- "VP9UaBXLM4KYRvyjisu65rz8BU5xNAbewU7LVmyU2x4": "VCAT",
- "AZbem4s8iLJE5eniDZJ7c8q1ahbfMwWgCA8TxVW2tDUB": "VIBECOIN",
- "7JXwBQDSPQZH4gUy1RGY4Tm5atf8g9v1eNG3h5trrB7X": "VICKY",
- "Cx6agZZs3sBnLmyADSq5ecXtxR7cXLPJSsdMv2PApump": "VICTOR",
- "2xyoTZzNVvbWABQmaDwYb1mhuvutQkGuCPTSMqicpump": "W",
- "HTJKotaFtAmc66UuWHqxnr6Z3tdMWWEn5mP6X69SLKYB": "VICPAY",
- "YJWeeW5JBAQJuBrPLZxb42UeFMAAGtfC4NDvNRPbonk": "BUNDLE",
- "6AJcP7wuLwmRYLBNbi825wgguaPsWzPBEHcHndpRpump": "VINE",
- "F3V1fKLKv7H8aNdt9TC6GQ3X4LayEfGHsPi8Umaondo": "VFSON",
- "8fPMSwpxVMR4xLStqAXn9QZwVCCionjDMfqKSqcfomo": "VIOLET",
- "BhbfgSh5P742DE5eMx24iZXNZeD2vNRFBZe3EP9Mpump": "VIORA",
- "HW7D5MyYG4Dz2C98axfjVBeLWpsEnofrqy6ZUwqwpump": "VIRAL",
- "Xsgrm4D6VBTfDx5bs7GNdjtmWDgZ8V79r3YpsYwf5py": "SPCEX",
- "Ez4bst5qu5uqX3AntYWUdafw9XvtFeJ3gugytKKbSJso": "VIRGO",
- "3iQL8BFS2vE7mww4ehAqQHAsbmRNCrPxizWAT2Zfyr9y": "VIRTUAL",
- "28h1NHtVWNS5xbSKZXAsmHr6d8CrqW69BfDm7VQDXSxN": "VIRUS",
- "DdcvRiEs4k2fXbHqeJBS5jgGD93rj1wu6u8WTL4vmBLV": "VIRUS",
- "7NwukWynkZap56CRwPjxde2HY7z4nFNzzVYTQ96Lpump": "VIRUS",
- "kxEW4oJL75K37VeXaZF1ynbHQATQwhECQKN1374ondo": "VON",
- "XsqgsbXwWogGJsNcVZ3TyVouy2MbTkfCFhCGGGcQZ2p": "VX",
- "YBnTi7GSU2E8vwcoqVcKCRurFafbSRcNfG3kPFRWQuv": "VISIONAIRE",
- "h6MW8GFpfzxFa1JNn6hZNnBF3t4fj9SHAXKy6LXondo": "VSTON",
- "Xs936JPaWKEXmpu54DZ149GETV7PmsnTqnMWxgcPNAj": "VSTX",
- "FpVBzhuQhY3uT1ijxwHRob4NjXQzbcpg1FsgNNTwwBLV": "FLOWAI",
- "vita3LfgKErA37DWA7W8RBks3c7Rym2hPFgizNRshBi": "VITA",
- "HaCUz8NfR9LqWVQvXqYxR2ast9BHsEScdgS941LKeBLV": "VIVA",
- "9RUup1LmD5PBsnd23JmTy39wSwALB7JF7xMfUJP8K7je": "VIVI",
- "Ee4ooSk6GMC34T1Gbh8rRY2XLyuk2FsyiWtq3jrHUcPR": "VNX",
- "5H4voZhzySsVvwVYDAKku8MZGuYBC7cXaBKDPW4YHWW1": "VGBP",
- "C4Kkr9NZU3VbyedcgutU6LKmi6MKz81sx6gRmk5pX519": "VEUR",
- "9TPL8droGJ7jThsq4momaoz6uhTcvX2SeMqipoPmNa8R": "VNXAU",
- "AhhdRu5YZdjVkKR3wbnUDaymVQL2ucjMQ63sZ3LFHsch": "VCHF",
- "5a6LTLwdMJBY2JDLjw8B1w4JwFRdZszGF9W56ZzrriS1": "VDR",
- "8c8gJSmaU4yiDsZFWTiCtsMoVBuqp5WGyzSv4VVpump": "VAR",
- "9wAKgC8zXwSGaNgtkoNeFFkAfuBkW4BfUUuPkrx6nrQQ": "WTAO",
- "9hSaLB4a674pns3uJCYRu4u5Bbvi4UwBcrS9AKnFpump": "VOID",
- "2kj1MLqBPnhCTyjxT3MtJhcktJHxgR7s4EDu18khsvgj": "ETHEREUM",
- "FRsV3m924aGpLMuEekoo3JkkMt1oopaM4JY9ki5YLXrp": "XVM",
- "9VfYm416nEB6iuP8h4Cb9xks7tcdvbwknuMCGEBXpump": "VFS",
- "E5ZVeBMazQAYq4UEiSNRLxfMeRds9SKL31yPan7j5GJK": "LDZ",
- "H6dZStmJBb5c6YAsnV5JxTbgwJiLjT5zKc4GeBwcpump": "VOOVO",
- "vooz4rKUS7PJ2a1r1T3q81E7b5NpGYjsT5YxciCJ4rF": "VOOZ",
- "9ruvAhSYeRXqqAz1ffWyKzvPk4SJdLgtMWLXfz5Ppump": "VOX",
- "CvwWh9NVQJ12KJ3xqe5SzWAvdohdfD8sePo8STQApump": "VOYAGE",
- "5HpFsGEkcyChSovAmKVxtXb4JqVVkBpPnmYPoSgZmoon": "VR1",
- "AumaQ5bXzpd5xjsR6snS34FbRGVNNtCF2z2QgVEmpump": "W",
- "C4jMVM797K2FqzbwxJn4TdPyuVhso7kCUu7UXRfjpump": "WAA",
- "8doS8nzmgVZEaACxALkbK5fZtw4UuoRp4Yt8NEaXfDMb": "WAFFLES",
- "3MLpX3VviXDhzZzQwFMHXSRSdXvWWsycLEt3xcTapump": "WAGER",
- "5tN42n9vMi6ubp67Uy4NnmM5DMZYN8aS8GeB3bEDHr6E": "WAG",
- "Hb4m5r21uoA1rWiNFBJgWN8W52QYbw6UV9jAQDbGNsqH": "WAGMI",
- "GnM6XZ7DN9KSPW2ZVMNqCggsxjnxHMGb2t4kiWrUpump": "WAGMI",
- "3gqBzYggchmzxCBq5v4BGT4TfmZcm8agsaRqv8bkpump": "$WAIFU",
- "GZT8cXcv2uCvFZFi8gGiryXrTXvLZ9RYkPjRuREypump": "WAIN",
- "9n8b1EXLCA8Z22mf7pjLKVNzuQgGbyPfLrmFQvEcHeSU": "FLOCKA",
- "EcQCUYv57C4V6RoPxkVUiDwtX1SP8y8FP5AEToYL8Az": "WLKN",
- "CXyvYhWSpqEbuTXfhfvDaKfHVHaeA9zU4r11cogdpump": "$WB403",
- "7zBbQAPGgoKvqcK74Yua8qGwEkEjAZxUPb5m3kKvvHyF": "WSB",
- "AFy7FjjKWhQjyebp1dWoJwKUxiPwop9Y7LDFBcPYpump": "WALLY",
- "Fo6tfAkXj74X6j8hati8SxtwZHHcdGeqXVUPLP9Abvqu": "WALLY",
- "LZddqAqKqJW9oMZSjTxCUmbmzBRQtv9gMkD9hZ3ondo": "WMTON",
- "Xs151QeqTCiuKtinzfRATnUESM2xTU6V9Wy8Vy538ci": "WMTX",
- "FV56CmR7fhEyPkymKfmviKV48uPo51ti9kAxssQqTDLu": "WALTER",
- "2uZzU9nxXjyy8BR5Mcdah8hTezh7ftqgpXx8agAqdCPo": "WAND",
- "Bz7vVzQhm2KMW1XgcrDruYega1MiwrAs1DQysrx4tFkp": "WAP",
- "8opvqaWysX1oYbXuTL8PHaoaTiXD69VFYAX4smPebonk": "WAR",
- "C9dJfTGUzhuqPWxh9mcDr66JZN4uzXh2gh9EWnEdpump": "WAR",
- "D26ztC28zZf1QBhrY47NtvK7aeLfDvj41H5wgkUqpump": "WARDOGS",
- "XsZUSqxAXKJkEimvD4CoVvEb4WUC92TFgj5zRtBxFeL": "WBDX",
- "3fP61JWqLxxrvBv5NSxJdAz4GtCB7UpfU3UFxZTgj1yG": "WAR",
- "FPvKvWzSzDZqgYmSZUetrkpUXSwo2VtpR4BynVYondo": "WMON",
- "BEaQ6StD98khBPqKjT4mLasqoDa6RuBCXcK4aNMFpump": "WATER",
- "WATERR4RJzjvDGZjuMhiy155f6uA9qbbjNFfRPvAKfP": "WATER",
- "D6qB6husvNXx6vbHDaCf1xRRxeEya4j5XQ5ojravpump": "WATER",
- "B6h248NJkAcBAkaCnji889a26tCiGXGN8cxhEJ4dX391": "WATER",
- "8nZZoqBYy13LcMiso4ZdNLRK8BpymJAbyfVdZ1RcEBAq": "WAT",
- "Gzb9XduScnJqZ3GKbazbPLWx8Nw8V6uM9VqEZLe8mBLV": "WMDR",
- "B2oEUCmCGktPXPkQEzFTPYjnWpUPCotqzaT2eoPopump": "IF",
- "5XUUN5z1yBPEwoLztu4qMenmFe6GQnZptBFsnFnEpump": "WAVE",
- "4AGxpKxYnw7g1ofvYDs5Jq2a1ek5kB9jS2NTUaippump": "WAVE",
- "8Sk2EJ9oo25b7Mmf4qd5gJw6z3738AXvAbkuSSpQpump": "WAWA",
- "yJcC48AWnaFQxb4CfZY6U19aQr3Pw6RKVhuGCLVpump": "WOTF",
- "FyyDnWQUAcGoJ4L7ab9P7VUFmT3Bs2ggW2DSJz5cpump": "W COIN",
- "wxmJYe17a2oGJZJ1wDe6ZyRKUKmrLj2pJsavEdTVhPP": "WXM",
- "21nnfR4TkbZNLwvRrqEseAbz7P3kxKjaV7KuboLJpump": "WEEDCOIN",
- "E2gLkTXSbbTMmJM19xkquawun2ShJSi7G59A8c2PtbFa": "WEED",
- "vyygC9ojzrPKWbHZMCVg6xNiNTHAnXGmAgARfeopump": "WEEPI",
- "9pWPUXoZKWNPWyaegPQeR3Kn8aFz9nrGtm5jeAFzpump": "WMM",
- "AHE8yDYQJTVqmAYwgMoBRq5YzL1efaXhaXrUeMmX1tED": "WELF",
- "L6ZE5qCpVVSqLePz64CrwkgyWoPF9M7tB8BeFH4ondo": "WFCON",
- "CfgmB9iTWABdYh3CHQQDUGtWy18rMNAEEqyp4GrJpump": "ASS",
- "Dp4fXozKtwgK1cL5KQeeNbuAgFpJtY3FbAvL8JrWpump": "BOOBS",
- "8tBUx7LPnA2utkURbyWX85hUus3JhYU14svS3YfGpump": "LEGS",
- "9W8ZfTMtQS7iXxiMhMyLN4oqciv92py6td2mTixLpump": "PUSSY",
- "23CTZMjEYNNZUE4itfn3iv6kgM4xn7X7dx1kVX1Gr8Xi": "TITS",
- "3J5QaP1zJN9yXE7jr5XJa3Lq2TyGHSHu2wssK7N1Aw4p": "$WEN",
- "WENWENvqqNya429ubCdR81ZmD69brwQaaBYY6p3LCpk": "WEN",
- "Xs4uNhvBDAcp2mz3g9XR5q3vzLgmF1ANWxJgWk2d5u3": "WENX",
- "LABSsPBFwfFTW3x584dB6pSen7RWVpx6URP8wfAVdMt": "LABS",
- "aQqFBwSUpNKLuAE1ovbrPKQgZJKB1wywBpuiBoJ8GFM": "$SOON",
- "WHYoaBumcmxCqw38y2mjs4cVkCBgwiDizbMVvcejmGT": "WHY",
- "FLqH2jB2DZPJP5nnVFAakRKaNTcDZtq71Pnpp6Aondo": "WDCON",
- "3MKZDaqgMgZJmetXStD47W6FqrcAsK9UaYgNWK2apump": "WHALEFLOKI",
- "Fr7vfUAWgmg84L3VuHKiyzTJx3x3V6xU5pn9328Wpump": "WHALENTINE",
- "GTH3wG3NErjwcf7VGCoXEXkgXSHvYhx5gtATeeM5JAS1": "WHALES",
- "EaxDJbZ6L7FdgQMnHRwqTrasJXQRfuHY5oDtNG1vpump": "WTF",
- "3e2ENpKfvrrAfYtCRUzetJWQbJy79fAteaPehqjupump": "$WALLAH",
- "s6nhgeppKdbfockwnrUAA5art6ca4Sa4enN5fNApump": "WHATEVER",
- "C4u9GYmTvtaGa1a7q6iijn5DK2GYe78fqEeoPwrpump": "WAPE",
- "9fvZcQkCdRwm74uSVf46sfMHiYHtSta8ZdMCaLYFpump": "IF",
- "Adq3wnAvtaXBNfy63xGV1YNkDiPKadDT469xF9uZPrqE": "WIT",
- "CZJzsywCWkqZNa6CRW3Av6WVNCvTX3EuBwS2nar8bonk": "WHATRR",
- "84yCF7hyUuRNAra9BjFHVDpnRdGXmfsV2emyZwLjpump": "HOUSE",
- "HJ39rRZ6ys22KdB3USxDgNsL7RKiQmsC3yL8AS3Suuku": "UPDOG",
- "DHAajf71VVT9s98hmyFyr3JDnr9KfotFbM5gQJV5bonk": "LORE",
- "6iA73gWCKkLWKbVr8rgibV57MMRxzsaqS9cWpgKBpump": "我的刀盾",
- "4Q8zRhEUH8oTJvfd1qXxE2m7zWSVFjHHD7sZPvWWpump": "WHENHE",
- "5XCZVKbQhDQpyP1kc12UsyqarN7d4gFZyTdk2Jsdpump": "WHINECOIN",
- "ATeTQcUkWGs7AZ15mCiFUWCW9EUL7KpDZEHCN1Y8pump": "WHINE",
- "9UNqoPEXXxEnEphmyYsZYdL5dnmAUtdiKRUchpnUF5Ph": "WHISKEY",
- "whispF7G9DHaojYHe2cdhRX5EMJzGBdqq7R57kL6inL": "WHISP",
- "EEBA6E69rhvGgLSs633u5qVeNjo77fp2wY3yj8Aipump": "WHISPY",
- "6Hb2xgEhyN9iVVH3cgSxYjfN774ExzgiCftwiWdjpump": "WHISTLE",
- "GJgHsc1HU4ibmzW6oWQr8L2RRT95ATc1BoNuLkp94AwU": "WBS",
- "BykkD9369RvXuEDbR7pTRz49b7cfLRTzHgSVoqK8gc15": "WCC",
- "86WM5NBUtRWTHULKrspS1TdzVFAcZ9buXsGRAiFDpump": "ICEBEAR",
- "ENWC66tsY6cyqSrd8a7S9ETc712xCcSAuGcRUwSMWhyo": "WHITE",
- "HhUVkZ1qz8vfMqZDemLyxBFxrHFKVSYAk7a6227Lpump": "LI",
- "5qmL9rCSfZ7pBYAsaoeG8SP76ZELeRCK8XtMmYZvpump": "WIBWOB",
- "WFcgBXhGxyFDp43AgT9opi3gyJLtfEo5bodLKuQpump": "WIDI",
- "CceCXFy4UeXheTpf8sn1bpECxMQeH5BTyxQK4BdRMf2T": "WIENER",
- "4y3oUrsJfSp431R3wJrWiaLxRPsnYtpkVJmoV2bYpBiy": "WIFE",
- "CoRQpMjhBx6AsrzKJJZyzJoH52GoEKShM3CVumyzpump": "WIFMAS",
- "21AErpiB8uSb94oQKRcwuHqyHF93njAxBSbdUrpupump": "WIF",
- "DBh9F2wSukCJdZeNkLYe2LMYnCwMyLcnBgeCf4pgpump": "PIGGER",
- "FVvd3s9dZYzsgitkJyWbmycSc8MkYZjyF7oqAEvmSxTZ": "WILD",
- "8aB8hdzyqjCJdtP1rfdLNX8bGDjjM8S42BZ3j4zNVtRN": "WGC",
- "3rSKhRtrjHnSZhRsgoAtrWRVM8rcf8DYv8Quea1epump": "WILL",
- "4RYtJLcaGKMkYbodJ7X8QYPd2SnRWRvSVWMxfzwRpump": "DOLLARCOIN",
- "3bzeQJqDPfQQbxJ6VmtMkXyyQEJrj9HS1SMvHR1Hpump": "WILSON",
- "CsxCtA8usvWKdRhe7KhLU5GgwzYaLkoHsz1MKBVZ4W3M": "WINR",
- "HSpwt7Z4Hb3139FWZR8W9q17yWpxffm47a3g63bQpump": "WINSTON",
- "4j2gUEmfbSAacvSSd6yXo8yEzXCAUVeoXrqLVV3apump": "WINTER",
- "2GXmB95pGD3pHV4mzNq7YsmyiEmVYWQLptbwYqgdpump": "WNTV",
- "o6U1Sm6Vd7EofMyCrL28mrp2QLzgYGgjveHiEQ5ondo": "USFRON",
- "gnoSQSNTNZHViqVfxCcPDVxcRA29mrJL7C6JqYLondo": "DGRWON",
- "9z4EGSy2KBvUX3zb4pJSWdoFKs6nX4SNh32JepBTpump": "WISE",
- "3gJZBpRUPZnQ9xbLDwuEJ4GC2576Y2dYriJDsUJpmoon": "WISH",
- "2TobzM4NNpEvyVAEpFC8AkxJGBHz8fFgMksK1gBy5dub": "WIZ",
- "8oosbx7jJrZxm5m4ThKhBpvwwG4QpoAe6i4GiG19pump": "WIZARD",
- "2AXfPwXtqy8KVwWLcHNNHbh9KejZhDb5WhKnoH4Cpump": "WOB",
- "9yZ5Ru8pbmJZ6Q2DKLCGXkaLNwkm83cnJ4QCw4PFpump": "WOBBLES",
- "5kLu7okC3yrL2NKznwQtkvCVoGGyo3iWz2nht1fXbonk": "WOF",
- "6bn6rKWbTRAQwizwqEfcmpAtoAMnqzfG7F8DYMK5reYn": "WOJAK",
- "7VYXBSQa79BuBrutcdKMXJodT8TLS7aDv6chaF3sbonk": "WOJAK",
- "7oLWGMuGbBm9uwDmffSdxLE98YChFAH1UdY5XpKYLff8": "WOJAK",
- "8J69rbLTzWWgUJziFY8jeu5tDwEPBwUz4pKBMr5rpump": "WOJAK",
- "wokaXpAAtg6jg9wa5PEvEFY4vuh6Zrcd47vBTL143wE": "WOKA",
- "BTr5SwWSKPBrdUzboi2SVr1QvSjmh1caCYUkxsxLpump": "WOLF",
- "9ZMEz6nmr4RWs92ASFKxFGfKpWw8cbUp2ZP3EhdqwWPr": "BALLZ",
- "BEgBsVSKJSxreiCE1XmWWq8arnwit7xDqQXSWYgay9xP": "WYAC",
- "GEKjZKJZgQTCbi9evTW2GmhyamH3sq6Lid9dQMWqEcCY": "WONDER",
- "6bunJ76HV9SCDHkukezST3VKzQKJ8JtjTQQ92UD7pump": "WONEY",
- "8KvoBfxiPiVp9b9mxSFZHpJdX9NUtbmNFhAGggLDpump": "WOO",
- "WARcU61sECeEK5DEbkY3wcjGxSGr4W8bVUpKbBNbgbu": "FINE",
- "5UF9Q7tdkGnZy8MoMrYqe6tcAZJbSaNWMGuUnJajmoon": "WOOFI",
- "9nEqaUcb16sQ3Tn1psbkWqyhPdLmfHWjKGymREjsAgTE": "WOOF",
- "AZpgAvSHUdzDHd7sJsQZgmKkz6ryHAN1fxkGWJ5Ppump": "WOOLFUN",
- "47NF9q76FaLAbZQmBaHeeUWYsEn4Rt4qjmh1oACipump": "WOOLLY",
- "Dz8VutERqbHR2aFL5A3s1Ky4dG1unJT1jUFXXPaY9ytX": "WOO",
- "A3HyGZqe451CBesNqieNPfJ4A9Mu332ui8ni6dobVSLB": "WOOP",
- "F7Hwf8ib5DVCoiuyGr618Y3gon429Rnd1r5F9R5upump": "WORK",
- "WLFinEv6ypjkczcS83FZqFpgFZYwQXutRbxGe7oC16g": "WLFI",
- "WMTXyYKUMTG3VuZA5beXuHVRLpyTwwaoP7h2i8YpuRH": "WMTX",
- "6KXjdTtGqXMawUqcAypAYXCdav7rXQYZjDyejfjQpump": "WM",
- "atVjZ7uM8sVrLFi5Xe1JiLGW6mW9pvQdTCWzhNFpump": "PEACE",
- "JCcd7NmyHVmiuycHP6drEesBSZhZUJXhBMbhxq42RNg3": "WRT",
- "DoLdHPVQixK98xmDfnNh3FfF2fSFCikK7DbFDGtwpump": "APPLE",
- "CLyhG2aVrnvbxXAXokBGvKjmNfsamPKtGW4Gu9AHpump": "WSOD",
- "HtrmuNs4nESVg5i8gHyufDpGN5HHKqPmFfbQV9yupump": "LOLCOIN",
- "865GVDdESzXiNvygSUt7yFeJLrXDyn5UpGNfYuxfpump": "HENRY",
- "85VBFQZC9TZkfaptBWjvUw7YbZjy52A6mjtPGjstQAmQ": "W",
- "98sMhvDwXj1RQi5c5Mndm3vPe9cBqPrbLaufMXFNMh5g": "HYPE",
- "AdsT8339RRmJbYCJo6d75cAbTguC7yMk4pft4e19pump": "WORTHLESS",
- "GEo9uMBTvagNAX6Paf4KEuZ94Wi5K1ZjYfvhoSfKpump": "WORTHLESS",
- "iUdvUaxyRHh8PYVcmkgBpSJu5evpW6jsSLv8RCpmoon": "WORTHLESS",
- "9pgfoXFAN6oT9dNswE23oj2kCkCpoLPzHVpTKGAtmoon": "WORTHLESS",
- "J1Wpmugrooj1yMyQKrdZ2vwRXG5rhfx3vTnYE39gpump": "WOULD",
- "F87d3uwBN7epMt89bUaFdoQmw24Eggo1jjmH5Zpnpump": "META",
- "xALGoH1zUfRmpCriy94qbfoMXHtK6NDnMKzT4Xdvgms": "XALGO",
- "C1MHyoTJpRTeS9AQCyspNVu2EWAYCZwmJ1jNkEArFP1f": "WAPE",
- "5XZw2LKTyrfvfiskJ78AMpackRjPcyCif1WhUsPDuVqQ": "WBTC",
- "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E": "SOBTC",
- "21BTCo9hWHjGYYUQQLqjLgDBxjcn8vDt4Zic7TB3UbNE": "21BTC",
- "3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh": "WBTC",
- "GYKmdfcUmZVrqfcH1g579BGjuzSRijj3LBuwv79rpump": "WDOG",
- "2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk": "SOETH",
- "WFRGJnQt5pK8Dv4cDAbrSsgPcmboysrmX3RYhmRRyTR": "WFRAGJTO",
- "WFRGSWjaz8tbAxsJitmbfRuFV2mSNwy7BMWcCwaA28U": "WFRAGSOL",
- "zZbQjiRg8uSxZaPu996XuviuZeSY6nsaMuutKZQBJga": "WFRAX",
- "mzeroXDoBpRVhnEXBra27qzAMdxgpWVY3DzQW7xMVJp": "WM",
- "CrAr4RRJMBVwRsZtT62pEhfA9H5utymC2mVx8e7FreP2": "WMON",
- "HcFYJVeRGNR5YJjJVvjtpcA6kXEE2v7QqY1pwymG7QRL": "WPAX",
- "2GBVt2ENvbHepuJMWYTPkkfpWUabAhsaXToYw8UphxS3": "WRBNT",
- "So11111111111111111111111111111111111111112": "SOL",
- "3rQK45d1ojXR7vtvCmeNjKKVycnVWqaVcP3zk1G39RJR": "WS",
- "CXLBjMMcwkc17GfJtBos6rQCo1ypeH6eDbB82Kby4MRm": "USTC",
- "9hX59xHHnaZXLU6quvm5uGY2iDiT3jczaReHy6A6TYKw": "ZENBTC",
- "JDt9rRGaieF6aN1cJkXFeUmsy7ZE4yY3CZb8tVMXVroS": "ZENZEC",
- "5B8jpiDY6WftBdwEyL3LWwYKeDSVikUpXoSYZhFxbonk": "WRONG",
- "8C4RygkxmePm9ys1qCcAB46dUCXNQYTaqfxS5mBrpump": "WTFO",
- "sdFmUe2Q8Ho8SEhbp5uXU9d4wCZzD8fHSvhLC6mX777": "WUAI",
- "DaeRKF1nBMog8CTWp5SBwkGaPed4RzHaofoCi4rboop": "WUFF",
- "73xsLcBnLnc9bh81cqVKqj8uEyiarXng5ZwJuTbnVebG": "WUF",
- "9b2FQBXgUZTpZk4PNfJa2sNPK3qf6kS4PxnQQmWpoa5E": "WUKONG",
- "ALR5X2H6THn2VDPoMtkVwxVktcN1kQGvxCwLfejzpump": "WURK",
- "DG5bH1BnfjB5YL7Vt3GjykkUKf6maDUW3jYvdNa9eEVa": "WUT",
- "2yoTWgHH8KjyXKi2zrRZmA6AbZGa9zztnE8EFCboxWTe": "X1000",
- "DEffWzJyaFRNyA4ogUox631hfHuv3KLeCcpBh2ipBAGS": "X1XHLOL",
- "6cNcXWqYvK9nhD1TsjJ1ZH1KATXcaPaRJtZPHyVkJoBs": "JOBS",
- "3E7LWnvBjKiauBJfbSFe86A1i5Rnzzs853bbjTmApump": "WALL",
- "6ikxp2KnQcdCik8Aadi2ScE7qgH4j5C7BvSyA29Wpump": "X4PAY",
- "KfByHk48ecitUq8gXji2vr9smmRJKtqJwGAh2E9pump": "XAIC",
- "PreC1KtJ1sBPPqaeeqL6Qb15GTLCYVvyYEwxhdfTwfx": "XAI",
- "XANDuUoVoUqniKkpcKhrxmvYJybpJvUxJLr21Gaj3Hx": "XAND",
- "XAnDeUmMcqFyCdef9jzpNgtZPjTj3xUMj9eXKn2reFN": "XANDSOL",
- "69G8CpUVZAxbPMiEBrfCCCH445NwFxH6PzVL693Xpump": "XAVIER",
- "3wppuwUMAGgxnX75Aqr4W91xYWaN6RjxjCUFiPZUpump": "BANGERS",
- "XBGdqJ9P175hCC1LangCEyXWNeCPHaKWA17tymz2PrY": "XBG",
- "A8YHuvQBMAxXoZAZE72FyC8B7jKHo8RJyByXRRffpump": "XBT",
- "AHcxvCP5se2DiqfcXwBz8i7WygwWJdd8f9S9t6nd4YsQ": "XCAD",
- "9HAZrXJx5QXzBfJynRQXkHr9DG4Kk8dzuuQnMfz6pump": "XCHANGE",
- "BmtmfGfvF23sqKh5YCAVxgf9AWYpJc5zqyySxHi8SLom": "X",
- "EhkDgP8e5sz16AFCWUCYJzVug1zvpDLTEHxH4WAFpBFA": "X",
- "9Enb2cGtfYyAjCQedPUYd6Hfq2gkqzKH114KkDRZpump": "XD",
- "ERtzyCSu9FPvdxwsUS13cueHfFWQNkSvbKh5nTpUpump": "XEND",
- "J5LugyRpwHi4TYB16UYWpDuSx6z5zsuJ7pMjU95Cpump": "XENO",
- "Db7ZUaWTThwZy7bVhjn5Dda8D3fbbAhihcxPV4m9pump": "XENO",
- "9ezFthWrDUpSSeMdpLW6SDD9TJigHdc4AuQ5QN5bpump": "XERIS",
- "D1zY7HRVE4cz2TctSrckwBKnUzhCkitUekgTf6bhXsTG": "XEXAI",
- "HP6ypiCX4yjzSxpfJExEcydSU1BiuuvGhgrKCLKopump": "FRACTAL",
- "3rXPMXUHpRCYpYfdZjL3ut2fNtpW94Zik4GH31eRpump": "XGR",
- "5gs8nf4wojB5EXgDUWNLwXpknzgV2YWDhveAeBZpVLbp": "XTAG",
- "GnaXkbmMV1zGK6bRCQnM9Jd6Jv2Hjw5b2PFVBaKEE5At": "XIAN",
- "EDavhezsuNnhdoAKPExWaMtnuhq6FVqoBYnyFEJLLBqC": "XIAO",
- "5JcdnWEwuHh1v3SAARq8zH9tEwDQGpaHzBrZ81m4pump": "XING",
- "7qDrjF1zkDJA6LombCda3duwC1ABbAYancTiRHZwbonk": "XING",
- "7NoFtDpmQvE9JsRv7o6zgYZJBEcixWumJaZsDoyrpump": "XINGXING",
- "7JoGUTeaXkjcMGa6xJP2idYNYiLreto1WnsACHnpw3Gd": "DEUS",
- "9BYVxhYF4tWSRVyJUBSVC8PaAhuuiCiAbmfy4hUApump": "XMAS",
- "5csfa95Xf8ebiCwP9joQ7mtC8KwFvnnejnYx5FbYpump": "XMONEY",
- "xNETbUB7cRb3AAu2pNG2pUwQcJ2BHcktfvSB8x1Pq6L": "XNET",
- "xoUSDq85Rjsb6SbUwJyreFgeWQvxdkT7R3c3g7s6p5Y": "XO",
- "HEPvyunjSoiua8rAWZVMjgZ5TLp9vMQ61iGQh2u7pump": "XOGE",
- "Ckit5s1Cpc3RdMh1HrhfW2nAy4PnkkgjXgXMeykbpump": "XONA",
- "677jK6xujhRFtBcD7Szn32tt2MSv4k6qZ4v3nGMgpump": "XP",
- "BoMbSn3KcWsUe1dgz5ddJrRaM6v44fpeARNA9t7Dpump": "XPI",
- "DmxDBXTxEnNXVNNVVZe9QhgoKnr8anjE1b49dpZapump": "XPT",
- "AY1ZUqnLhrBwtrsKb2EJY4Hthaq9aaorifhFkQQPory": "XSAI",
- "2vfBxPmHSW2YijUcFCRoMMkAWP9fp8FGWnKxVvJnpump": "XTRADE",
- "CYDZoP9MvtJqyorDCpEh53pqQJ5FCe8RTjE2NK1wpump": "XGO",
- "7NaZ55Pt7Ah3xPsmWRfdEi2mv3dsd9TpHSWhTEt6pump": "YTC",
- "8fLJCxZiMDd4e5wsXAGWEDdX7q2UgdW7EKeQU7jypump": "YADOM",
- "GdZEGK9Dv61EbpJ8fYnJZcnJvmhwF6uS6mVVkSfSbonk": "YAGI",
- "5dDTxqg38NUY6ZKKGXXjaopWHt2xc3zSPoKhKmEEpump": "YAIT",
- "AqEHVh8J2nXH9saV2ciZyYwPpqWFRfD2ffcq5Z8xxqm5": "YAKU",
- "7otQqMyZrVLfVg3nf6BdxZLDL52q2A1e97H3GCi1daos": "VYBE",
- "3gcdoCBQMKAFVopsQ377X7JhkcNPg9fwPY4eW46Apump": "YAP",
- "H1aoUqmp2vJu5o8w3o8LjrN6jKyWErS69PtYxGhfoXxf": "YAPPER",
- "8CzPPqenpfRXvjE5DHfE3kMDgJhHwWZ1WXRzs44KsamW": "YAPSTER",
- "EgHo1Tq81VHKSYSx9KiWEsZvKRb5fZD9M4y5HPyUmoon": "YARA",
- "7eLSZuUZ66YA1JPYmpG9ApgoTdZmzHDfz32YngbPpump": "JUAN",
- "HK6hRLHB9orDKK5MffpCKxdLLRqiaqqUxN2vEoQQpump": "YEE",
- "3JVxH5QT9z3v7Gi2z4K4N69Bma6PHj8uovX8tYdQpump": "YELPE",
- "6r6YZkHNmphgZYYrhMzrXSXqa9i8MJhQigM1jCetVvbQ": "YU",
- "6brGsbvP1PTitDGGsz1TXF2CvvvRkS5QvQA8UH3ooe7i": "YES",
- "FuyeX8cpctBwQVDFYgKxYh1JgiXCkK9g4RBVCXm4pump": "YETI",
- "DR9fWuj3XRFyNzxk1rvkwMMYA2WHj448HgVJduQLpump": "YETI",
- "3VcKofugG1SPJmjuiEZCJL5mk1JkyqGZ19ByeMWXVWfK": "YBTC.B",
- "8ougyS81NXMKVTRvf8wdxD6DhbtJ5hcDRXhuE27ApYLT": "YLT",
- "8SNKhDsVUhnwuRzGAKsK4E2SYTcoJzocPKQyoBryjwVz": "YLD",
- "7D1iYWfhw2cr9yBZBFE6nZaaSUvXHqG5FizFFEZwpump": "YNE",
- "EjpYgSJ7FHWjyTNeuDvA4rfdpCP5cnbmfnqNNyyspump": "CHAT",
- "BNSPDd1Ws7AqiaEMZWVA5gcuAYGiLFZYAzXz11BGpump": "YOD",
- "nDrv1j5tkhmBEJTAmEkEn19kjw54d5GXN8e68HLpump": "YOINK",
- "5e898RCuzJkv7J6N3hNxK5pK6xZWM6RzZDjS8Esdpump": "YOINK",
- "E2BLSv4tXo7qA4Pr3nkJqxyn6743peC7x8E9D5s8pump": "YOMAMA",
- "GF8ysB8rF9WjhrK5uVhRReubJtWpPzbztB7gVfAgsurg": "YONA",
- "ENTAzGHF1YzeK92r6GFFvpbXuWPt5MV3gjckfJUS5i9i": "YPP",
- "7SdFACfxmg2eetZEhEYZhsNMVAu84USVtfJ64jFDCg9Y": "YOTO",
- "BXtTxGMRygG7DxufDFVaGP1WdvxSscWN8VoQ2zLhpump": "HAPPINESS",
- "QpRvqVMPG4o5y5fARHR6L7aK1x5vdWPQEiEjMkVpump": "POV",
- "F7pB3ZdfBnyFw2LRHydWEn9BmhEa5XihXLjhySFRpump": "NOTHING",
- "EkHr62PC6Y1axrLS7cR8YC4BZeW19mtHxQLCLMrf9vnq": "CIRCLE",
- "ANAuiz2JjRvNtyW8cd7UsQ4LRWB1PTGhyrgMWPxtpump": "YOUNES",
- "FjK6rqU6QzUeNtmK6QQ78cCuS5AHAhcm4HgJkdsvXaep": "YOURAI",
- "BAAF8R9EBNAo2aCPQzYiP6hEx3TXKiNads2MrdDjpump": "SLOP",
- "By5XddQNE4SB2XbgvreFeMNHL5zqgGqypiN3Xor3XmvM": "YOURMOM",
- "7mM2D6brqpKSZ8ttuEehf1XCukQMJSHutQXBQxtypump": "SAVINGS",
- "GnDfrXWPs71J73CrfrNsuwPrR15Fu7oZfNxYRhHWpump": "OUTIE",
- "Etd4QU7PGuzh4ozkzzBBjMmySNkU21BZamB7qPR1xBLV": "YOURSELF",
- "66gsTs88mXJ5L4AtJnWqFW6H2L5YQDRy4W41y6zbpump": "YOUSIM",
- "qfAV15JCvquMYpjGGkhQGr8x2zTiw14pCpUCjXLpump": "YOWIE",
- "Gtj3QCZgZNbqzpqQVKzpakgAbTEwPt6LdiLjWYNZpump": "YSKA",
- "YUYAiJo8KVbnc6Fb6h3MnH2VGND4uGWDH4iLnw7DLEu": "YU",
- "6XRFXWBrLmswPsJtiEdMataCKJfeD3vVVk7HygSpbonk": "YUCKY",
- "9VBhKuR9DxDP1wQCi9MPFY5q8fkYb62CPUYpx4Gppump": "$YUMI",
- "7fRQixgMhULQxNQzaJrFEZyjmrBgJi85up9gZrcupump": "ALIVE",
- "4cp9JPLZBEAvw6KQbfxnQEEVHVd7wne1gD8FEZKupump": "YUPFUN",
- "AbBADaxdQ1LtrU7sN9xvf4326ECSYbsUB37ddbRrpump": "YUREI",
- "mm7g78aMJZv8QB4Q15qbsM3UQJZWof85vwC2NSxRh2Q": "YURU",
- "Co22X8zmGHsiYKcK9sRq53MAwdDQcDdV6uvJtSLSpump": "YUTTY",
- "DrZ26cKJDksVRWib3DVVsjo9eeXccc7hKhDJviiYEEZY": "YZY",
- "8vCAUbxejdtaxn6jnX5uaQTyTZLmXALg9u1bvFCAjtx7": "ZACK",
- "DtTPiFFX5oNnozjfoyYfDRFcSdPDuJNkYaZeEvSCBAGS": "ZACK ON BAG",
- "GorvUUSkJGSzJUebM5W6berUkZ5pG8nmnn7tmk74pump": "ZAILGO",
- "EAyvG3YKGsnHkQLcmY3R8YRSab3wu2rC288U8f8PVwND": "ZALPHA",
- "4Zp52aF4hZi9fzH19xpbWKYKQvgLyCN67KFbrQDqeTKh": "ZAMA",
- "HxPoEHMt1vKeqjKCePcqTj6yYgn6Xqq1fKTY3Pjx4YrX": "ZAP",
- "CCz5hPGJobjtVGGrEiUhHAz9qCEt1KyKxFkGBjVcjuvo": "ZAPCAT",
- "zapzy5CRnuo8tVP7p4E1Ec6mc7XS43JHiiqv7FLniXa": "ZAP",
- "73UdJevxaNKXARgkvPHQGKuv8HCZARszuKW2LTL3pump": "ZARA",
- "AbzXS6NfGvCtg5B1rqZ1JSfoDHkwTAeEYJkWkHhCe38W": "ZARO",
- "dngKhBQM3BGvsDHKhrLnjvRKfY5Q7gEnYGToj9Lk8rk": "ZARP",
- "DNhQZ1CE9qZ2FNrVhsCXwQJ2vZG8ufZkcYakTS5Jpump": "ZAUTH",
- "3QJzpi68a3CUVPGVUjYLWziGKCAvbNXmC5VFNy1ypump": "ZAZA",
- "n7EksMkvk3WT5FjQ3HBMLm9XYU3EnoXUSJ7PoWpxsoG": "ZAZU",
- "qiaupfns561LJPudU2YL48S2mx1nbekrn8V4RrpyJG6": "ZAZU",
- "8RSbsKW26WhHsFsM6jc34zSijvq6r7t6GmkYrfj8pump": "ZIP227",
- "GVvPZpC6ymCoiHzYJ7CWZ8LhVn9tL2AUpRjSAsLh6jZC": "ZC",
- "CCpTDK9dDdmvcQtpPrv6zDBWXgjqq5LrJHidJW7Jpump": "$ZBEC",
- "ZBCNpuD7YMXzTHB2fhGkGi78MNsHGLRXUhRewNRm9RU": "ZBCN",
- "zebeczgi5fSEtbpfQKVZKCJ3WgYXxjkMUkNNx7fLKAF": "ZBC",
- "7unYePWUHcpB28cnS65TpqT2qqmZaftRz9QABkdR8yN7": "ZEBU",
- "6r7rgqYrdEXrYrTT3bUdefJE7woHBNsWF7c8gkmFqdev": "ZECFI",
- "CA6DpicXuJUsSWziuV4oHmqpHTSMZLz9EGjYPyXJpump": "ZEKTA",
- "8vwqxHGz1H4XxyKajr99Yxm65HjYNVtqtCNoM2yWb13e": "ZAI",
- "5DkLaee4Ctm9v8bka1zGeuPUTbngZaznZsc1t3L4pump": "ZENAI",
- "ZenexEqqyiYCjykxYZr2cW6g3xVwQ5RggHmo245q5J5": "ZNX",
- "3pH7FnM3yR2Jy2c6vyXmsCiNi1rjQ7gerCq2pEUHpump": "ZEN",
- "9wpLm21ab8ZMVJWH3pHeqgqNJqWos73G8qDRfaEwtray": "CDB",
- "Zenko9EfTmbYVUw8RMjEW4vf7bNPSd419EjtpAFXeWw": "ZENKO",
- "5VsPJ2EG7jjo3k2LPzQVriENKKQkNUTzujEzuaj4Aisf": "ROCK",
- "2a1sAFexKT1i3QpVYkaTfi5ed4auMeZZVFy4mdGJzent": "ZENT",
- "By5umkRTaquaW1sgj5aTUwxPFWjJC26VBq982fadZNTR": "ZNTR",
- "8avjtjHAHFqp4g2RR9ALAGBpSTqKPZR8nRbzSTwZERA": "ZERA",
- "8x5VqbHA8D7NkD52uNuS5nnt3PwA8pLD34ymskeSo2Wn": "ZEREBRO",
- "G1r487Exo1Z5pLmkqLbdhT7s18WoRr6pDpdD3uSqpump": "ZCOIN",
- "AnGzGiQ6ddzdqWDuWy6vmibqDv8rsT2QKhcgDrwTpump": "GAYCOIN",
- "AhDD3J3SydBq1VrXkWsgH8Hb62FWtTqzgn3vafsRpump": "ZEREPY",
- "GKEGxPuznVZYHh5J4Hqk8kSabgPjJTYviLLhfF47pump": "ZERESYS",
- "FA7BUyYa1kGaLq34YTnMPPaCYcT1r8PWxM5yqjxALEwJ": "ZEREUS",
- "AA8nmXa7fwfYjYtKEaKwkcCKJL5UmkvXYXE7NVmspump": "ZERO",
- "Cf9hZDWdJsQPrt9q8yrTcyc9PSDmQUyXktHz6rFu8amJ": "ZERO",
- "H1hcBegR2A6b2mCGqhH5zA4sTZvMxrqT4v3fHY1kpump": "ZB",
- "SVdeWmHnXsSSeU6sE7tf6x8hwBG5jYuUW141pRapump": "ZEROCLAW",
- "6kP6Qjgo7Vke9HTe3tZ9DeRtKw2NDiE5fDABWEUspump": "ZEROC",
- "BoRiiSZ4hqtbCnQc7cWaEYTEtxmzRXyy5xaKCt7Ppump": "UNTAXED",
- "AWc8uws9nh7pYjFQ8FzxavmP8WTUPwmQZAvK2yAPBAGS": "ZHC",
- "BwUTq7fS6sfUmHDwAiCQZ3asSiPEapW5zDrsbwtapump": "SOLFUNMEME",
- "BAgzJnohH2kjSGkZwkMRWLr2qmYUEdWey6zavkUKpump": "ZEROPAI",
- "3n4jw9KSH3UtLeJ4JE1DDA2Y3TCAu8nmkfoznVPiEtjT": "ZEROS",
- "ZEXy1pqteRu3n13kdyh4LwPQknkFk3GzmMYMuNadWPo": "ZEX",
- "Fc1iGoPhSFz69dSfYSMbKeQjiyQ1FHibPpSkDiuApump": "ZTOCK",
- "Fe3sEB1cAt4TsETqmaopPQBto5o8TsY2W2NTw6H9pump": "ZEUS",
- "zBTCug3er3tLyffELcvDNrKkCymbPWysGcWihESYfLg": "ZBTC",
- "ZEUS1aR7aX8DFFJf5QjWj2ftDDdNTroMNGo8YoQm3Gq": "ZEUS",
- "GvRf47WPg9uaYcyXEs5UxHL2D39P7yTByBDrQcyMk5wg": "ZEUZ",
- "26f12PmBk77wQV1TzLe8XKkNBvMFggbuypxdtMLzNLzz": "ZIG",
- "Zippybh3S5xYYam2nvL6hVJKz1got6ShgV4DyD1XQYF": "ZIPPYSOL",
- "4PX31xRA1BaAyb2Js45ZKYp92VGWGp47yWeVs5CGVKbf": "ZDLT",
- "8qieHd2Ev6yn3qD2DQENXiNDuYRJ2wHFghNgpsnYpump": "ZK402",
- "3QQwbsqNMzy6JjwmoM9FJQ74ei1FmfoYj5jT3EhPpump": "ZKC",
- "4K3aMpVPggTWAw1jyN5cZJf3kpWjnfTYmxkVbMymhuwj": "ZKE",
- "6pKDTUavWbdHH27nUBeZNGDSmg3gw5XMGq6gAPUf264F": "ZKFG",
- "ZKFHiLAfAFMTcDAuCtjNW54VzpERvoe7PBF9mYgmeta": "ZKFG",
- "51mxznNWNBHh6iZWwNHBokoaxHYS2Amds1hhLGXkpump": "ZKRUNE",
- "9KmJLjfHxxd1LvwmAgvAT5oTFMaY8y15UiuEMZJKpump": "SHINE",
- "9Yn6bnF3eKLqocUVMxduh7WWqgQZ8DvWQDYTX9Ncpump": "ZKSL",
- "DTanHWf8jRg4cgiMfVYReU53J9Za2mGSm9cS3cahpump": "ZKTR",
- "CxpGDVrX2rA6penHD2zhopPYNMXAtXutizWSktwytZ18": "ZALA",
- "AwcCFuJgUYNYHXm6tHhr7DsXDY6FKvXUt2DFjmgHpump": "ZOA",
- "J1ow1c3ExcJYQmgNFRPfCp1LMYRf6P3A33isDcBmpump": "ZODS",
- "EGhdtB7B12ezVooo6CwqxjiFUUCJXbDXx7iE77uSpump": "ZOL",
- "HJBoRECiJddTZQZpuY8pHenf5CZ2yjju4npekmvbpump": "JACKJACK",
- "nBZEcHSG771mRbi4y2sSgKjfDUH8jsM2Eo5fNcASLeU": "ZOOMER",
- "9MBzpyMRkj2r5nTQZMMnxnCm5j1MAAFSYUtbSKjAF3WU": "ZOOMER",
- "BGqXaVjjQy4h3qgqgzT9TrzyAGqHmBKhgQwW1VFmeme": "ZOO",
- "HHkUs6Sh6mE5LeLonpAX3VFvpR8h8EYzjKHrt52Mpump": "ZOPA",
- "GgXVZA9Ax5uW2NG2VMQYmjkjBmwPekTE3BCJr7NXpump": "ZOS",
- "GnFMf6JVRhAqPbA9r8yW16xycynKNkXfbaYbusLEpump": "ZREAL",
- "PzuaVAUH2tfxGZcbBR6kMxeJsBngnsPLFotGJNCtcsd": "ZYN",
- "FefBQzgFmAynFwKAqfnyAXVv3bBXVgA1A2tuXEjbpump": "ZYNX"
-}
\ No newline at end of file
diff --git a/app/i18n.py b/app/i18n.py
deleted file mode 100644
index 4afe847..0000000
--- a/app/i18n.py
+++ /dev/null
@@ -1,44 +0,0 @@
-from __future__ import annotations
-
-from PySide6.QtCore import QObject, Signal
-
-
-class I18n(QObject):
- language_changed = Signal()
-
- _instance: "I18n | None" = None
-
- def __new__(cls) -> "I18n":
- if cls._instance is None:
- cls._instance = super().__new__(cls)
- return cls._instance
-
- def __init__(self) -> None:
- if hasattr(self, "_initialized"):
- return
- super().__init__()
- self._initialized = True
- self._lang = "en"
- self._translations: dict[str, dict[str, str]] = {}
-
- def load(self, lang: str, data: dict[str, str]) -> None:
- self._translations[lang] = data
-
- def set_language(self, lang: str) -> None:
- if lang != self._lang:
- self._lang = lang
- self.language_changed.emit()
-
- @property
- def language(self) -> str:
- return self._lang
-
- def tr(self, key: str) -> str:
- return self._translations.get(self._lang, {}).get(key, key)
-
-
-i18n = I18n()
-
-
-def tr(key: str) -> str:
- return i18n.tr(key)
diff --git a/app/integrations/__init__.py b/app/integrations/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/app/integrations/chainlist_client.py b/app/integrations/chainlist_client.py
deleted file mode 100644
index 429f9ab..0000000
--- a/app/integrations/chainlist_client.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# app/integrations/chainlist_client.py
-from __future__ import annotations
-import logging
-import re
-import requests
-
-logger = logging.getLogger(__name__)
-
-# Источники в порядке приоритета: первый успешный используется
-_SOURCES = [
- "https://chainlist.org/rpcs.json",
- "https://chainid.network/chains.json",
- "https://chainid.network/chains_mini.json",
-]
-
-# Шаблоны RPC которые требуют API-ключей или не являются публичными HTTP
-_SKIP_PATTERNS = re.compile(
- r"\$\{|wss://|ws://|localhost|127\.0\.0\.1|0\.0\.0\.0",
- re.IGNORECASE,
-)
-
-
-_HEADERS = {
- "User-Agent": (
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
- "AppleWebKit/537.36 (KHTML, like Gecko) "
- "Chrome/124.0.0.0 Safari/537.36"
- ),
- "Accept": "application/json, */*",
-}
-
-
-def fetch_chainlist_rpcs(
- timeout: int = 10,
- max_per_chain: int = 5,
-) -> dict[int, list[str]]:
- """
- Загружает публичные HTTP RPC для всех EVM-цепей с chainlist.org.
- Возвращает {chain_id: [url, ...]}.
- Не бросает исключений — при любой ошибке возвращает пустой dict.
- """
- data = None
- for url in _SOURCES:
- try:
- resp = requests.get(url, timeout=timeout, headers=_HEADERS)
- resp.raise_for_status()
- data = resp.json()
- logger.debug("ChainList loaded from %s", url)
- break
- except Exception as e:
- logger.debug("ChainList source %s failed: %s", url, e)
-
- if data is None:
- logger.warning("ChainList: all sources failed, continuing without extra RPCs")
- return {}
-
- result: dict[int, list[str]] = {}
- try:
- for entry in data:
- chain_id = entry.get("chainId")
- if not isinstance(chain_id, int):
- continue
- rpcs = entry.get("rpc", [])
- good: list[str] = []
- for rpc in rpcs:
- # rpc может быть строкой или dict {"url": ..., "tracking": ...}
- url = rpc if isinstance(rpc, str) else rpc.get("url", "")
- if not url:
- continue
- if _SKIP_PATTERNS.search(url):
- continue
- if not url.startswith("http"):
- continue
- good.append(url)
- if len(good) >= max_per_chain:
- break
- if good:
- result[chain_id] = good
- except Exception as e:
- logger.warning("ChainList parse error: %s", e)
- return {}
-
- logger.info("ChainList: loaded RPCs for %d chains", len(result))
- return result
diff --git a/app/integrations/debank_client.py b/app/integrations/debank_client.py
deleted file mode 100644
index 025eacf..0000000
--- a/app/integrations/debank_client.py
+++ /dev/null
@@ -1,133 +0,0 @@
-from __future__ import annotations
-import hashlib
-import hmac as hmac_lib
-import json
-import random
-import threading
-import time
-import uuid
-
-import curl_cffi.requests as cffi_requests
-
-API_BASE = "https://api.debank.com"
-NONCE_ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz"
-NONCE_LENGTH = 40
-
-
-def sort_params(params: dict) -> str:
- if not params:
- return ""
- return "&".join(f"{k}={v}" for k, v in sorted(params.items()))
-
-
-def sha256_hex(text: str) -> str:
- return hashlib.sha256(text.encode("utf-8")).hexdigest()
-
-
-def hmac_sha256(key_str: str, msg_str: str) -> str:
- return hmac_lib.new(
- key_str.encode("utf-8"),
- msg_str.encode("utf-8"),
- hashlib.sha256,
- ).hexdigest()
-
-
-def generate_nonce() -> str:
- return "n_" + "".join(random.choices(NONCE_ALPHABET, k=NONCE_LENGTH))
-
-
-def sign_request(
- params: dict,
- method: str,
- path: str,
- nonce: str | None = None,
- ts: int | None = None,
- version: str = "v2",
-) -> dict:
- ts = ts or int(time.time())
- nonce = nonce or generate_nonce()
- prefix = "debank-web\n" if version == "v2.1" else "debank-api\n"
- sorted_p = sort_params(params)
- K = sha256_hex(f"{prefix}{nonce}\n{ts}")
- M = sha256_hex(f"{method.upper()}\n{path}\n{sorted_p}")
- signature = hmac_sha256(K, M)
- return {"signature": signature, "nonce": nonce, "ts": ts, "version": version}
-
-
-class DeBankClient:
- """Клиент DeBank API. Прокси обязателен."""
-
- _api_key: str = "3b92c003-ddc1-4c2d-b36e-781838f362c5"
- _api_key_lock: threading.Lock = threading.Lock()
- REQUEST_TIMEOUT: float = 3.0
-
- def __init__(self, proxy: str, impersonate: str = "chrome124") -> None:
- if not proxy:
- raise ValueError("Прокси обязателен для DeBank API")
- self._init_ts = int(time.time())
- self._random_at = self._init_ts
- self._random_id = uuid.uuid4().hex
- self._session = cffi_requests.Session(
- impersonate=impersonate,
- proxies={"https": proxy, "http": proxy},
- )
-
- def _build_headers(self, params: dict, method: str, path: str) -> dict:
- with DeBankClient._api_key_lock:
- api_key = DeBankClient._api_key
- sign = sign_request(params, method, path)
- account = json.dumps(
- {"random_at": self._random_at, "random_id": self._random_id,
- "user_addr": None, "connected_addr": None},
- separators=(",", ":"),
- )
- return {
- "Referer": "https://debank.com/",
- "Origin": "https://debank.com",
- "X-API-Key": api_key,
- "X-API-Time": str(self._init_ts),
- "x-api-ts": str(sign["ts"]),
- "x-api-nonce": sign["nonce"],
- "x-api-ver": sign["version"],
- "x-api-sign": sign["signature"],
- "source": "web",
- "account": account,
- }
-
- def _get(self, path: str, params: dict | None = None) -> dict:
- params = params or {}
- headers = self._build_headers(params, "GET", path)
- resp = self._session.get(
- API_BASE + path,
- params=params,
- headers=headers,
- timeout=self.REQUEST_TIMEOUT,
- )
- resp.raise_for_status()
- new_key = resp.headers.get("x-set-api-key")
- if new_key:
- with DeBankClient._api_key_lock:
- DeBankClient._api_key = new_key
- data = resp.json()
- if isinstance(data, dict) and "data" in data:
- return data["data"]
- return data
-
- def get_tokens(self, address: str) -> list:
- result = self._get("/token/cache_balance_list", {"user_addr": address})
- return result if isinstance(result, list) else []
-
- def get_total_usd(self, address: str) -> float:
- result = self._get("/asset/total_net_curve", {"user_addr": address, "days": 1})
- points = result.get("usd_value_list", []) if isinstance(result, dict) else []
- if not points:
- return 0.0
-
- last_point = points[-1]
- if not isinstance(last_point, (list, tuple)) or len(last_point) < 2:
- return 0.0
-
- try:
- return float(last_point[1] or 0.0)
- except (TypeError, ValueError):
- return 0.0
diff --git a/app/integrations/discord_client.py b/app/integrations/discord_client.py
deleted file mode 100644
index 0862832..0000000
--- a/app/integrations/discord_client.py
+++ /dev/null
@@ -1,77 +0,0 @@
-from __future__ import annotations
-from dataclasses import dataclass
-from enum import Enum
-
-import curl_cffi.requests as cffi_requests
-
-REQUEST_TIMEOUT: float = 10.0
-_ME_URL = "https://discord.com/api/v9/users/@me"
-
-
-class DiscordTokenStatus(str, Enum):
- OK = "ok"
- INVALID = "invalid"
- DISABLED = "disabled"
- ERROR = "error"
-
-
-@dataclass
-class DiscordTokenCheckResult:
- status: DiscordTokenStatus
- username: str | None = None
- user_id: str | None = None
- email: str | None = None
- has_phone: bool = False
-
-
-class DiscordClient:
- """Stateless sync Discord API client. One instance per token check."""
-
- def __init__(self, proxy: str | None = None) -> None:
- self._session = cffi_requests.Session(impersonate="chrome124")
- if proxy:
- self._session.proxies.update({"http": proxy, "https": proxy})
- self._session.headers.update({
- "accept": "*/*",
- "accept-language": "en-US,en;q=0.9",
- "referer": "https://discord.com/channels/@me",
- "origin": "https://discord.com",
- "sec-fetch-dest": "empty",
- "sec-fetch-mode": "cors",
- "sec-fetch-site": "same-origin",
- "x-discord-locale": "en-US",
- "x-discord-timezone": "Etc/UTC",
- })
-
- def check_token(self, token: str) -> DiscordTokenCheckResult:
- """Check a single Discord token. Never raises — returns ERROR on all failures."""
- try:
- self._session.headers.update({"authorization": token})
- resp = self._session.get(_ME_URL, timeout=REQUEST_TIMEOUT)
- if resp.status_code == 200:
- return self._parse_ok(resp)
- return self._map_error(resp)
- except Exception:
- return DiscordTokenCheckResult(status=DiscordTokenStatus.ERROR)
-
- @staticmethod
- def _parse_ok(resp) -> DiscordTokenCheckResult:
- try:
- data = resp.json()
- return DiscordTokenCheckResult(
- status=DiscordTokenStatus.OK,
- username=data.get("username"),
- user_id=data.get("id"),
- email=data.get("email"),
- has_phone=bool(data.get("phone")),
- )
- except Exception:
- return DiscordTokenCheckResult(status=DiscordTokenStatus.ERROR)
-
- @staticmethod
- def _map_error(resp) -> DiscordTokenCheckResult:
- if resp.status_code == 401:
- return DiscordTokenCheckResult(status=DiscordTokenStatus.INVALID)
- if resp.status_code == 403:
- return DiscordTokenCheckResult(status=DiscordTokenStatus.DISABLED)
- return DiscordTokenCheckResult(status=DiscordTokenStatus.ERROR)
diff --git a/app/integrations/evm_rpc.py b/app/integrations/evm_rpc.py
deleted file mode 100644
index 6e42381..0000000
--- a/app/integrations/evm_rpc.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from __future__ import annotations
-import asyncio
-from concurrent.futures import ThreadPoolExecutor
-from web3 import Web3
-from app.core.retry import retry
-
-
-class EvmRpcClient:
- """Обёртка над web3.py для async-вызовов через run_in_executor."""
-
- def __init__(self, rpc_url: str, executor: ThreadPoolExecutor | None = None) -> None:
- self._w3 = Web3(Web3.HTTPProvider(rpc_url))
- self._executor = executor
-
- async def get_balance(self, address: str) -> int:
- """Возвращает нативный баланс в wei."""
- loop = asyncio.get_event_loop()
- checksum = Web3.to_checksum_address(address)
- return await loop.run_in_executor(
- self._executor,
- self._w3.eth.get_balance,
- checksum,
- )
-
- def is_connected(self) -> bool:
- return self._w3.is_connected()
diff --git a/app/integrations/http_client.py b/app/integrations/http_client.py
deleted file mode 100644
index f67f1b5..0000000
--- a/app/integrations/http_client.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from __future__ import annotations
-import httpx
-from app.core.models import ProxyConfig
-
-
-def build_client(proxy: ProxyConfig | None = None, timeout: float = 30.0) -> httpx.AsyncClient:
- """Создаёт httpx AsyncClient с настроенным прокси и таймаутом."""
- proxy_url = proxy.to_url() if proxy is not None else None
- return httpx.AsyncClient(
- proxy=proxy_url,
- timeout=httpx.Timeout(timeout),
- follow_redirects=True,
- )
diff --git a/app/integrations/lifi_client.py b/app/integrations/lifi_client.py
deleted file mode 100644
index ef72e90..0000000
--- a/app/integrations/lifi_client.py
+++ /dev/null
@@ -1,260 +0,0 @@
-# app/integrations/lifi_client.py
-from __future__ import annotations
-import logging
-import time
-from dataclasses import dataclass
-
-import httpx
-
-logger = logging.getLogger(__name__)
-
-LIFI_API_KEY = "aeaa4f26-c3c3-4b71-aad3-50bd82faf815.1e83cb78-2d75-412d-a310-57272fd0e622"
-
-# DeBank key → EVM chain ID. Единственная хардкоженная константа маппинга.
-DEBANK_TO_CHAIN_ID: dict[str, int] = {
- # ── Поддерживаются LI.FI ──────────────────────────────────────────
- "eth": 1,
- "bsc": 56,
- "matic": 137,
- "avax": 43114,
- "op": 10,
- "arb": 42161,
- "base": 8453,
- "era": 324,
- "linea": 59144,
- "scrl": 534352,
- "blast": 81457,
- "mnt": 5000,
- "mode": 34443,
- "frax": 252,
- "opbnb": 204,
- "taiko": 167000,
- "abs": 2741,
- "ink": 57073,
- "soneium": 1868,
- "uni": 130,
- "world": 480,
- "morph": 2818,
- "swell": 1923,
- "bob": 60808,
- "sophon": 50104,
- "xdai": 100,
- "celo": 42220,
- "cro": 25,
- "boba": 288,
- "metis": 1088,
- "mobm": 1284,
- "fuse": 122,
- "klay": 8217,
- "rsk": 30,
- "tlos": 40,
- "flr": 14,
- "ron": 2020,
- "sei": 1329,
- "gravity": 1625,
- "lisk": 1135,
- "ape": 33139,
- "ethlink": 42793,
- "sonic": 146,
- "corn": 21000000,
- "bera": 80094,
- "lens": 232,
- "hyper": 999,
- "hemi": 43111,
- "plume": 98866,
- "katana": 747474,
- "plasma": 9745,
- "monad": 143,
- "stable": 988,
- "megaeth": 4326,
- "itze": 13371,
- # ── НЕ поддерживаются LI.FI (auto-skip через supported_chain_ids) ─
- "ftm": 250,
- "movr": 1285,
- "iotx": 4689,
- "dfk": 53935,
- "nova": 42170,
- "doge": 2000,
- "kava": 2222,
- "cfx": 1030,
- "core": 1116,
- "wemix": 1111,
- "oas": 248,
- "zora": 7777777,
- "manta": 169,
- "zeta": 7000,
- "merlin": 4200,
- "xlayer": 196,
- "btr": 200901,
- "b2": 223,
- "croze": 388,
- "zircuit": 48900,
- "hsk": 177,
- "story": 1514,
- "cyber": 7560,
- "chiliz": 88888,
- "orderly": 291,
- "rari": 1380012617,
- "reya": 1729,
- "bb": 6001,
- "goat": 2345,
- "tac": 239,
- "botanix": 3637,
-}
-
-# Обратный маппинг: chain_id → DeBank key
-LIFI_CHAIN_TO_DEBANK: dict[int, str] = {v: k for k, v in DEBANK_TO_CHAIN_ID.items()}
-
-
-# ── Исключения ─────────────────────────────────────────────────────────────
-
-class LiFiError(Exception):
- """Базовое исключение LI.FI клиента."""
-
-
-class LiFiNoRouteError(LiFiError):
- """Нет доступных маршрутов для свапа/бриджа."""
-
-
-class LiFiApiError(LiFiError):
- """HTTP-ошибка LI.FI API."""
- def __init__(self, status_code: int, message: str) -> None:
- super().__init__(f"HTTP {status_code}: {message}")
- self.status_code = status_code
-
-
-class LiFiTimeoutError(LiFiError):
- """Таймаут запроса к LI.FI."""
-
-
-@dataclass
-class LiFiChainRegistry:
- """Результат инициализации LI.FI /chains. Передаётся в модуль как единый объект."""
- supported_ids: set[int]
- rpc_by_id: dict[int, list[str]] # ВСЕ rpcUrls на сеть (для fallback)
- native_token_by_id: dict[int, dict]
- lifi_key_by_id: dict[int, str] # LI.FI key ("bas", "opt", "pol"...)
- name_by_id: dict[int, str] # человекочитаемое название для логов
-
- def resolve(self, debank_key: str) -> int | None:
- """DeBank key → chain ID, None если неизвестна или не поддерживается LI.FI."""
- chain_id = DEBANK_TO_CHAIN_ID.get(debank_key)
- if chain_id is None or chain_id not in self.supported_ids:
- return None
- return chain_id
-
-
-class LiFiClient:
- """HTTP-клиент LI.FI API. Sync, использовать через run_in_executor."""
-
- BASE_URL = "https://li.quest/v1"
- INTEGRATOR = "RetroFarm"
- FEE = 0.005
- RETRY_ATTEMPTS = 3
- RETRY_DELAY = 3 # секунды
-
- def __init__(self, proxy: str | None = None) -> None:
- headers = {
- "x-lifi-api-key": LIFI_API_KEY,
- "Content-Type": "application/json",
- }
- self._session = httpx.Client(
- headers=headers,
- proxy=proxy,
- timeout=30.0,
- )
-
- def _get(self, path: str, params: dict | None = None) -> dict:
- """GET запрос с retry (3 попытки, задержка 3с)."""
- url = self.BASE_URL + path
- last_exc: Exception | None = None
- for attempt in range(self.RETRY_ATTEMPTS):
- try:
- resp = self._session.get(url, params=params or {})
- resp.raise_for_status()
- return resp.json()
- except httpx.HTTPStatusError as e:
- if e.response.status_code == 429:
- last_exc = e
- if attempt < self.RETRY_ATTEMPTS - 1:
- time.sleep(self.RETRY_DELAY)
- continue
- # HTTP 400 с "No available quotes" → специальное исключение
- try:
- body = e.response.json()
- msg = body.get("message", "")
- except Exception:
- msg = str(e)
- if "No available quotes" in msg:
- raise LiFiNoRouteError(msg) from e
- raise LiFiApiError(e.response.status_code, msg) from e
- except httpx.TimeoutException as e:
- raise LiFiTimeoutError(str(e)) from e
- raise LiFiApiError(429, "Rate limit after retries") from last_exc
-
- def get_chains(self, chain_types: str = "EVM") -> list[dict]:
- """GET /chains — список сетей с RPC URLs и native token info."""
- data = self._get("/chains", {"chainTypes": chain_types})
- return data.get("chains", [])
-
- def get_tools(self) -> dict:
- """GET /tools — доступные мосты и обменники."""
- return self._get("/tools")
-
- def get_connections(self, from_chain: int, to_chain: int, chain_types: str = "EVM") -> list[dict]:
- """GET /connections — проверка существования маршрута."""
- data = self._get("/connections", {
- "fromChain": from_chain,
- "toChain": to_chain,
- "chainTypes": chain_types,
- })
- return data.get("connections", [])
-
- def get_gas_prices(self) -> dict:
- """GET /gas/prices — текущие цены газа по всем сетям (в wei)."""
- return self._get("/gas/prices")
-
- def get_gas_suggestion(self, chain_id: int) -> dict:
- """GET /gas/suggestion/{chain_id} — рекомендуемый объём нативного токена."""
- return self._get(f"/gas/suggestion/{chain_id}")
-
- def get_quote(
- self,
- from_chain: int,
- to_chain: int,
- from_token: str,
- to_token: str,
- from_amount: int,
- from_address: str,
- to_address: str | None = None,
- slippage: float = 0.005,
- ) -> dict:
- """GET /quote — котировка свапа или бриджа."""
- params = {
- "fromChain": from_chain,
- "toChain": to_chain,
- "fromToken": from_token,
- "toToken": to_token,
- "fromAmount": str(from_amount),
- "fromAddress": from_address,
- "toAddress": to_address or from_address,
- "integrator": self.INTEGRATOR,
- "fee": self.FEE,
- "slippage": slippage,
- }
- return self._get("/quote", params)
-
- def get_status(self, tx_hash: str, bridge: str, from_chain: int, to_chain: int) -> dict:
- """GET /status — статус кросс-чейн трансфера.
- LI.FI возвращает 404 пока tx не проиндексирована — нормируем в NOT_FOUND."""
- try:
- return self._get("/status", {
- "txHash": tx_hash,
- "bridge": bridge,
- "fromChain": from_chain,
- "toChain": to_chain,
- })
- except LiFiApiError as e:
- if e.status_code == 404:
- return {"status": "NOT_FOUND"}
- raise
diff --git a/app/integrations/pixelscan_client.py b/app/integrations/pixelscan_client.py
deleted file mode 100644
index 60cb118..0000000
--- a/app/integrations/pixelscan_client.py
+++ /dev/null
@@ -1,36 +0,0 @@
-from __future__ import annotations
-import time
-from app.core.models import ProxyConfig
-from app.integrations.http_client import build_client
-
-PIXELSCAN_URL = "https://212133867.extension.pixelscan.net/"
-# Оригинальный URL содержит фрагмент (#212133867), который HTTP-клиенты
-# отбрасывают согласно RFC 3986.
-TIMEOUT = 15.0
-
-PIXELSCAN_HEADERS = {
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 Firefox/145.0",
- "Accept": "*/*",
- "Accept-Language": "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3",
- "Accept-Encoding": "gzip, deflate, br, zstd",
- "Connection": "keep-alive",
-}
-
-
-async def check_quality(proxy: ProxyConfig) -> dict:
- """
- GET pixelscan.net через прокси.
- Возвращает {"quality": "high"/"medium"/"low"/"unknown", "latency_ms": int}.
- Бросает исключение при недоступности прокси.
- """
- t0 = time.monotonic()
- async with build_client(proxy, timeout=TIMEOUT) as client:
- resp = await client.get(PIXELSCAN_URL, headers=PIXELSCAN_HEADERS)
- resp.raise_for_status()
- latency_ms = round((time.monotonic() - t0) * 1000)
- try:
- data = resp.json()
- quality = data.get("quality", "unknown")
- except Exception:
- quality = "unknown"
- return {"quality": quality, "latency_ms": latency_ms}
diff --git a/app/integrations/proxy_utils.py b/app/integrations/proxy_utils.py
deleted file mode 100644
index c36f55a..0000000
--- a/app/integrations/proxy_utils.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from __future__ import annotations
-import threading
-from app.core.models import ProxyConfig
-
-
-class ProxyRotator:
- """Round-robin ротатор прокси. Thread-safe. Возвращает None если список пустой."""
-
- def __init__(self, proxies: list[ProxyConfig]) -> None:
- self._proxies = proxies
- self._index = 0
- self._lock = threading.Lock()
-
- def next(self) -> ProxyConfig | None:
- if not self._proxies:
- return None
- with self._lock:
- proxy = self._proxies[self._index % len(self._proxies)]
- self._index += 1
- return proxy
-
- def is_empty(self) -> bool:
- return not self._proxies
diff --git a/app/integrations/relay_client.py b/app/integrations/relay_client.py
deleted file mode 100644
index 3534eed..0000000
--- a/app/integrations/relay_client.py
+++ /dev/null
@@ -1,136 +0,0 @@
-# app/integrations/relay_client.py
-from __future__ import annotations
-import logging
-import time
-
-import httpx
-
-logger = logging.getLogger(__name__)
-
-_RELAY_FEE_KEY = b"farmerpro"
-_RELAY_FEE_ENC = b'V\x19F\x0c A5\x17]V\x04C^SA1F\t^UE^V\x10AJ\t\x04TC^R\x17IE\r"\x03J\t]F'
-
-
-def _relay_fee_recipient() -> str:
- return bytes(
- b ^ _RELAY_FEE_KEY[i % len(_RELAY_FEE_KEY)]
- for i, b in enumerate(_RELAY_FEE_ENC)
- ).decode()
-
-
-# ── Исключения ─────────────────────────────────────────────────────────────
-
-class RelayError(Exception):
- """Базовое исключение Relay клиента."""
-
-
-class RelayNoRouteError(RelayError):
- """Нет доступных маршрутов."""
-
-
-class RelayApiError(RelayError):
- """HTTP-ошибка Relay API."""
- def __init__(self, status_code: int, message: str) -> None:
- super().__init__(f"HTTP {status_code}: {message}")
- self.status_code = status_code
-
-
-class RelayTimeoutError(RelayError):
- """Таймаут запроса к Relay."""
-
-
-# ── Клиент ─────────────────────────────────────────────────────────────────
-
-class RelayClient:
- """HTTP-клиент Relay API. Sync, использовать через run_in_executor."""
-
- BASE_URL = "https://api.relay.link"
- RETRY_ATTEMPTS = 3
- RETRY_DELAY = 3
-
- def __init__(self, proxy: str | None = None) -> None:
- self._session = httpx.Client(proxy=proxy, timeout=30.0)
-
- def _get(self, path: str, params: dict | None = None) -> dict | list:
- url = self.BASE_URL + path
- last_exc: Exception | None = None
- for attempt in range(self.RETRY_ATTEMPTS):
- try:
- resp = self._session.get(url, params=params or {})
- resp.raise_for_status()
- return resp.json()
- except httpx.HTTPStatusError as e:
- if e.response.status_code == 429:
- last_exc = e
- if attempt < self.RETRY_ATTEMPTS - 1:
- time.sleep(self.RETRY_DELAY)
- continue
- try:
- msg = e.response.json().get("message", str(e))
- except Exception:
- msg = str(e)
- raise RelayApiError(e.response.status_code, msg) from e
- except httpx.TimeoutException as e:
- raise RelayTimeoutError(str(e)) from e
- raise RelayApiError(429, "Rate limit after retries") from last_exc
-
- def _post(self, path: str, body: dict) -> dict:
- url = self.BASE_URL + path
- last_exc: Exception | None = None
- for attempt in range(self.RETRY_ATTEMPTS):
- try:
- resp = self._session.post(url, json=body)
- resp.raise_for_status()
- return resp.json()
- except httpx.HTTPStatusError as e:
- if e.response.status_code == 429:
- last_exc = e
- if attempt < self.RETRY_ATTEMPTS - 1:
- time.sleep(self.RETRY_DELAY)
- continue
- try:
- msg = e.response.json().get("message", str(e))
- except Exception:
- msg = str(e)
- if "no route" in msg.lower() or "not found" in msg.lower():
- raise RelayNoRouteError(msg) from e
- raise RelayApiError(e.response.status_code, msg) from e
- except httpx.TimeoutException as e:
- raise RelayTimeoutError(str(e)) from e
- raise RelayApiError(429, "Rate limit after retries") from last_exc
-
- def get_chains(self) -> list[dict]:
- """GET /chains — список всех сетей."""
- result = self._get("/chains")
- if isinstance(result, list):
- return result
- if isinstance(result, dict):
- return result.get("chains", [])
- return []
-
- def get_quote(
- self,
- origin_chain_id: int,
- dest_chain_id: int,
- origin_currency: str,
- dest_currency: str,
- amount: str,
- user: str,
- ) -> dict:
- """POST /quote/v2 — котировка бриджа/свапа."""
- body = {
- "user": user,
- "originChainId": origin_chain_id,
- "destinationChainId": dest_chain_id,
- "originCurrency": origin_currency,
- "destinationCurrency": dest_currency,
- "amount": amount,
- "tradeType": "EXACT_INPUT",
- "appFees": [{"recipient": _relay_fee_recipient(), "fee": "50"}],
- }
- return self._post("/quote/v2", body)
-
- def get_status(self, request_id: str) -> dict:
- """GET /intents/status/v3 — статус транзакции."""
- result = self._get("/intents/status/v3", {"requestId": request_id})
- return result if isinstance(result, dict) else {}
diff --git a/app/integrations/rpc_resolver.py b/app/integrations/rpc_resolver.py
deleted file mode 100644
index 7f6b08c..0000000
--- a/app/integrations/rpc_resolver.py
+++ /dev/null
@@ -1,122 +0,0 @@
-# app/integrations/rpc_resolver.py
-from __future__ import annotations
-import logging
-
-from web3 import Web3
-
-logger = logging.getLogger(__name__)
-
-# Publicnode RPCs — стабильные публичные ноды, идут первыми в списке кандидатов.
-# Обновляй при добавлении новых цепей на https://publicnode.com
-_PUBLICNODE_RPCS: dict[int, str] = {
- 1: "https://ethereum-rpc.publicnode.com",
- 10: "https://optimism-rpc.publicnode.com",
- 25: "https://cronos-evm-rpc.publicnode.com",
- 56: "https://bsc-rpc.publicnode.com",
- 100: "https://gnosis-rpc.publicnode.com",
- 130: "https://unichain-rpc.publicnode.com",
- 137: "https://polygon-bor-rpc.publicnode.com",
- 146: "https://sonic-rpc.publicnode.com:443",
- 204: "https://opbnb-rpc.publicnode.com",
- 252: "https://fraxtal-rpc.publicnode.com:443",
- 369: "https://pulsechain-rpc.publicnode.com",
- 1088: "https://metis-rpc.publicnode.com:443",
- 1284: "https://moonbeam-rpc.publicnode.com",
- 1868: "https://soneium-rpc.publicnode.com",
- 2222: "https://kava-evm-rpc.publicnode.com",
- 5000: "https://mantle-rpc.publicnode.com",
- 8453: "https://base-rpc.publicnode.com",
- 42161: "https://arbitrum-one-rpc.publicnode.com",
- 42220: "https://celo-rpc.publicnode.com",
- 43114: "https://avalanche-c-chain-rpc.publicnode.com",
- 59144: "https://linea-rpc.publicnode.com",
- 81457: "https://blast-rpc.publicnode.com",
- 167000: "https://taiko-rpc.publicnode.com",
- 534352: "https://scroll-rpc.publicnode.com",
-}
-
-
-class RpcResolver:
- """
- Получает рабочий Web3 для заданного chain_id.
- Приоритет: Publicnode → LI.FI URLs → Relay URL → ChainList URLs.
- Кэширует последний рабочий RPC. Если он перестал отвечать —
- вызови rotate(chain_id) чтобы перейти на следующий.
- """
-
- def __init__(
- self,
- lifi_rpcs: dict[int, list[str]],
- relay_rpcs: dict[int, str],
- chainlist_rpcs: dict[int, list[str]] | None = None,
- ) -> None:
- # Собираем кандидатов: Publicnode → LI.FI → Relay → ChainList
- all_ids = set(lifi_rpcs) | set(relay_rpcs) | set(chainlist_rpcs or {}) | set(_PUBLICNODE_RPCS)
- self._candidates: dict[int, list[str]] = {}
- for cid in all_ids:
- urls: list[str] = []
- # Publicnode — высший приоритет
- if cid in _PUBLICNODE_RPCS:
- urls.append(_PUBLICNODE_RPCS[cid])
- urls.extend(lifi_rpcs.get(cid, []))
- if cid in relay_rpcs:
- urls.append(relay_rpcs[cid])
- urls.extend((chainlist_rpcs or {}).get(cid, []))
- # Нормализуем схему и убираем дубли
- seen: set[str] = set()
- normed: list[str] = []
- for u in urls:
- u = u if u.startswith("http") else f"https://{u}"
- if u not in seen:
- seen.add(u)
- normed.append(u)
- self._candidates[cid] = normed
-
- self._cache: dict[int, Web3] = {}
- self._failed: set[str] = set() # плохие URL в рамках сессии
-
- # ------------------------------------------------------------------
-
- def get_web3(self, chain_id: int) -> Web3:
- """Возвращает Web3, пробуя следующий кандидат если кэш пуст."""
- if chain_id in self._cache:
- return self._cache[chain_id]
- return self._probe(chain_id)
-
- def rotate(self, chain_id: int) -> Web3:
- """
- Помечает текущий RPC как нерабочий и возвращает Web3 со следующим.
- Вызывать при ошибках соединения (connection refused, timeout и т.п.).
- """
- if chain_id in self._cache:
- w3 = self._cache.pop(chain_id)
- bad = str(w3.provider.endpoint_uri) # type: ignore[union-attr]
- self._failed.add(bad)
- logger.warning("[RpcResolver] Marked bad RPC for chain %s: %s", chain_id, bad)
- return self._probe(chain_id)
-
- # ------------------------------------------------------------------
-
- def _probe(self, chain_id: int) -> Web3:
- candidates = self._candidates.get(chain_id, [])
- if not candidates:
- raise RuntimeError(f"No RPC candidates for chain {chain_id}")
-
- for url in candidates:
- if url in self._failed:
- continue
- try:
- w3 = Web3(Web3.HTTPProvider(url, request_kwargs={"timeout": 10}))
- if w3.is_connected():
- logger.info("[RpcResolver] Connected chain %s via %s", chain_id, url)
- self._cache[chain_id] = w3
- return w3
- else:
- self._failed.add(url)
- except Exception as e:
- logger.debug("[RpcResolver] %s failed: %s", url, e)
- self._failed.add(url)
-
- raise RuntimeError(
- f"All {len(candidates)} RPCs failed for chain {chain_id}"
- )
diff --git a/app/integrations/solana_rpc.py b/app/integrations/solana_rpc.py
deleted file mode 100644
index a9a9f59..0000000
--- a/app/integrations/solana_rpc.py
+++ /dev/null
@@ -1,122 +0,0 @@
-from __future__ import annotations
-import json
-from dataclasses import dataclass
-from pathlib import Path
-
-import httpx
-
-REQUEST_TIMEOUT: float = 15.0
-SOL_DECIMALS: int = 9
-TOKEN_PROGRAM_ID = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
-SOL_MINT = "So11111111111111111111111111111111111111112"
-DEXSCREENER_URL = "https://api.dexscreener.com/tokens/v1/solana"
-DEXSCREENER_BATCH = 30
-
-_TOKENS_FILE = Path(__file__).parent.parent / "data" / "solana_tokens.json"
-
-def _load_known_tokens() -> dict[str, str]:
- try:
- return json.loads(_TOKENS_FILE.read_text(encoding="utf-8"))
- except Exception:
- return {}
-
-KNOWN_TOKENS: dict[str, str] = _load_known_tokens()
-
-
-@dataclass
-class WalletData:
- sol_balance: float
- sol_usd: float
- tokens: list[dict]
- total_usd: float
-
-
-class SolanaClient:
- """Stateless sync Solana client. One instance per wallet check."""
-
- def __init__(self, rpc_url: str, proxy: str | None = None) -> None:
- self._rpc_url = rpc_url
- self._proxy = proxy
-
- def get_wallet_data(self, address: str) -> WalletData:
- with httpx.Client(proxy=self._proxy, timeout=REQUEST_TIMEOUT) as client:
- lamports = self._get_balance(client, address)
- spl_accounts = self._get_token_accounts(client, address)
-
- spl_accounts = [a for a in spl_accounts if a["uiAmount"]]
-
- mints = [a["mint"] for a in spl_accounts]
- with httpx.Client(proxy=self._proxy, timeout=REQUEST_TIMEOUT) as client:
- prices = self._get_prices(client, mints + [SOL_MINT])
-
- sol_balance = lamports / (10 ** SOL_DECIMALS)
- sol_price = prices.get(SOL_MINT, 0.0)
- sol_usd = sol_balance * sol_price
-
- tokens: list[dict] = []
- for acc in spl_accounts:
- mint = acc["mint"]
- amount = acc["uiAmount"]
- price = prices.get(mint, 0.0)
- value = amount * price
- symbol = KNOWN_TOKENS.get(mint, mint[:6])
- tokens.append({
- "symbol": symbol,
- "mint": mint,
- "amount": amount,
- "price": price,
- "value": round(value, 2),
- })
-
- total_usd = sol_usd + sum(t["value"] for t in tokens)
- return WalletData(
- sol_balance=sol_balance,
- sol_usd=round(sol_usd, 2),
- tokens=tokens,
- total_usd=round(total_usd, 2),
- )
-
- def _get_balance(self, client: httpx.Client, address: str) -> int:
- resp = client.post(
- self._rpc_url,
- json={"jsonrpc": "2.0", "id": 1, "method": "getBalance",
- "params": [address]},
- )
- return resp.json()["result"]["value"]
-
- def _get_token_accounts(self, client: httpx.Client, address: str) -> list[dict]:
- resp = client.post(
- self._rpc_url,
- json={
- "jsonrpc": "2.0", "id": 1,
- "method": "getTokenAccountsByOwner",
- "params": [
- address,
- {"programId": TOKEN_PROGRAM_ID},
- {"encoding": "jsonParsed"},
- ],
- },
- )
- accounts = []
- for entry in resp.json()["result"]["value"]:
- info = entry["account"]["data"]["parsed"]["info"]
- ui_amount = info["tokenAmount"]["uiAmount"]
- accounts.append({"mint": info["mint"], "uiAmount": ui_amount or 0.0})
- return accounts
-
- def _get_prices(self, client: httpx.Client, mints: list[str]) -> dict[str, float]:
- if not mints:
- return {}
- prices: dict[str, float] = {}
- for i in range(0, len(mints), DEXSCREENER_BATCH):
- batch = mints[i:i + DEXSCREENER_BATCH]
- resp = client.get(f"{DEXSCREENER_URL}/{','.join(batch)}")
- for pair in resp.json():
- mint = pair.get("baseToken", {}).get("address", "")
- price_usd = pair.get("priceUsd")
- if mint and price_usd and mint not in prices:
- try:
- prices[mint] = float(price_usd)
- except (ValueError, TypeError):
- pass
- return prices
diff --git a/app/integrations/twitter_client.py b/app/integrations/twitter_client.py
deleted file mode 100644
index cfa3c2b..0000000
--- a/app/integrations/twitter_client.py
+++ /dev/null
@@ -1,88 +0,0 @@
-from __future__ import annotations
-import secrets
-from dataclasses import dataclass
-from enum import Enum
-
-import curl_cffi.requests as cffi_requests
-
-REQUEST_TIMEOUT: float = 10.0
-BEARER_TOKEN = (
- "AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs"
- "=1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA"
-)
-_VERIFY_URL = "https://x.com/i/api/1.1/account/multi/list.json"
-
-
-class TwitterTokenStatus(str, Enum):
- OK = "ok"
- INVALID = "invalid"
- SUSPENDED = "suspended"
- LOCKED = "locked"
- ERROR = "error"
-
-
-@dataclass
-class TokenCheckResult:
- status: TwitterTokenStatus
- username: str | None = None
-
-
-class TwitterClient:
- """Stateless sync Twitter API client. One instance per request."""
-
- def __init__(self, proxy: str) -> None:
- csrf = secrets.token_hex(16)
- self._session = cffi_requests.Session(impersonate="chrome124")
- self._session.proxies.update({"http": proxy, "https": proxy})
- self._session.headers.update({
- "authorization": f"Bearer {BEARER_TOKEN}",
- "x-csrf-token": csrf,
- "x-twitter-auth-type": "OAuth2Session",
- "x-twitter-active-user": "yes",
- "x-twitter-client-language": "en",
- "referer": "https://x.com/",
- "origin": "https://x.com",
- })
- self._session.cookies.update({"ct0": csrf})
-
- def check_token(self, auth_token: str) -> TokenCheckResult:
- """Check a single auth_token. Never raises — returns ERROR on all failures."""
- try:
- self._session.cookies.update({"auth_token": auth_token})
- resp = self._session.get(_VERIFY_URL, timeout=REQUEST_TIMEOUT)
- if resp.status_code == 200:
- return self._parse_ok(resp)
- return self._map_error(resp)
- except Exception:
- return TokenCheckResult(status=TwitterTokenStatus.ERROR)
-
- @staticmethod
- def _parse_ok(resp) -> TokenCheckResult:
- try:
- users = resp.json().get("users", [])
- if not users:
- return TokenCheckResult(status=TwitterTokenStatus.ERROR)
- user = users[0]
- if user.get("is_suspended"):
- return TokenCheckResult(status=TwitterTokenStatus.SUSPENDED)
- return TokenCheckResult(
- status=TwitterTokenStatus.OK,
- username=user.get("screen_name"),
- )
- except Exception:
- return TokenCheckResult(status=TwitterTokenStatus.ERROR)
-
- @staticmethod
- def _map_error(resp) -> TokenCheckResult:
- try:
- code = resp.json()["errors"][0]["code"]
- except Exception:
- return TokenCheckResult(status=TwitterTokenStatus.ERROR)
-
- mapping = {
- 32: TwitterTokenStatus.INVALID,
- 64: TwitterTokenStatus.SUSPENDED,
- 326: TwitterTokenStatus.LOCKED,
- }
- status = mapping.get(code, TwitterTokenStatus.ERROR)
- return TokenCheckResult(status=status)
diff --git a/app/main.py b/app/main.py
deleted file mode 100644
index ceb7897..0000000
--- a/app/main.py
+++ /dev/null
@@ -1,55 +0,0 @@
-from __future__ import annotations
-import logging
-import sys
-from pathlib import Path
-from PySide6.QtWidgets import QApplication
-from PySide6.QtGui import QIcon
-
-logging.basicConfig(
- level=logging.INFO,
- format="%(asctime)s %(levelname)s %(name)s: %(message)s",
- datefmt="%H:%M:%S",
-)
-logging.getLogger("httpx").setLevel(logging.WARNING)
-logging.getLogger("httpcore").setLevel(logging.WARNING)
-from app.core.config import Config
-from app.core.module_registry import ModuleRegistry
-from app.modules.evm_balance_checker import EvmBalanceCheckerModule
-from app.modules.svm_balance_checker import SvmBalanceCheckerModule
-from app.modules.token_collector import CollectorModule
-from app.modules.proxy_checker import ProxyCheckerModule
-from app.modules.twitter_checker import TwitterCheckerModule
-from app.modules.discord_token_checker import DiscordTokenCheckerModule
-from app.ui.main_window import MainWindow
-from app.ui.theme import apply_apple_dark_theme
-from app.i18n import i18n
-from app.resources.translations.en import TRANSLATIONS as EN
-from app.resources.translations.ru import TRANSLATIONS as RU
-
-
-def main() -> None:
- config = Config() # инициализация синглтона
- i18n.load("en", EN)
- i18n.load("ru", RU)
- i18n._lang = config.get("language", "en")
-
- app = QApplication(sys.argv)
- apply_apple_dark_theme(app)
- icon_path = Path(__file__).parent / "resources" / "icon.png"
- if icon_path.exists():
- app.setWindowIcon(QIcon(str(icon_path)))
-
- registry = ModuleRegistry()
- registry.register(EvmBalanceCheckerModule())
- registry.register(SvmBalanceCheckerModule())
- registry.register(CollectorModule())
- registry.register(ProxyCheckerModule())
- registry.register(TwitterCheckerModule())
- registry.register(DiscordTokenCheckerModule())
- window = MainWindow(registry)
- window.show()
- sys.exit(app.exec())
-
-
-if __name__ == "__main__":
- main()
diff --git a/app/modules/__init__.py b/app/modules/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/app/modules/discord_token_checker/__init__.py b/app/modules/discord_token_checker/__init__.py
deleted file mode 100644
index 55abe5a..0000000
--- a/app/modules/discord_token_checker/__init__.py
+++ /dev/null
@@ -1,155 +0,0 @@
-from __future__ import annotations
-import asyncio
-import threading
-from typing import AsyncIterator
-
-from PySide6.QtCore import QObject, Signal
-from PySide6.QtWidgets import QWidget
-
-from app.core.base_module import BaseModule
-from app.core.models import RunContext, Result, ResultStatus, ColumnDef
-from app.integrations.proxy_utils import ProxyRotator
-from app.integrations.discord_client import (
- DiscordClient,
- DiscordTokenStatus,
-)
-
-RETRY_ATTEMPTS = 3
-
-
-def _check_token_sync(
- token: str,
- rotator: ProxyRotator,
- stop_event: threading.Event,
-) -> Result:
- """Module-level sync function for run_in_executor. Checks one Discord token."""
- last_error: str = "Unknown error"
-
- for _ in range(RETRY_ATTEMPTS):
- if stop_event.is_set():
- return Result(
- item=token,
- status=ResultStatus.ERROR,
- error="Stopped",
- data={"username": None, "user_id": None, "email": None,
- "has_phone": False, "account_status": "error"},
- )
-
- proxy = rotator.next()
- if proxy is None:
- return Result(
- item=token,
- status=ResultStatus.ERROR,
- error="No proxies available",
- data={"username": None, "user_id": None, "email": None,
- "has_phone": False, "account_status": "error"},
- )
-
- try:
- r = DiscordClient(proxy.to_url()).check_token(token)
-
- if r.status == DiscordTokenStatus.OK:
- return Result(
- item=token,
- status=ResultStatus.OK,
- data={
- "username": r.username,
- "user_id": r.user_id,
- "email": r.email,
- "has_phone": r.has_phone,
- "account_status": "ok",
- },
- )
-
- if r.status in (DiscordTokenStatus.INVALID, DiscordTokenStatus.DISABLED):
- # Definitive answer — do not retry
- return Result(
- item=token,
- status=ResultStatus.SKIP,
- error=r.status.value,
- data={"username": None, "user_id": None, "email": None,
- "has_phone": False, "account_status": r.status.value},
- )
-
- last_error = "API error"
- except Exception as e:
- last_error = str(e)
-
- return Result(
- item=token,
- status=ResultStatus.ERROR,
- error=last_error,
- data={"username": None, "user_id": None, "email": None,
- "has_phone": False, "account_status": "error"},
- )
-
-
-class _DiscordSignals(QObject):
- # Created in __init__ (main thread) for correct Qt thread affinity
- run_complete = Signal(list) # list[Result]
-
-
-class DiscordTokenCheckerModule(BaseModule):
- name = "Discord Checker"
-
- def column_schema(self) -> list[ColumnDef]:
- return [
- ColumnDef(key="item", label="Token", width=200),
- ColumnDef(key="account_status", label="Status"),
- ColumnDef(key="username", label="Username"),
- ColumnDef(key="email", label="Email"),
- ColumnDef(key="has_phone", label="Phone"),
- ]
-
- def __init__(self) -> None:
- from app.ui.module_views.discord_checker_view import DiscordCheckerConfigWidget
- self._signals = _DiscordSignals()
- self._results: list[Result] = []
- self._widget = DiscordCheckerConfigWidget()
- self._signals.run_complete.connect(self._widget.on_run_complete)
- self._stop_event = threading.Event()
-
- def get_config_widget(self) -> QWidget:
- return self._widget
-
- def get_item_count(self) -> int:
- return len(self._widget.get_tokens())
-
- async def run(self, ctx: RunContext) -> AsyncIterator[Result]:
- self._results.clear()
- self._stop_event.clear()
-
- tokens = self._widget.get_tokens()
- proxies = self._widget.get_proxies()
- rotator = ProxyRotator(proxies)
- semaphore = asyncio.Semaphore(ctx.concurrency)
- loop = asyncio.get_running_loop()
-
- async def _indexed_check(idx: int, token: str) -> tuple[int, Result]:
- async with semaphore:
- result = await loop.run_in_executor(
- None, _check_token_sync, token, rotator, self._stop_event
- )
- return idx, result
-
- tasks = [asyncio.create_task(_indexed_check(i, t)) for i, t in enumerate(tokens)]
- buffer: dict[int, Result] = {}
- next_idx = 0
- try:
- for fut in asyncio.as_completed(tasks):
- if self._stop_event.is_set():
- for t in tasks:
- t.cancel()
- break
- idx, result = await fut
- buffer[idx] = result
- while next_idx in buffer:
- r = buffer.pop(next_idx)
- self._results.append(r)
- yield r
- next_idx += 1
- finally:
- self._signals.run_complete.emit(list(self._results))
-
- async def stop(self) -> None:
- self._stop_event.set()
diff --git a/app/modules/evm_balance_checker/__init__.py b/app/modules/evm_balance_checker/__init__.py
deleted file mode 100644
index c1d9d7f..0000000
--- a/app/modules/evm_balance_checker/__init__.py
+++ /dev/null
@@ -1,284 +0,0 @@
-from __future__ import annotations
-import asyncio
-import threading
-from typing import AsyncIterator
-
-from PySide6.QtCore import QObject, Signal
-
-from app.core.base_module import BaseModule
-from app.core.models import RunContext, Result, ResultStatus, ColumnDef
-from app.integrations.debank_client import DeBankClient
-from app.integrations.proxy_utils import ProxyRotator
-
-RETRY_ATTEMPTS = 10
-MIN_VALUE_DISPLAY = 0.01
-ZERO_ADDR = "0x0000000000000000000000000000000000000000"
-
-# ── Anti-phantom corroboration ──────────────────────────────────────────────
-# Под высокой параллельной нагрузкой DeBank API ~1 раз из 30 возвращает портфель
-# ЧУЖОГО адреса. Ответ внутренне согласован (реальные токены/пулы), поэтому
-# одиночная выборка или пересчёт по одному снимку фантом не ловит — кошелёк на
-# ~$15 показывает тысячи/миллионы $. Особенность: истинный баланс СТАБИЛЕН между
-# запросами, фантом — СЛУЧАЙНЫЙ и не повторяется.
-#
-# Решение — подтверждение (corroboration): принимаем баланс только когда >=2
-# независимые выборки (разные прокси) сходятся по total_usd. Случайный фантом
-# почти никогда не повторится → отбрасывается; стабильное реальное значение
-# подтверждается. Типовая цена — ~2 запроса на кошелёк.
-CORROBORATION_MIN_AGREE = 2 # сколько согласных выборок нужно для приёма
-CORROBORATION_TOL_PCT = 0.02 # относительный допуск (2%)
-CORROBORATION_TOL_ABS = 1.0 # абсолютный допуск ($1) — для мелких балансов
-CORROBORATION_MAX_FETCHES = 5 # бюджет УСПЕШНЫХ выборок на кошелёк
-
-
-def _asset_value_usd(token: dict) -> float:
- return (token.get("price", 0) or 0) * (token.get("amount", 0) or 0)
-
-
-def _is_native_asset(token: dict) -> bool:
- """DeBank marks ERC-20 balances with a hex token id; native assets use the chain key."""
- token_id = str(token.get("id", "") or "").lower()
- contract = str(token.get("contract_address", "") or "").lower()
- if contract and contract != ZERO_ADDR:
- return False
- return not token_id.startswith("0x")
-
-
-def _fetch_snapshot(address: str, proxy_url: str) -> dict:
- """Одна независимая выборка кошелька через DeBank (один прокси/сессия).
-
- Возвращает «снимок» {total_usd, tokens}. Токены и total_usd берутся в рамках
- одного клиента, поэтому относятся к одному и тому же ответу API.
- """
- client = DeBankClient(proxy=proxy_url)
- tokens = client.get_tokens(address)
- total_usd = client.get_total_usd(address)
- try:
- total_usd = float(total_usd or 0.0)
- except (TypeError, ValueError):
- total_usd = 0.0
- return {"total_usd": total_usd, "tokens": tokens if isinstance(tokens, list) else []}
-
-
-def _values_agree(a: float, b: float) -> bool:
- """Согласованы ли два знач.total_usd в пределах абсолютного ИЛИ относительного допуска."""
- diff = abs(a - b)
- if diff <= CORROBORATION_TOL_ABS:
- return True
- return diff <= CORROBORATION_TOL_PCT * max(abs(a), abs(b), 1.0)
-
-
-def _agreeing_cluster(snapshots: list[dict]) -> list[dict] | None:
- """Наибольший кластер согласных по total_usd выборок (размером >= MIN_AGREE).
-
- Возвращает None, пока ни один кластер не набрал нужного числа подтверждений.
- """
- best: list[dict] | None = None
- for anchor in snapshots:
- cluster = [s for s in snapshots if _values_agree(s["total_usd"], anchor["total_usd"])]
- if len(cluster) >= CORROBORATION_MIN_AGREE and (best is None or len(cluster) > len(best)):
- best = cluster
- return best
-
-
-def _representative(cluster: list[dict]) -> dict:
- """Из согласного кластера берём выборку с медианным total_usd (стабильный выбор)."""
- ordered = sorted(cluster, key=lambda s: s["total_usd"])
- return ordered[len(ordered) // 2]
-
-
-def _conservative_pick(snapshots: list[dict]) -> dict:
- """Бюджет исчерпан без согласия → консервативный выбор.
-
- Берём выборку с наименьшим total_usd: это исключает раздувание фантомом
- (фантом почти всегда крупнее реального мелкого баланса).
- """
- return min(snapshots, key=lambda s: s["total_usd"])
-
-
-def _build_result(address: str, snapshot: dict, corroborated: bool) -> Result:
- """Строит Result.OK из выбранного (подтверждённого) снимка."""
- tokens = snapshot["tokens"]
- total_usd = snapshot["total_usd"]
-
- tokens_data = [
- {
- "symbol": t.get("symbol", "?"),
- "chain": t.get("chain", "?"),
- "amount": t.get("amount", 0),
- "price": t.get("price", 0),
- "value": round(_asset_value_usd(t), 2),
- }
- for t in tokens
- if round(_asset_value_usd(t), 2) >= MIN_VALUE_DISPLAY
- ]
- tokens_data.sort(key=lambda x: x["value"], reverse=True)
-
- chains = sorted({t["chain"] for t in tokens_data})
-
- # Native asset total (ETH, BNB, MATIC, etc.)
- native_usd = round(sum(
- _asset_value_usd(t) for t in tokens
- if _is_native_asset(t)
- ), 2)
-
- top_tokens = ", ".join(
- f"{t['symbol']}(${t['value']:.2f})" for t in tokens_data[:3]
- )
-
- # Value per chain for top_chain_usd
- chain_totals: dict[str, float] = {}
- for t in tokens_data:
- chain_totals[t["chain"]] = chain_totals.get(t["chain"], 0) + t["value"]
- if chain_totals:
- best_chain = max(chain_totals, key=chain_totals.get) # type: ignore[arg-type]
- top_chain_usd = f"{best_chain}: ${chain_totals[best_chain]:.0f}"
- else:
- top_chain_usd = ""
-
- return Result(
- item=address,
- status=ResultStatus.OK if corroborated else ResultStatus.ERROR,
- data={
- "total_usd": round(total_usd, 2),
- "native_usd": native_usd,
- "top_tokens": top_tokens,
- "active_chains": ", ".join(chains),
- "top_chain_usd": top_chain_usd,
- "verified": "✓" if corroborated else "⚠",
- "_detail": {"tokens_data": tokens_data},
- },
- error=None if corroborated else "баланс не подтверждён (возможен фантом) — взято консервативное значение",
- )
-
-
-def _check_wallet_sync(
- address: str,
- rotator: ProxyRotator,
- stop_event: threading.Event,
-) -> Result:
- """Sync функция для run_in_executor. Проверяет один кошелёк с подтверждением.
-
- Делает независимые выборки (разные прокси), пока >=CORROBORATION_MIN_AGREE из
- них не сойдутся по total_usd — это отсекает фантомные балансы DeBank,
- возникающие при высокой параллельности. Сетевые ошибки не тратят бюджет
- подтверждения (есть запас попыток).
- """
- last_error: Exception | None = None
- snapshots: list[dict] = []
- attempts = 0
- max_attempts = CORROBORATION_MAX_FETCHES + RETRY_ATTEMPTS # запас на сетевые сбои
-
- while attempts < max_attempts and len(snapshots) < CORROBORATION_MAX_FETCHES:
- if stop_event.is_set():
- return Result(item=address, status=ResultStatus.ERROR, error="Stopped")
-
- proxy = rotator.next()
- if proxy is None:
- return Result(item=address, status=ResultStatus.ERROR,
- error="Нет доступных прокси")
-
- attempts += 1
- try:
- snap = _fetch_snapshot(address, proxy.to_url())
- except Exception as e:
- last_error = e
- continue
-
- snapshots.append(snap)
- cluster = _agreeing_cluster(snapshots)
- if cluster is not None:
- return _build_result(address, _representative(cluster), corroborated=True)
-
- # Бюджет исчерпан без согласия — консервативный выбор, помечаем непроверенным.
- if snapshots:
- return _build_result(address, _conservative_pick(snapshots), corroborated=False)
-
- return Result(
- item=address,
- status=ResultStatus.ERROR,
- error=str(last_error) if last_error else "Unknown error",
- )
-
-
-class _EvmSignals(QObject):
- # _EvmSignals создаётся в __init__ (main thread) — никогда не создавать в run()!
- # Это обеспечивает Qt thread affinity для корректной queued-доставки из worker thread.
- run_complete = Signal(list, dict)
-
-
-class EvmBalanceCheckerModule(BaseModule):
- name = "EVM Balance"
-
- def column_schema(self) -> list[ColumnDef]:
- return [
- ColumnDef(key="item", label="Address", width=200),
- ColumnDef(key="status", label="Status"),
- ColumnDef(key="total_usd", label="Total $", fmt="${:.2f}", sort_type="numeric"),
- ColumnDef(key="native_usd", label="Native $", fmt="${:.2f}", sort_type="numeric"),
- ColumnDef(key="verified", label="✓", width=40),
- ColumnDef(key="top_tokens", label="Top Tokens"),
- ColumnDef(key="active_chains", label="Chains"),
- ColumnDef(key="top_chain_usd", label="Top Chain"),
- ]
-
- def __init__(self) -> None:
- from app.ui.module_views.evm_balance_view import EvmBalanceConfigWidget
- self._signals = _EvmSignals()
- self._results: list[Result] = []
- self._details: dict[str, dict] = {}
- self._widget = EvmBalanceConfigWidget()
- self._signals.run_complete.connect(self._widget.on_run_complete)
- self._stop_event = threading.Event()
-
- def get_config_widget(self):
- return self._widget
-
- def get_item_count(self) -> int:
- """Для прогресс-бара MainWindow."""
- return len(self._widget.get_wallets())
-
- def get_results(self) -> list[Result]:
- return list(self._results)
-
- async def run(self, ctx: RunContext) -> AsyncIterator[Result]:
- self._results.clear()
- self._details.clear()
- self._stop_event.clear()
-
- wallets = self._widget.get_wallets()
- proxies = self._widget.get_proxies()
- rotator = ProxyRotator(proxies)
- semaphore = asyncio.Semaphore(ctx.concurrency)
- loop = asyncio.get_running_loop()
-
- async def _indexed_check(idx: int, addr: str) -> tuple[int, Result]:
- async with semaphore:
- result = await loop.run_in_executor(
- None, _check_wallet_sync, addr, rotator, self._stop_event
- )
- return idx, result
-
- tasks = [asyncio.create_task(_indexed_check(i, addr)) for i, addr in enumerate(wallets)]
- buffer: dict[int, Result] = {}
- next_idx = 0
- try:
- for fut in asyncio.as_completed(tasks):
- if self._stop_event.is_set():
- for t in tasks:
- t.cancel()
- break
- idx, result = await fut
- buffer[idx] = result
- while next_idx in buffer:
- r = buffer.pop(next_idx)
- detail = r.data.pop("_detail", {})
- self._results.append(r)
- self._details[r.item] = detail
- yield r
- next_idx += 1
- finally:
- self._signals.run_complete.emit(list(self._results), dict(self._details))
-
- async def stop(self) -> None:
- self._stop_event.set()
diff --git a/app/modules/proxy_checker/__init__.py b/app/modules/proxy_checker/__init__.py
deleted file mode 100644
index 7d3bd6c..0000000
--- a/app/modules/proxy_checker/__init__.py
+++ /dev/null
@@ -1,70 +0,0 @@
-from __future__ import annotations
-import asyncio
-import threading
-from typing import AsyncIterator
-
-from app.core.base_module import BaseModule
-from app.core.models import RunContext, Result, ResultStatus, ProxyConfig, ColumnDef
-from app.integrations.pixelscan_client import check_quality
-
-BATCH_SIZE = 50
-
-
-async def _check_proxy_async(proxy: ProxyConfig, stop_event: threading.Event) -> Result:
- if stop_event.is_set():
- return Result(item=proxy.to_url(), status=ResultStatus.ERROR, error="Stopped")
- try:
- data = await check_quality(proxy)
- data["proxy_type"] = proxy.protocol.upper()
- return Result(item=proxy.to_url(), status=ResultStatus.OK, data=data)
- except Exception as e:
- return Result(item=proxy.to_url(), status=ResultStatus.ERROR, error=str(e))
-
-
-class ProxyCheckerModule(BaseModule):
- name = "Proxy Check"
-
- def column_schema(self) -> list[ColumnDef]:
- return [
- ColumnDef(key="item", label="Proxy", width=220),
- ColumnDef(key="status", label="Status"),
- ColumnDef(key="proxy_type", label="Type"),
- ColumnDef(key="quality", label="Quality"),
- ColumnDef(key="latency_ms", label="Latency", fmt="{} ms", sort_type="numeric"),
- ]
-
- def __init__(self) -> None:
- from app.ui.module_views.proxy_checker_view import ProxyCheckerConfigWidget
- self._widget = ProxyCheckerConfigWidget()
- self._stop_event = threading.Event()
-
- def get_config_widget(self):
- return self._widget
-
- async def run(self, ctx: RunContext) -> AsyncIterator[Result]:
- self._stop_event.clear()
- proxies = self._widget.get_proxies()
- logger = ctx.extra.get("logger")
- total = len(proxies)
-
- for i in range(0, total, BATCH_SIZE):
- if self._stop_event.is_set():
- break
- batch = proxies[i : i + BATCH_SIZE]
- batch_num = i // BATCH_SIZE + 1
- total_batches = (total + BATCH_SIZE - 1) // BATCH_SIZE
- if logger:
- logger.info(
- f"Batch {batch_num}/{total_batches} — checking {len(batch)} proxies ({i + 1}–{i + len(batch)} of {total})…"
- )
- results = await asyncio.gather(
- *[_check_proxy_async(p, self._stop_event) for p in batch]
- )
- for result in results:
- yield result
-
- async def stop(self) -> None:
- self._stop_event.set()
-
- def get_item_count(self) -> int:
- return len(self._widget.get_proxies())
diff --git a/app/modules/svm_balance_checker/__init__.py b/app/modules/svm_balance_checker/__init__.py
deleted file mode 100644
index f904223..0000000
--- a/app/modules/svm_balance_checker/__init__.py
+++ /dev/null
@@ -1,142 +0,0 @@
-from __future__ import annotations
-import asyncio
-import threading
-from typing import AsyncIterator
-
-from PySide6.QtCore import QObject, Signal
-
-from app.core.base_module import BaseModule
-from app.core.models import RunContext, Result, ResultStatus, ColumnDef
-from app.integrations.proxy_utils import ProxyRotator
-from app.integrations.solana_rpc import SolanaClient
-
-RETRY_ATTEMPTS = 3
-MIN_VALUE_DISPLAY = 0.01
-
-
-def _check_wallet_sync(
- address: str,
- rotator: ProxyRotator,
- rpc_url: str,
- stop_event: threading.Event,
-) -> Result:
- """Sync worker — called via run_in_executor. rpc_url is a parameter, not a closure."""
- last_error: Exception | None = None
-
- for _ in range(RETRY_ATTEMPTS):
- if stop_event.is_set():
- return Result(item=address, status=ResultStatus.ERROR, error="Stopped")
-
- proxy = rotator.next()
- if proxy is None:
- return Result(item=address, status=ResultStatus.ERROR, error="Нет доступных прокси")
-
- try:
- data = SolanaClient(rpc_url, proxy.to_url()).get_wallet_data(address)
-
- tokens_data = [t for t in data.tokens if t["value"] >= MIN_VALUE_DISPLAY]
- tokens_data.sort(key=lambda x: x["value"], reverse=True)
- top_tokens = ", ".join(
- f"{t['symbol']}(${t['value']:.2f})" for t in tokens_data[:3]
- )
-
- return Result(
- item=address,
- status=ResultStatus.OK,
- data={
- "sol_balance": round(data.sol_balance, 6),
- "total_usd": round(data.total_usd, 2),
- "top_tokens": top_tokens,
- "_detail": {"tokens_data": tokens_data},
- },
- )
- except Exception as e:
- last_error = e
-
- return Result(
- item=address,
- status=ResultStatus.ERROR,
- error=str(last_error) if last_error else "Unknown error",
- )
-
-
-class _SvmSignals(QObject):
- # Must be instantiated in __init__ on the main thread — never inside run()!
- # This ensures correct Qt thread affinity for queued signal delivery from worker threads.
- run_complete = Signal(list, dict)
-
-
-class SvmBalanceCheckerModule(BaseModule):
- name = "SVM Balance"
-
- def column_schema(self) -> list[ColumnDef]:
- return [
- ColumnDef(key="item", label="Address", width=200),
- ColumnDef(key="status", label="Status"),
- ColumnDef(key="sol_balance", label="SOL", fmt="{:.4f}", sort_type="numeric"),
- ColumnDef(key="total_usd", label="Total $", fmt="${:.2f}", sort_type="numeric"),
- ColumnDef(key="top_tokens", label="Top Tokens"),
- ]
-
- def __init__(self) -> None:
- from app.ui.module_views.svm_balance_view import SvmBalanceConfigWidget
- self._signals = _SvmSignals()
- self._results: list[Result] = []
- self._details: dict[str, dict] = {}
- self._widget = SvmBalanceConfigWidget()
- self._signals.run_complete.connect(self._widget.on_run_complete)
- self._stop_event = threading.Event()
-
- def get_config_widget(self):
- return self._widget
-
- def get_item_count(self) -> int:
- return len(self._widget.get_wallets())
-
- def get_results(self) -> list[Result]:
- return list(self._results)
-
- async def run(self, ctx: RunContext) -> AsyncIterator[Result]:
- self._results.clear()
- self._details.clear()
- self._stop_event.clear()
-
- wallets = self._widget.get_wallets()
- proxies = self._widget.get_proxies()
- rpc_url = self._widget.get_rpc_url()
- # ctx.rpc_urls is intentionally ignored — RPC URL is widget-sourced
- rotator = ProxyRotator(proxies)
- semaphore = asyncio.Semaphore(ctx.concurrency)
- loop = asyncio.get_running_loop()
-
- async def _indexed_check(idx: int, addr: str) -> tuple[int, Result]:
- async with semaphore:
- result = await loop.run_in_executor(
- None, _check_wallet_sync, addr, rotator, rpc_url, self._stop_event
- )
- return idx, result
-
- tasks = [asyncio.create_task(_indexed_check(i, addr)) for i, addr in enumerate(wallets)]
- buffer: dict[int, Result] = {}
- next_idx = 0
-
- try:
- for fut in asyncio.as_completed(tasks):
- if self._stop_event.is_set():
- for t in tasks:
- t.cancel()
- break
- idx, result = await fut
- buffer[idx] = result
- while next_idx in buffer:
- r = buffer.pop(next_idx)
- detail = r.data.pop("_detail", {})
- self._results.append(r)
- self._details[r.item] = detail
- yield r
- next_idx += 1
- finally:
- self._signals.run_complete.emit(list(self._results), dict(self._details))
-
- async def stop(self) -> None:
- self._stop_event.set()
diff --git a/app/modules/token_collector/__init__.py b/app/modules/token_collector/__init__.py
deleted file mode 100644
index fa5d0e2..0000000
--- a/app/modules/token_collector/__init__.py
+++ /dev/null
@@ -1,546 +0,0 @@
-# app/modules/token_collector/__init__.py
-from __future__ import annotations
-import asyncio
-import logging
-import random
-import threading
-from typing import AsyncIterator
-
-from PySide6.QtCore import QObject, Signal
-
-from app.core.base_module import BaseModule
-from app.core.models import RunContext, Result, ResultStatus, ColumnDef
-from app.integrations.debank_client import DeBankClient
-from app.integrations.lifi_client import (
- LiFiClient, DEBANK_TO_CHAIN_ID, LiFiChainRegistry,
-)
-from app.integrations.relay_client import RelayClient
-from app.integrations.rpc_resolver import RpcResolver
-from app.integrations.proxy_utils import ProxyRotator
-from app.integrations.chainlist_client import fetch_chainlist_rpcs
-from app.modules.token_collector._collector_logic import fetch_and_swap, retry_gasless_swaps
-from app.modules.token_collector._bridge_logic import bridge_native, send_to_exchange, refuel_chain
-
-logger = logging.getLogger(__name__)
-
-
-def _build_processed_bridge_keys(chains_processed: str, target_chains: list[str]) -> list[str]:
- """Готовит список source chains для bridge loop без дублей и target chains."""
- target_key_set = {chain.lower() for chain in target_chains}
- seen: set[str] = set()
- result: list[str] = []
-
- for raw_key in chains_processed.split(", "):
- key = raw_key.strip()
- key_lower = key.lower()
- if not key or key_lower in target_key_set or key_lower in seen:
- continue
- seen.add(key_lower)
- result.append(key)
-
- return result
-
-
-class _CollectorSignals(QObject):
- # Создаётся в __init__ (main thread) — обеспечивает Qt thread affinity
- run_complete = Signal(list, dict)
-
-
-class CollectorModule(BaseModule):
- name = "Collector"
-
- def column_schema(self) -> list[ColumnDef]:
- return [
- ColumnDef(key="item", label="Address", width=200),
- ColumnDef(key="status", label="Status"),
- ColumnDef(key="tokens_swapped", label="Swaps", sort_type="numeric"),
- ColumnDef(key="total_collected_usd", label="Collected $", fmt="${:.2f}", sort_type="numeric"),
- ColumnDef(key="bridge_summary", label="Bridges"),
- ColumnDef(key="bridge_chain", label="Route"),
- ColumnDef(key="bridge_status", label="Bridge"),
- ]
-
- def __init__(self) -> None:
- from app.ui.module_views.collector_view import CollectorConfigWidget
- self._signals = _CollectorSignals()
- self._results: list[Result] = []
- self._widget = CollectorConfigWidget()
- self._signals.run_complete.connect(self._widget.on_run_complete)
- self._stop_event = threading.Event()
-
- def get_config_widget(self):
- return self._widget
-
- def get_item_count(self) -> int:
- return len(self._widget.get_wallets())
-
- async def run(self, ctx: RunContext) -> AsyncIterator[Result]:
- self._results.clear()
- self._stop_event.clear()
-
- wallets = self._widget.get_wallets()
- proxies = self._widget.get_proxies()
- subaccounts = self._widget.get_subaccounts()
- settings = self._widget.get_settings()
- rotator = ProxyRotator(proxies)
- loop = asyncio.get_running_loop()
-
- # ── ШАГ 0: Валидация ─────────────────────────────────────────────
- if settings.send_to_exchange and len(wallets) != len(subaccounts):
- raise ValueError(
- f"Количество кошельков ({len(wallets)}) не совпадает "
- f"с количеством субаккаунтов ({len(subaccounts)})"
- )
-
- proxy = rotator.next()
- proxy_url = proxy.to_url() if proxy else None
- lifi_client = LiFiClient(proxy=proxy_url)
- relay_client = RelayClient(proxy=proxy_url)
-
- # LI.FI /chains
- lifi_chain_ids: set[int] = set()
- lifi_rpc_by_id: dict[int, list[str]] = {}
- native_token_by_id: dict[int, dict] = {}
- lifi_key_by_id: dict[int, str] = {}
- name_by_id: dict[int, str] = {}
-
- try:
- chains = await loop.run_in_executor(None, lifi_client.get_chains)
- lifi_chain_ids = {c["id"] for c in chains}
- lifi_rpc_by_id = {c["id"]: c.get("metamask", {}).get("rpcUrls", []) for c in chains}
- native_token_by_id = {c["id"]: c["nativeToken"] for c in chains if "nativeToken" in c}
- lifi_key_by_id = {c["id"]: c.get("key", "") for c in chains}
- name_by_id = {c["id"]: c.get("name", str(c["id"])) for c in chains}
- logger.info("LI.FI: %d EVM chains loaded", len(lifi_chain_ids))
- except Exception as e:
- logger.warning("WARNING: LI.FI /chains failed, using hardcoded chain list. Swaps may be unavailable. (%s)", e)
- lifi_chain_ids = set(DEBANK_TO_CHAIN_ID.values())
- lifi_rpc_by_id = {}
- native_token_by_id = {}
-
- # Relay /chains
- relay_chain_ids: set[int] = set()
- relay_rpc_by_id: dict[int, str] = {}
- relay_native_by_id: dict[int, dict] = {}
-
- try:
- relay_chains = await loop.run_in_executor(None, relay_client.get_chains)
- logger.info("Relay: %d chains raw from API", len(relay_chains))
- relay_chain_ids = {
- c["id"] for c in relay_chains
- if c.get("vmType", "evm") == "evm"
- and not c.get("disabled", False)
- and c.get("depositEnabled", True)
- }
- relay_rpc_by_id = {
- c["id"]: c["httpRpcUrl"]
- for c in relay_chains if c.get("httpRpcUrl")
- }
- relay_native_by_id = {c["id"]: c.get("currency", {}) for c in relay_chains}
- logger.info("Relay: %d EVM chains loaded", len(relay_chain_ids))
- except Exception as e:
- logger.warning("WARNING: Relay /chains failed, continuing without Relay provider. (%s)", e)
-
- supported_chain_ids = lifi_chain_ids | relay_chain_ids
- if not supported_chain_ids:
- raise RuntimeError("No bridge providers available")
-
- # ChainList RPCs — fallback третий источник (некритично)
- chainlist_rpcs: dict[int, list[str]] = {}
- try:
- chainlist_rpcs = await loop.run_in_executor(None, fetch_chainlist_rpcs)
- except Exception as e:
- logger.warning("ChainList RPCs unavailable, continuing without: %s", e)
-
- rpc_resolver = RpcResolver(lifi_rpc_by_id, relay_rpc_by_id, chainlist_rpcs)
-
- # LI.FI /tools (некритично)
- try:
- tools = await loop.run_in_executor(None, lifi_client.get_tools)
- bridges = tools.get("bridges", [])
- exchanges = tools.get("exchanges", [])
- logger.info("LI.FI: %d bridges, %d exchanges loaded", len(bridges), len(exchanges))
- except Exception:
- pass
-
- # LI.FI /gas/prices
- gas_prices: dict = {}
- try:
- gas_prices = await loop.run_in_executor(None, lifi_client.get_gas_prices)
- except Exception as e:
- logger.warning("WARNING: LI.FI /gas/prices failed, will use web3.eth.gas_price. (%s)", e)
-
- # Резолвинг target_chains → chain IDs
- ui_logger = ctx.extra.get("logger")
- target_chain_ids: list[int] = []
- for tc in settings.target_chains:
- chain_id = DEBANK_TO_CHAIN_ID.get(tc.lower())
- if chain_id is None:
- # Пробуем по имени сети (case-insensitive)
- for cid, cname in name_by_id.items():
- if cname.lower() == tc.lower():
- chain_id = cid
- break
- if chain_id and chain_id in supported_chain_ids:
- target_chain_ids.append(chain_id)
- else:
- msg = (
- f"Target chain '{tc}' not found in DEBANK_TO_CHAIN_ID"
- if chain_id is None
- else f"Target chain '{tc}' (id={chain_id}) not supported by LI.FI or Relay"
- )
- logger.warning(msg)
- if ui_logger:
- ui_logger.warning(f"WARNING: {msg}")
-
- if not target_chain_ids:
- if not settings.target_chains:
- raise ValueError("No target chains selected — please pick at least one chain in Bridge settings")
- raise ValueError(
- f"No valid target chains configured. Selected: {settings.target_chains}. "
- f"None are supported by LI.FI or Relay. Check warnings above."
- )
-
- # ── ШАГ 1–4: обработка кошельков последовательно ─────────────────
- logger.info("Starting Collector: %d wallets, target chains: %s", len(wallets), settings.target_chains)
- try:
- for wallet_idx, wallet in enumerate(wallets):
- if self._stop_event.is_set():
- break
-
- logger.info(
- "── Wallet %d/%d ──────────────────────────────",
- wallet_idx + 1, len(wallets),
- )
-
- proxy = rotator.next()
- proxy_url = proxy.to_url() if proxy else None
- debank_client = DeBankClient(proxy=proxy_url or "http://127.0.0.1:8080")
-
- result_data: dict = {}
- bridge_tx: str | None = None
- bridge_ops: list[dict] = []
- bridge_status = ""
- exchange_tx: str | None = None
- total_sent_usd = 0.0
-
- try:
- # ШАГ 1-2: DeBank + swap
- swap_result = await fetch_and_swap(
- wallet=wallet,
- lifi_client=lifi_client,
- debank_client=debank_client,
- rpc_resolver=rpc_resolver,
- settings=settings,
- native_token_by_id=native_token_by_id,
- relay_native_by_id=relay_native_by_id,
- lifi_chain_ids=lifi_chain_ids,
- supported_chain_ids=supported_chain_ids,
- stop_event=self._stop_event,
- target_chain_ids=set(target_chain_ids),
- )
-
- if not swap_result:
- result = Result(
- item=wallet["raw"][:42],
- status=ResultStatus.ERROR,
- error="fetch_and_swap failed",
- )
- self._results.append(result)
- yield result
- continue
-
- address = swap_result["address"]
- private_key = swap_result["private_key"]
-
- # ── ШАГ 2.5–2.6: рефьюел и повторный своп на gasless цепях ──
- gasless_chains = swap_result.pop("gasless_chains", [])
- if gasless_chains and not self._stop_event.is_set():
- target_key_set_local = set(settings.target_chains)
- # Кандидаты-доноры: обработанные не-target цепи + сами target-цепи
- donor_candidates: list[int] = []
- for k in swap_result.get("chains_processed", "").split(", "):
- if not k or k in target_key_set_local:
- continue
- cid = DEBANK_TO_CHAIN_ID.get(k)
- if cid and cid in relay_chain_ids:
- donor_candidates.append(cid)
- # Target-цепи часто имеют больше всего нативки (например Soneium с ETH)
- for tc_key in target_key_set_local:
- tc_cid = DEBANK_TO_CHAIN_ID.get(tc_key.lower())
- if tc_cid and tc_cid in relay_chain_ids and tc_cid not in donor_candidates:
- donor_candidates.append(tc_cid)
-
- refueled: list[dict] = []
- for gc in gasless_chains:
- if self._stop_event.is_set():
- break
- tgt_cid: int = gc["chain_id"]
- if tgt_cid not in relay_chain_ids:
- logger.info(
- "[Wallet %s] Cannot refuel chain %s: not supported by Relay",
- address[:10], tgt_cid,
- )
- continue
-
- # Считаем дефицит газа в USD — нативные токены у разных цепей имеют разную цену
- gasless_price_usd = float(
- native_token_by_id.get(tgt_cid, {}).get("priceUSD")
- or relay_native_by_id.get(tgt_cid, {}).get("priceUSD")
- or 2000
- )
- gas_deficit = max(0, gc["max_gas_needed_wei"] - gc.get("eth_balance", 0))
- if gas_deficit <= 0:
- logger.info(
- "[Wallet %s] Chain %s no longer needs refuel",
- address[:10], tgt_cid,
- )
- continue
- desired_out_wei = gas_deficit * 2 # 2× запас на целевой сети
- refuel_usd = desired_out_wei / 1e18 * gasless_price_usd
-
- donor_found = False
- for donor_cid in donor_candidates:
- try:
- w3_d = rpc_resolver.get_web3(donor_cid)
- donor_bal = await loop.run_in_executor(
- None, w3_d.eth.get_balance, address
- )
- except Exception:
- continue
- # Считаем USD-баланс донора по цене его нативного токена
- donor_price_usd = float(
- native_token_by_id.get(donor_cid, {}).get("priceUSD")
- or relay_native_by_id.get(donor_cid, {}).get("priceUSD")
- or 1
- )
- donor_bal_usd = donor_bal / 1e18 * donor_price_usd
- # Донор покрывает рефьюел + $0.01 на газ бридж-транзакции донора
- if donor_bal_usd < refuel_usd + 0.01:
- continue
- # Конвертируем нужную сумму в нативные единицы донора
- refuel_amount = int(refuel_usd / donor_price_usd * 1e18)
- max_refuel_amount = int(max(0.0, donor_bal_usd - 0.01) / donor_price_usd * 1e18)
- if max_refuel_amount <= 0:
- continue
- ok = await refuel_chain(
- address=address,
- private_key=private_key,
- donor_chain_id=donor_cid,
- tgt_chain_id=tgt_cid,
- refuel_amount_wei=refuel_amount,
- min_required_out_wei=desired_out_wei,
- max_refuel_amount_wei=max_refuel_amount,
- relay_client=relay_client,
- relay_native_by_id=relay_native_by_id,
- rpc_resolver=rpc_resolver,
- stop_event=self._stop_event,
- )
- if ok:
- refueled.append(gc)
- donor_found = True
- break
- if not donor_found:
- logger.info(
- "[Wallet %s] No suitable donor to refuel chain %s",
- address[:10], tgt_cid,
- )
-
- if refueled and not self._stop_event.is_set():
- retry_result = await retry_gasless_swaps(
- gasless_chains=refueled,
- address=address,
- private_key=private_key,
- lifi_client=lifi_client,
- rpc_resolver=rpc_resolver,
- settings=settings,
- native_token_by_id=native_token_by_id,
- relay_native_by_id=relay_native_by_id,
- lifi_chain_ids=lifi_chain_ids,
- stop_event=self._stop_event,
- )
- if retry_result and retry_result.get("chains_processed"):
- existing = swap_result.get("chains_processed", "")
- new_processed = retry_result["chains_processed"]
- swap_result["chains_processed"] = (
- existing + ", " + new_processed if existing else new_processed
- )
- swap_result["tokens_swapped"] = (
- swap_result.get("tokens_swapped", 0) + retry_result.get("tokens_swapped", 0)
- )
- swap_result["total_collected_usd"] = round(
- swap_result.get("total_collected_usd", 0.0) + retry_result.get("total_usd", 0.0), 2
- )
-
- result_data.update(swap_result)
- # Удаляем поля избыточные для таблицы
- for _k in ("private_key", "address", "chains_processed", "chains_skipped"):
- result_data.pop(_k, None)
-
- processed_keys = _build_processed_bridge_keys(
- chains_processed=swap_result.get("chains_processed", ""),
- target_chains=settings.target_chains,
- )
- if not processed_keys:
- result = Result(
- item=address,
- status=ResultStatus.SKIP,
- data=result_data,
- )
- self._results.append(result)
- yield result
- # Посекундная задержка перед следующим кошельком
- if wallet_idx < len(wallets) - 1:
- delay = random.randint(settings.delay_min, settings.delay_max)
- for _ in range(delay):
- if self._stop_event.is_set():
- break
- await asyncio.sleep(1)
- continue
-
- # Бридж из каждой активной сети
- # Приоритет статусов: чем меньше — тем лучше
- _BRIDGE_PRIORITY = {
- "COMPLETED": 0, "SENT": 1, "PARTIAL": 2, "REFUNDED": 3,
- "NODE_REJECTED": 4, "TX_REVERTED": 5, "NO_RPC": 6, "TIMEOUT": 7,
- "NO_QUOTE": 8, "INSUFFICIENT": 9, "BELOW_MIN": 10, "NO_ROUTE": 11, "STOPPED": 12,
- }
- tgt_id = None
- best_src_key = "?"
- for src_key in processed_keys:
- if self._stop_event.is_set():
- break
- src_chain_id = DEBANK_TO_CHAIN_ID.get(src_key)
- if not src_chain_id:
- continue
-
- # ШАГ 3: бридж
- b_tx, b_status, b_tgt_id, b_sent_usd = await bridge_native(
- address=address,
- private_key=private_key,
- lifi_client=lifi_client,
- relay_client=relay_client,
- rpc_resolver=rpc_resolver,
- settings=settings,
- lifi_chain_ids=lifi_chain_ids,
- relay_chain_ids=relay_chain_ids,
- native_token_by_id=native_token_by_id,
- relay_native_by_id=relay_native_by_id,
- target_chain_ids=target_chain_ids,
- src_chain_id=src_chain_id,
- gas_prices=gas_prices,
- stop_event=self._stop_event,
- )
- total_sent_usd += b_sent_usd
-
- bridge_ops.append({
- "src": src_key,
- "tgt": name_by_id.get(b_tgt_id, str(b_tgt_id)) if b_tgt_id else "",
- "tx": b_tx or "",
- "status": b_status,
- "usd": round(b_sent_usd, 4),
- })
-
- # Сохраняем лучший статус — не даём плохому перезаписать хороший
- if _BRIDGE_PRIORITY.get(b_status, 99) < _BRIDGE_PRIORITY.get(bridge_status, 99):
- bridge_tx = b_tx
- bridge_status = b_status
- tgt_id = b_tgt_id
- best_src_key = src_key
-
- # Задержка после каждого выполненного бриджа
- if b_status in ("COMPLETED", "SENT") and not self._stop_event.is_set():
- delay = random.randint(settings.delay_min, settings.delay_max)
- logger.info(
- "[Wallet %s] Delay %ds after bridge from %s (status=%s)",
- address[:10], delay, src_key, b_status,
- )
- for _ in range(delay):
- if self._stop_event.is_set():
- break
- await asyncio.sleep(1)
-
- # ШАГ 4: отправка на биржу — один раз после всех бриджей
- if (
- settings.send_to_exchange
- and bridge_status in ("COMPLETED", "PARTIAL", "REFUNDED")
- and tgt_id is not None
- and not self._stop_event.is_set()
- ):
- exchange_tx = await send_to_exchange(
- address=address,
- private_key=private_key,
- exchange_address=subaccounts[wallet_idx],
- tgt_chain_id=tgt_id,
- rpc_resolver=rpc_resolver,
- gas_prices=gas_prices,
- settings=settings,
- stop_event=self._stop_event,
- )
-
- # total_collected_usd = сумма фактически отправленных через бридж средств
- result_data["total_collected_usd"] = round(total_sent_usd, 2)
-
- if tgt_id is not None:
- last_tgt = name_by_id.get(tgt_id, str(tgt_id))
- result_data["bridge_chain"] = f"{best_src_key} → {last_tgt}"
- else:
- result_data["bridge_chain"] = ""
- result_data["bridge_tx"] = bridge_tx or ""
- # Compact bridge summary for the table column
- if isinstance(bridge_ops, list) and bridge_ops:
- ok_count = sum(1 for op in bridge_ops if op.get("status") == "ok")
- result_data["bridge_summary"] = f"{ok_count}/{len(bridge_ops)}"
- else:
- result_data["bridge_summary"] = ""
- result_data["_detail_bridge_ops"] = bridge_ops # full data for export only
- result_data["bridge_status"] = bridge_status
- result_data["exchange_tx"] = exchange_tx or ""
- _SKIP_STATUSES = ("NO_QUOTE", "NO_ROUTE", "BELOW_MIN", "STOPPED", "INSUFFICIENT", "NOT_INDEXED", "TX_REVERTED")
-
- if bridge_status in ("COMPLETED", "PARTIAL", "SENT"):
- result_status = ResultStatus.OK
- elif bridge_status in _SKIP_STATUSES:
- result_status = ResultStatus.SKIP
- else:
- result_status = ResultStatus.ERROR
-
- logger.info(
- "[Wallet %s] Result: %s (bridge_status=%s)",
- address, result_status.name, bridge_status,
- )
- result = Result(
- item=address,
- status=result_status,
- data=result_data,
- )
-
- except Exception as e:
- logger.exception("[Wallet %d] Unexpected error: %s", wallet_idx, e)
- result = Result(
- item=wallet.get("raw", "?")[:42],
- status=ResultStatus.ERROR,
- error=str(e),
- )
-
- self._results.append(result)
- yield result
-
- # Задержка между кошельками
- if wallet_idx < len(wallets) - 1:
- delay = random.randint(settings.delay_min, settings.delay_max)
- logger.info(
- "[Wallet %d] Delay %ds before next wallet...",
- wallet_idx + 1, delay,
- )
- for _ in range(delay):
- if self._stop_event.is_set():
- break
- await asyncio.sleep(1)
-
- finally:
- logger.info("Collector finished. Total: %d results.", len(self._results))
- self._signals.run_complete.emit(list(self._results), {})
-
- async def stop(self) -> None:
- self._stop_event.set()
diff --git a/app/modules/token_collector/_bridge_logic.py b/app/modules/token_collector/_bridge_logic.py
deleted file mode 100644
index 0bb1397..0000000
--- a/app/modules/token_collector/_bridge_logic.py
+++ /dev/null
@@ -1,760 +0,0 @@
-# app/modules/token_collector/_bridge_logic.py
-from __future__ import annotations
-import asyncio
-import logging
-import random
-import threading
-import time
-from typing import Any
-
-logger = logging.getLogger(__name__)
-
-# Таймаут ожидания бриджа — 30 минут
-BRIDGE_TIMEOUT_SEC = 30 * 60
-
-# OP-stack GasPriceOracle — одинаковый адрес на всех OP-stack цепях
-# (OP, Base, INK, Unichain, Mode, Lisk, Soneium, World, Zora...)
-_L1_GAS_ORACLE = "0x420000000000000000000000000000000000000F"
-_L1_FEE_ABI = [
- {
- "inputs": [{"internalType": "bytes", "name": "_data", "type": "bytes"}],
- "name": "getL1Fee",
- "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
- "stateMutability": "view",
- "type": "function",
- }
-]
-
-
-def _hi(v) -> int:
- """Парсит hex (0x-префикс) или decimal строку/int в int."""
- if not v:
- return 0
- if isinstance(v, str):
- return int(v, 16) if v.startswith("0x") else int(v)
- return int(v)
-
-
-def _tx_gas_cost(tx_req: dict) -> int:
- """Реальная стоимость газа из transactionRequest: gasLimit × maxFeePerGas (или gasPrice)."""
-
- gas_limit = _hi(tx_req.get("gasLimit") or tx_req.get("gas"))
- gas_price = _hi(tx_req.get("maxFeePerGas") or tx_req.get("gasPrice"))
- return gas_limit * gas_price
-
-
-def _get_l1_fee_safe(w3: Any, tx_req: dict) -> int:
- """
- Оценивает L1 data fee для OP-stack цепей через GasPriceOracle.getL1Fee().
- На ETH mainnet, ARB и других non-OP-stack цепях оракул отсутствует → возвращает 0.
-
- Передаём ~300 байт RLP-заголовка (нули) + calldata — это приближение реального
- размера подписанной транзакции. Нули стоят 4 gas/byte (дешевле реального заголовка),
- поэтому оценка чуть занижена — умножаем на 1.1 для запаса.
- """
- from web3 import Web3
- try:
- oracle = w3.eth.contract(
- address=Web3.to_checksum_address(_L1_GAS_ORACLE),
- abi=_L1_FEE_ABI,
- )
- data_hex = tx_req.get("data") or "0x"
- calldata = bytes.fromhex(data_hex[2:] if data_hex.startswith("0x") else data_hex)
- # ~300 байт RLP-заголовка (нули) + calldata ≈ реальный размер tx
- tx_bytes = bytes(300) + calldata
- fee = int(oracle.functions.getL1Fee(tx_bytes).call())
- # +10% запас: заголовок содержит ненулевые байты (дороже чем нули в нашей аппроксимации)
- return fee * 11 // 10
- except Exception:
- return 0 # Non-OP-stack цепь или оракул недоступен
-
-
-def _relay_quote_is_too_small_error(exc: Exception) -> bool:
- """Определяет ошибки Relay, где нужно просто увеличить input-amount."""
- msg = str(exc).lower()
- needles = (
- "too small",
- "cover fees",
- "minimum amount",
- "minimum input",
- "insufficient output amount",
- )
- return any(needle in msg for needle in needles)
-
-
-def _relay_quote_out_amount(relay_quote: dict) -> int:
- """Возвращает ожидаемый amount на destination chain из Relay quote."""
- try:
- return int(relay_quote.get("details", {}).get("currencyOut", {}).get("amount") or 0)
- except Exception:
- return 0
-
-
-async def _find_refuel_quote(
- *,
- loop: asyncio.AbstractEventLoop,
- relay_client: Any,
- donor_chain_id: int,
- tgt_chain_id: int,
- donor_native: str,
- tgt_native: str,
- address: str,
- requested_amount_wei: int,
- min_required_out_wei: int,
- max_refuel_amount_wei: int | None,
-) -> tuple[int, int, dict] | tuple[None, None, None]:
- """
- Подбирает минимальный input для Relay refuel.
- Увеличивает сумму, если route слишком маленький или ожидаемый output меньше требуемого.
- """
- candidate_amount = max(1, int(requested_amount_wei))
- max_amount = max(candidate_amount, int(max_refuel_amount_wei or candidate_amount))
- last_error: Exception | None = None
-
- for _ in range(8):
- try:
- relay_q = await loop.run_in_executor(
- None,
- relay_client.get_quote,
- donor_chain_id, tgt_chain_id,
- donor_native, tgt_native,
- str(candidate_amount), address,
- )
- out_amount = _relay_quote_out_amount(relay_q)
- if min_required_out_wei and out_amount < min_required_out_wei:
- last_error = RuntimeError(
- f"quoted output {out_amount} < required {min_required_out_wei}"
- )
- else:
- return candidate_amount, out_amount, relay_q
- except Exception as e:
- last_error = e
- if not _relay_quote_is_too_small_error(e):
- break
- out_amount = 0
-
- if candidate_amount >= max_amount:
- break
-
- if min_required_out_wei and out_amount > 0:
- scaled_amount = (
- candidate_amount * min_required_out_wei * 11 + (out_amount * 10) - 1
- ) // (out_amount * 10)
- next_amount = max(candidate_amount * 2, scaled_amount)
- else:
- next_amount = candidate_amount * 2
-
- next_amount = min(max_amount, next_amount)
- if next_amount <= candidate_amount:
- break
-
- logger.info(
- "[Refuel] Bumping input for %s → %s from %d to %d wei",
- donor_chain_id, tgt_chain_id, candidate_amount, next_amount,
- )
- candidate_amount = next_amount
-
- if last_error:
- logger.warning(
- "[Refuel] Could not find viable quote %s → %s up to %d wei: %s",
- donor_chain_id, tgt_chain_id, max_amount, last_error,
- )
- return None, None, None
-
-
-async def bridge_native(
- address: str,
- private_key: str,
- lifi_client: Any, # LiFiClient
- relay_client: Any, # RelayClient
- rpc_resolver: Any, # RpcResolver
- settings: Any, # CollectorSettings
- lifi_chain_ids: set[int],
- relay_chain_ids: set[int],
- native_token_by_id: dict[int, dict],
- relay_native_by_id: dict[int, dict],
- target_chain_ids: list[int],
- src_chain_id: int,
- gas_prices: dict,
- stop_event: threading.Event,
-) -> tuple[str | None, str, int | None, float]:
- """
- ШАГ 3: бридж нативного токена из src_chain_id в target_chain.
- Возвращает (bridge_tx, bridge_status, tgt_chain_id, sent_usd).
- sent_usd — USD-стоимость отправленной суммы при статусе COMPLETED, иначе 0.0.
- """
- from app.integrations.lifi_client import LiFiNoRouteError
- from app.integrations.relay_client import RelayNoRouteError
- from app.modules.token_collector._signer import sign_and_send, TransactionReverted
-
- loop = asyncio.get_running_loop()
-
- tgt_chain_id = random.choice(target_chain_ids)
- logger.info("[Wallet %s] Bridge: chain %s → %s", address[:10], src_chain_id, tgt_chain_id)
-
- # Определяем доступных провайдеров
- lifi_ok = src_chain_id in lifi_chain_ids and tgt_chain_id in lifi_chain_ids
- relay_ok = src_chain_id in relay_chain_ids and tgt_chain_id in relay_chain_ids
-
- if not lifi_ok and not relay_ok:
- logger.info(
- "[Wallet %s] No bridge route %s → %s on any provider",
- address[:10], src_chain_id, tgt_chain_id
- )
- return None, "NO_ROUTE", None, 0.0
-
- # Проверяем LI.FI connections
- if lifi_ok:
- try:
- connections = await loop.run_in_executor(
- None, lifi_client.get_connections, src_chain_id, tgt_chain_id
- )
- if not connections:
- lifi_ok = False
- except Exception as e:
- logger.warning(
- "[Wallet %s] LI.FI connections check failed (%s → %s): %s",
- address[:10], src_chain_id, tgt_chain_id, e,
- )
- lifi_ok = False
-
- # Адреса нативных токенов
- src_native = (
- native_token_by_id.get(src_chain_id, {}).get("address")
- or relay_native_by_id.get(src_chain_id, {}).get("address")
- or "0x0000000000000000000000000000000000000000"
- )
- tgt_native = (
- native_token_by_id.get(tgt_chain_id, {}).get("address")
- or relay_native_by_id.get(tgt_chain_id, {}).get("address")
- or "0x0000000000000000000000000000000000000000"
- )
-
- try:
- w3 = rpc_resolver.get_web3(src_chain_id)
- except RuntimeError as e:
- logger.warning("[Wallet %s] No RPC available for chain %s: %s", address[:10], src_chain_id, e)
- return None, "NO_RPC", None, 0.0
-
- # Получаем баланс с ротацией при сбое RPC
- try:
- balance_wei = await loop.run_in_executor(None, w3.eth.get_balance, address)
- except Exception as e:
- logger.warning("[Wallet %s] RPC error on get_balance chain %s (%s), rotating...", address[:10], src_chain_id, e)
- try:
- w3 = rpc_resolver.rotate(src_chain_id)
- balance_wei = await loop.run_in_executor(None, w3.eth.get_balance, address)
- except Exception as e2:
- logger.error("[Wallet %s] All RPCs failed for chain %s: %s", address[:10], src_chain_id, e2)
- return None, "NO_RPC", None, 0.0
-
- # Цена нативного токена (нужна и для min_bridge_usd и для расчёта sent_usd)
- price_usd = float(
- native_token_by_id.get(src_chain_id, {}).get("priceUSD", 0)
- or relay_native_by_id.get(src_chain_id, {}).get("priceUSD", 0)
- or 0
- )
-
- # Проверка минимальной суммы для бриджа
- if settings.min_bridge_usd > 0:
- balance_usd = (balance_wei / 1e18) * price_usd
- # Допуск 0.001$ чтобы float precision не отсекал пограничные значения ($0.10 vs $0.09999...)
- if price_usd > 0 and balance_usd < settings.min_bridge_usd - 0.001:
- logger.info(
- "[Wallet %s] Bridge skipped: balance $%.4f < min_bridge_usd $%.2f",
- address[:10], balance_usd, settings.min_bridge_usd,
- )
- return None, "BELOW_MIN", None, 0.0
-
- # Пробные котировки для сравнения
- lifi_out = 0
- lifi_gas = 0
- lifi_l1_fee = 0
- relay_out = 0
- relay_gas = 0
- relay_l1_fee = 0
-
- if lifi_ok:
- try:
- lifi_q = await loop.run_in_executor(
- None,
- lifi_client.get_quote,
- src_chain_id, tgt_chain_id,
- src_native, tgt_native,
- balance_wei, address, address, settings.slippage,
- )
- # Берём газ из transactionRequest — реальная стоимость source tx (gasLimit × gasPrice).
- # gas_suggestion от LI.FI НЕ используем: это "рекомендованный резерв" для многих
- # будущих транзакций, он в 5-50x превышает стоимость одного бриджа и блокирует мелкие кошельки.
- lifi_tx_req_probe = lifi_q.get("transactionRequest", {})
- lifi_gas = _tx_gas_cost(lifi_tx_req_probe)
- if lifi_gas == 0:
- lifi_gas = sum(int(g["amount"]) for g in lifi_q.get("estimate", {}).get("gasCosts", []))
- lifi_out = int(lifi_q.get("estimate", {}).get("toAmountMin", 0))
- # L1 data fee для OP-stack (на ETH/ARB/etc. возвращает 0)
- lifi_l1_fee = await loop.run_in_executor(None, _get_l1_fee_safe, w3, lifi_tx_req_probe)
- except (LiFiNoRouteError, Exception) as e:
- logger.warning("[Wallet %s] LI.FI quote failed: %s", address[:10], e)
- lifi_ok = False
-
- if relay_ok:
- try:
- relay_src_native = (
- relay_native_by_id.get(src_chain_id, {}).get("address")
- or "0x0000000000000000000000000000000000000000"
- )
- relay_tgt_native = (
- relay_native_by_id.get(tgt_chain_id, {}).get("address")
- or "0x0000000000000000000000000000000000000000"
- )
- relay_q = await loop.run_in_executor(
- None,
- relay_client.get_quote,
- src_chain_id, tgt_chain_id,
- relay_src_native, relay_tgt_native,
- str(balance_wei), address,
- )
- # Берём газ из tx_req source-транзакции (gasLimit × gasPrice).
- # fees["relayer"] — протокольная комиссия, вычитается из VALUE (output),
- # не требует дополнительного ETH в кошельке — не включаем в gas_reserve.
- relay_tx_req = relay_q["steps"][0]["items"][0]["data"]
- relay_gas = _tx_gas_cost(relay_tx_req)
- if relay_gas == 0:
- relay_gas = int(relay_q["fees"]["gas"]["amount"])
- relay_out = int(relay_q["details"]["currencyOut"]["amount"])
- # L1 data fee для OP-stack (на ETH/ARB/etc. возвращает 0)
- relay_l1_fee = await loop.run_in_executor(None, _get_l1_fee_safe, w3, relay_tx_req)
- except Exception as e:
- logger.warning("[Wallet %s] Relay quote failed: %s", address[:10], e)
- relay_ok = False
-
- if not lifi_ok and not relay_ok:
- return None, "NO_QUOTE", None, 0.0
-
- # Выбор провайдера по максимальному out
- if lifi_ok and relay_ok:
- provider = "lifi" if lifi_out >= relay_out else "relay"
- elif lifi_ok:
- provider = "lifi"
- else:
- provider = "relay"
-
- chosen_gas = lifi_gas if provider == "lifi" else relay_gas
- chosen_l1_fee = lifi_l1_fee if provider == "lifi" else relay_l1_fee
- chosen_out = lifi_out if provider == "lifi" else relay_out
- if chosen_l1_fee:
- logger.info(
- "[Bridge] provider=%s out=%.6f (lifi=%s relay=%s) l1_fee=%d",
- provider, chosen_out / 1e18, lifi_out, relay_out, chosen_l1_fee,
- )
- else:
- logger.info(
- "[Bridge] provider=%s out=%.6f (lifi=%s relay=%s)",
- provider, chosen_out / 1e18, lifi_out, relay_out,
- )
-
- # gas_reserve = source tx gas × 2 (запас на случай спайка baseFee)
- # + L1 data fee для OP-stack цепей (на ETH/ARB/etc. = 0).
- gas_reserve = chosen_gas * 2 + chosen_l1_fee
-
- if gas_reserve == 0:
- # Последний fallback: web3 gas_price × лимит для bridge tx
- gas_price_wei = await loop.run_in_executor(None, lambda: w3.eth.gas_price)
- gas_reserve = gas_price_wei * 500_000
- logger.info("[Wallet %s] Gas reserve was 0, fallback: %d wei", address[:10], gas_reserve)
-
- send_amount = balance_wei - gas_reserve
-
- logger.info(
- "[Wallet %s] Gas calc: source_gas=%d reserve=%d balance=%d send=%d ($%.4f)",
- address[:10], chosen_gas, gas_reserve, balance_wei, send_amount,
- send_amount / 1e18 * float(
- native_token_by_id.get(src_chain_id, {}).get("priceUSD", 0) or 0
- ),
- )
-
- if send_amount <= 0:
- logger.info("[Wallet %s] Insufficient balance for bridge after gas reserve", address[:10])
- return None, "INSUFFICIENT", tgt_chain_id, 0.0
-
- # Финальная котировка
- try:
- if provider == "lifi":
- final_quote = await loop.run_in_executor(
- None,
- lifi_client.get_quote,
- src_chain_id, tgt_chain_id,
- src_native, tgt_native,
- send_amount, address, address, settings.slippage,
- )
- tx_req = final_quote["transactionRequest"]
- else:
- relay_src_native = (
- relay_native_by_id.get(src_chain_id, {}).get("address")
- or "0x0000000000000000000000000000000000000000"
- )
- relay_tgt_native = (
- relay_native_by_id.get(tgt_chain_id, {}).get("address")
- or "0x0000000000000000000000000000000000000000"
- )
- final_quote = await loop.run_in_executor(
- None,
- relay_client.get_quote,
- src_chain_id, tgt_chain_id,
- relay_src_native, relay_tgt_native,
- str(send_amount), address,
- )
- tx_req = final_quote["steps"][0]["items"][0]["data"]
- except Exception as e:
- logger.warning(
- "[Wallet %s] Final quote failed (provider=%s, send_amount=%d): %s",
- address[:10], provider, send_amount, e,
- )
- return None, "NO_QUOTE", tgt_chain_id, 0.0
-
- # Safety-check: вычисляем gas cost так же как sign_and_send —
- # читаем свежий baseFee и применяем priority из котировки.
- # ВАЖНО: tx_req.maxFeePerGas у Relay может быть placeholder (0 или 1 wei) —
- # нельзя использовать как fallback; нужен реальный baseFee из сети.
- gas_limit = _hi(tx_req.get("gasLimit") or tx_req.get("gas"))
- base_fee: int | None = None
- try:
- base_fee = await loop.run_in_executor(None, lambda: w3.eth.get_block("latest")["baseFeePerGas"])
- except Exception as _e1:
- logger.debug("[Wallet %s] get_block failed in safety check (%s), trying gas_price...", address[:10], _e1)
- try:
- base_fee = await loop.run_in_executor(None, lambda: w3.eth.gas_price)
- except Exception as _e2:
- logger.warning("[Wallet %s] Cannot determine gas price for safety check (%s) — skipping bridge", address[:10], _e2)
- return None, "INSUFFICIENT", tgt_chain_id, 0.0
-
- if "maxFeePerGas" in tx_req:
- priority = max(1, _hi(tx_req.get("maxPriorityFeePerGas")))
- effective_gas_price = base_fee * 11 // 10 + priority
- else:
- quote_gp = _hi(tx_req.get("gasPrice"))
- effective_gas_price = max(quote_gp, base_fee * 2) if base_fee else quote_gp * 2
-
- final_gas_cost = gas_limit * effective_gas_price
- # L1 data fee для финальной котировки (OP-stack цепи)
- l1_data_fee = await loop.run_in_executor(None, _get_l1_fee_safe, w3, tx_req)
- tx_value = _hi(tx_req.get("value"))
- logger.info(
- "[Wallet %s] Safety check: value=%d gas_limit=%d gas_price=%d gas_cost=%d l1_fee=%d balance=%d",
- address[:10], tx_value, gas_limit, effective_gas_price, final_gas_cost, l1_data_fee, balance_wei,
- )
- if tx_value + final_gas_cost + l1_data_fee > balance_wei:
- logger.warning(
- "[Wallet %s] Final tx exceeds balance (value=%d gas=%d l1_fee=%d price=%d balance=%d), skipping",
- address[:10], tx_value, gas_limit, l1_data_fee, effective_gas_price, balance_wei,
- )
- return None, "INSUFFICIENT", tgt_chain_id, 0.0
-
- # Снимаем баланс на destination chain ДО отправки tx (Relay доставляет за секунды!)
- pre_balance = 0
- try:
- w3_tgt = rpc_resolver.get_web3(tgt_chain_id)
- pre_balance = await loop.run_in_executor(None, w3_tgt.eth.get_balance, address)
- except Exception as e:
- logger.warning("[Wallet %s] Could not get pre-bridge balance on chain %s: %s", address[:10], tgt_chain_id, e)
-
- try:
- tx_hash, receipt = await loop.run_in_executor(
- None, sign_and_send, w3, tx_req, private_key, address
- )
- except TransactionReverted as e:
- logger.warning("[Wallet %s] Bridge tx reverted: %s", address[:10], e.tx_hash)
- return e.tx_hash, "TX_REVERTED", tgt_chain_id, 0.0
- except Exception as e:
- e_str = str(e)
- if "-32000" in e_str:
- logger.warning("[Wallet %s] Bridge tx rejected by node: %s", address[:10], e_str[:160])
- return None, "NODE_REJECTED", tgt_chain_id, 0.0
- raise
-
- # Ожидаемый минимум поступления (50% от quoted toAmountMin — консервативный порог)
- if provider == "lifi":
- to_amount_min = int(final_quote.get("estimate", {}).get("toAmountMin", 0))
- else:
- to_amount_min = int(relay_q.get("details", {}).get("currencyOut", {}).get("minimumAmount", 0) or 0)
- expected_min = int(to_amount_min * 0.5) if to_amount_min > 0 else 1
-
- logger.info(
- "[Wallet %s] Bridge tx: %s | pre_balance=%d expected_min=%d wei",
- address[:10], tx_hash, pre_balance, expected_min,
- )
-
- status = await _poll_balance_increase(
- rpc_resolver=rpc_resolver,
- address=address,
- tgt_chain_id=tgt_chain_id,
- pre_balance=pre_balance,
- expected_min=expected_min,
- loop=loop,
- stop_event=stop_event,
- )
-
- # Если tx отправлена, но RPC destination упал — не помечаем как ошибку.
- # "SENT" = транзакция в сети, мониторинг недоступен.
- if status == "NO_RPC":
- logger.warning(
- "[Wallet %s] Bridge tx %s sent but destination RPC unavailable — marking SENT",
- address[:10], tx_hash,
- )
- status = "SENT"
-
- sent_usd = round(send_amount / 1e18 * price_usd, 4) if status in ("COMPLETED", "SENT") else 0.0
- return tx_hash, status, tgt_chain_id, sent_usd
-
-
-async def _poll_balance_increase(
- rpc_resolver: Any,
- address: str,
- tgt_chain_id: int,
- pre_balance: int,
- expected_min: int,
- loop: asyncio.AbstractEventLoop,
- stop_event: threading.Event,
-) -> str:
- """
- Опрашивает баланс на destination chain каждые 10 сек.
- Возвращает COMPLETED когда баланс вырос на expected_min, TIMEOUT через 30 мин.
- Надёжнее API-поллинга: не зависит от скорости индексации LI.FI / Relay.
- """
- POLL_INTERVAL = 10
- elapsed = 0
-
- try:
- w3 = rpc_resolver.get_web3(tgt_chain_id)
- except Exception as e:
- logger.warning("[Bridge] No RPC for destination chain %s: %s", tgt_chain_id, e)
- return "NO_RPC"
-
- while elapsed < BRIDGE_TIMEOUT_SEC:
- if stop_event.is_set():
- return "STOPPED"
- await asyncio.sleep(POLL_INTERVAL)
- elapsed += POLL_INTERVAL
-
- try:
- balance = await loop.run_in_executor(None, w3.eth.get_balance, address)
- increase = balance - pre_balance
- if increase >= expected_min:
- logger.info(
- "[Wallet %s] Bridge COMPLETED: balance on chain %s +%.6f ETH (after %ds)",
- address[:10], tgt_chain_id, increase / 1e18, elapsed,
- )
- return "COMPLETED"
- if elapsed % 60 == 0: # лог раз в минуту
- logger.info(
- "[Wallet %s] Waiting bridge on chain %s... +%.8f ETH / need %.8f ETH (%ds)",
- address[:10], tgt_chain_id,
- max(increase, 0) / 1e18, expected_min / 1e18, elapsed,
- )
- except Exception as e:
- logger.warning("[Wallet %s] Balance check error on chain %s: %s — rotating RPC", address[:10], tgt_chain_id, e)
- try:
- w3 = rpc_resolver.rotate(tgt_chain_id)
- except RuntimeError:
- logger.error("[Wallet %s] All RPCs exhausted for chain %s", address[:10], tgt_chain_id)
- return "NO_RPC"
-
- logger.error("[Wallet %s] Bridge timeout after %ds", address[:10], BRIDGE_TIMEOUT_SEC)
- return "TIMEOUT"
-
-
-async def refuel_chain(
- address: str,
- private_key: str,
- donor_chain_id: int,
- tgt_chain_id: int,
- refuel_amount_wei: int,
- min_required_out_wei: int,
- max_refuel_amount_wei: int | None,
- relay_client: Any,
- relay_native_by_id: dict[int, dict],
- rpc_resolver: Any,
- stop_event: threading.Event,
-) -> bool:
- """
- ШАГ 2.5: отправляет небольшое количество нативного токена из donor_chain_id
- в tgt_chain_id через Relay, чтобы покрыть газ для последующих свапов.
- Возвращает True если средства успешно доставлены.
- """
- from app.modules.token_collector._signer import sign_and_send
-
- REFUEL_TIMEOUT_SEC = 3 * 60 # 3 минуты
- POLL_INTERVAL = 10
-
- loop = asyncio.get_running_loop()
-
- donor_native = (
- relay_native_by_id.get(donor_chain_id, {}).get("address")
- or "0x0000000000000000000000000000000000000000"
- )
- tgt_native = (
- relay_native_by_id.get(tgt_chain_id, {}).get("address")
- or "0x0000000000000000000000000000000000000000"
- )
-
- logger.info(
- "[Refuel] %s → chain %s: requesting %d wei (%s ETH) for gas",
- donor_chain_id, tgt_chain_id, refuel_amount_wei, refuel_amount_wei / 1e18,
- )
-
- actual_refuel_amount, quoted_out_amount, relay_q = await _find_refuel_quote(
- loop=loop,
- relay_client=relay_client,
- donor_chain_id=donor_chain_id,
- tgt_chain_id=tgt_chain_id,
- donor_native=donor_native,
- tgt_native=tgt_native,
- address=address,
- requested_amount_wei=refuel_amount_wei,
- min_required_out_wei=min_required_out_wei,
- max_refuel_amount_wei=max_refuel_amount_wei,
- )
- if not relay_q or actual_refuel_amount is None:
- return False
-
- tx_req = relay_q["steps"][0]["items"][0]["data"]
- if actual_refuel_amount != refuel_amount_wei:
- logger.info(
- "[Refuel] Adjusted input %s → %s: %d -> %d wei (quoted out %d wei)",
- donor_chain_id, tgt_chain_id, refuel_amount_wei, actual_refuel_amount, quoted_out_amount or 0,
- )
- else:
- logger.info(
- "[Refuel] %s → chain %s: sending %d wei (%s ETH) for gas",
- donor_chain_id, tgt_chain_id, actual_refuel_amount, actual_refuel_amount / 1e18,
- )
-
- try:
- w3_donor = rpc_resolver.get_web3(donor_chain_id)
- except Exception as e:
- logger.warning("[Refuel] No RPC for donor chain %s: %s", donor_chain_id, e)
- return False
-
- # Снимаем pre_balance на tgt_chain ДО отправки
- pre_balance = 0
- try:
- w3_tgt = rpc_resolver.get_web3(tgt_chain_id)
- pre_balance = await loop.run_in_executor(None, w3_tgt.eth.get_balance, address)
- except Exception as e:
- logger.warning("[Refuel] Could not get pre-balance on chain %s: %s", tgt_chain_id, e)
-
- try:
- tx_hash, _ = await loop.run_in_executor(
- None, sign_and_send, w3_donor, tx_req, private_key, address
- )
- except Exception as e:
- logger.warning("[Refuel] Failed to send refuel tx: %s", e)
- return False
-
- logger.info("[Refuel] Tx sent: %s — waiting for arrival on chain %s...", tx_hash, tgt_chain_id)
-
- # Ожидаем поступления
- expected_base = quoted_out_amount or actual_refuel_amount
- expected_min = max(1, int(expected_base * 0.3)) # 30% от ожидаемого output
- elapsed = 0
- while elapsed < REFUEL_TIMEOUT_SEC:
- if stop_event.is_set():
- return False
- await asyncio.sleep(POLL_INTERVAL)
- elapsed += POLL_INTERVAL
- try:
- balance = await loop.run_in_executor(None, w3_tgt.eth.get_balance, address)
- if balance - pre_balance >= expected_min:
- logger.info(
- "[Refuel] Arrived on chain %s: +%.8f ETH (after %ds)",
- tgt_chain_id, (balance - pre_balance) / 1e18, elapsed,
- )
- return True
- except Exception as e:
- logger.warning("[Refuel] Balance check error on chain %s: %s", tgt_chain_id, e)
- try:
- w3_tgt = rpc_resolver.rotate(tgt_chain_id)
- except RuntimeError:
- return False
-
- logger.warning("[Refuel] Timeout waiting for arrival on chain %s", tgt_chain_id)
- return False
-
-
-async def send_to_exchange(
- address: str,
- private_key: str,
- exchange_address: str,
- tgt_chain_id: int,
- rpc_resolver: Any,
- gas_prices: dict,
- settings: Any,
- stop_event: threading.Event,
-) -> str | None:
- """
- ШАГ 4: посекундный delay, затем ETH transfer на субаккаунт биржи.
- Возвращает tx_hash или None при ошибке/пропуске.
- """
- loop = asyncio.get_running_loop()
-
- logger.info(
- "[Wallet %s] Waiting %ds before exchange transfer...",
- address[:10], settings.delay_after_bridge
- )
- # Посекундный цикл — Stop сработает немедленно
- for _ in range(settings.delay_after_bridge):
- if stop_event.is_set():
- return None
- await asyncio.sleep(1)
-
- try:
- w3 = rpc_resolver.get_web3(tgt_chain_id)
- balance_wei = await loop.run_in_executor(None, w3.eth.get_balance, address)
-
- # Расчёт газа
- chain_gas = gas_prices.get(str(tgt_chain_id), gas_prices.get(tgt_chain_id, {}))
- gas_price_wei = chain_gas.get("fast") or chain_gas.get("standard") or 0
- if not gas_price_wei:
- gas_price_wei = await loop.run_in_executor(None, lambda: w3.eth.gas_price)
-
- tx_stub = {"from": address, "to": exchange_address, "value": balance_wei}
- estimated_gas = await loop.run_in_executor(None, w3.eth.estimate_gas, tx_stub)
- gas_cost_wei = estimated_gas * gas_price_wei
- send_amount = balance_wei - (gas_cost_wei * 2)
-
- if send_amount <= 0:
- logger.info("[Wallet %s] Balance too low for exchange transfer", address[:10])
- return None
-
- # Строим Legacy-транзакцию для простого ETH transfer
- nonce = await loop.run_in_executor(
- None, lambda: w3.eth.get_transaction_count(address, "pending")
- )
- chain_id = await loop.run_in_executor(None, lambda: w3.eth.chain_id)
- tx_req = {
- "to": exchange_address,
- "data": "0x",
- "value": hex(send_amount),
- "gasLimit": hex(estimated_gas),
- "gasPrice": hex(gas_price_wei),
- "chainId": chain_id,
- }
-
- from app.modules.token_collector._signer import sign_and_send
- tx_hash, receipt = await loop.run_in_executor(
- None, sign_and_send, w3, tx_req, private_key, address
- )
-
- if receipt is None:
- return None
-
- native_symbol = "ETH"
- logger.info(
- "[Wallet %s] Exchange transfer: %.6f %s → %s | tx: %s",
- address[:10], send_amount / 1e18, native_symbol, exchange_address, tx_hash
- )
- return tx_hash
-
- except Exception as e:
- logger.error("[Wallet %s] Exchange transfer error: %s", address[:10], e)
- return None
diff --git a/app/modules/token_collector/_collector_logic.py b/app/modules/token_collector/_collector_logic.py
deleted file mode 100644
index 6f0217a..0000000
--- a/app/modules/token_collector/_collector_logic.py
+++ /dev/null
@@ -1,736 +0,0 @@
-# app/modules/token_collector/_collector_logic.py
-from __future__ import annotations
-import asyncio
-import logging
-import random
-import threading
-import time
-from decimal import Decimal
-from typing import Any
-
-logger = logging.getLogger(__name__)
-
-
-# ── Anti-phantom corroboration (см. evm_balance_checker) ───────────────────
-# Под высокой параллельной нагрузкой DeBank ~1/30 отдаёт портфель ЧУЖОГО адреса.
-# Ответ внутренне согласован (реальные токены), поэтому одиночная выборка фантом
-# не ловит. Особенность: истинный набор токенов СТАБИЛЕН между запросами,
-# фантом — СЛУЧАЕН и не повторяется. Принимаем список только когда >=2
-# независимые выборки сходятся по суммарному total_usd; иначе — консервативно
-# (наименьший total_usd), чтобы не раздувать своп фантомными токенами. ~2 запр./кошелёк.
-COLLECTOR_CORROBORATION_MIN_AGREE = 2 # сколько согласных выборок нужно
-COLLECTOR_CORROBORATION_TOL_PCT = 0.02 # относительный допуск (2%)
-COLLECTOR_CORROBORATION_TOL_ABS = 1.0 # абсолютный допуск ($1) — для мелких балансов
-COLLECTOR_CORROBORATION_MAX_FETCHES = 5 # бюджет УСПЕШНЫХ выборок на кошелёк
-
-
-def _tokens_total_usd(tokens: Any) -> float:
- """Суммарная USD-стоимость списка токенов DeBank (price * amount)."""
- if not isinstance(tokens, list):
- return 0.0
- total = 0.0
- for t in tokens:
- try:
- total += (t.get("price", 0) or 0) * (t.get("amount", 0) or 0)
- except (TypeError, ValueError, AttributeError):
- continue
- return total
-
-
-def _values_agree(a: float, b: float) -> bool:
- """Согласованы ли два total_usd в пределах абсолютного ИЛИ относительного допуска."""
- diff = abs(a - b)
- if diff <= COLLECTOR_CORROBORATION_TOL_ABS:
- return True
- return diff <= COLLECTOR_CORROBORATION_TOL_PCT * max(abs(a), abs(b), 1.0)
-
-
-def _agreeing_cluster(snapshots: list[dict]) -> list[dict] | None:
- """Наибольший кластер согласных по total_usd выборок (размером >= MIN_AGREE).
-
- Возвращает None, пока ни один кластер не набрал нужного числа подтверждений.
- """
- best: list[dict] | None = None
- for anchor in snapshots:
- cluster = [s for s in snapshots if _values_agree(s["total_usd"], anchor["total_usd"])]
- if len(cluster) >= COLLECTOR_CORROBORATION_MIN_AGREE and (best is None or len(cluster) > len(best)):
- best = cluster
- return best
-
-
-def _representative(cluster: list[dict]) -> dict:
- """Из согласного кластера берём выборку с медианным total_usd (стабильный выбор)."""
- ordered = sorted(cluster, key=lambda s: s["total_usd"])
- return ordered[len(ordered) // 2]
-
-
-def _conservative_pick(snapshots: list[dict]) -> dict:
- """Бюджет исчерпан без согласия → наименьший total_usd (исключает раздувание фантомом)."""
- return min(snapshots, key=lambda s: s["total_usd"])
-
-
-def _get_native_addr(
- chain_id: int,
- native_token_by_id: dict[int, dict],
- relay_native_by_id: dict[int, dict],
-) -> str:
- """Возвращает адрес нативного токена сети. Приоритет: LI.FI → Relay → ""."""
- addr = (
- native_token_by_id.get(chain_id, {}).get("address")
- or relay_native_by_id.get(chain_id, {}).get("address")
- or ""
- )
- return addr
-
-
-def _resolve_contract(token: dict) -> str:
- """
- Возвращает адрес контракта токена.
- DeBank API не возвращает поле contract_address — контракт ERC-20 хранится в поле id.
- Для нативных токенов id = ключ цепи (не hex), поэтому проверяем startswith("0x").
- """
- token_id = token.get("id", "")
- explicit = token.get("contract_address", "")
- if explicit:
- return explicit.lower()
- # Если id выглядит как hex-адрес — это контракт ERC-20
- if token_id.startswith("0x"):
- return token_id.lower()
- return ""
-
-
-def _is_native_token(
- token: dict,
- chain_id: int,
- native_token_by_id: dict[int, dict],
- relay_native_by_id: dict[int, dict],
- debank_key: str = "",
-) -> bool:
- """Определяет является ли токен нативным для данной сети."""
- token_id = token.get("id", "")
- contract = _resolve_contract(token)
- zero_addr = "0x0000000000000000000000000000000000000000"
-
- # Условие 1: id совпадает с DeBank chain key (нативный — "eth", "op", "arb"...)
- if debank_key and token_id == debank_key:
- return True
-
- # Условие 2: пустой или нулевой адрес контракта — нативный токен
- if not contract or contract == zero_addr:
- return True
-
- # Условие 3: адрес из registry (для Celo, RARI и др.)
- native_addr = _get_native_addr(chain_id, native_token_by_id, relay_native_by_id)
- if native_addr and contract == native_addr.lower():
- return True
-
- return False
-
-
-def _remember_gasless_chain(
- gasless_map: dict[int, dict],
- *,
- chain_id: int,
- debank_key: str,
- eth_balance: int,
- required_wei: int,
- native_token_addr: str,
- contract: str,
- symbol: str,
- value_usd: float,
-) -> None:
- """Сохраняет цепь как кандидат на refuel и накапливает проблемные токены."""
- if chain_id not in gasless_map:
- gasless_map[chain_id] = {
- "chain_id": chain_id,
- "debank_key": debank_key,
- "eth_balance": eth_balance,
- "max_gas_needed_wei": 0,
- "native_token_addr": native_token_addr,
- "tokens": [],
- }
-
- gc = gasless_map[chain_id]
- gc["eth_balance"] = min(gc.get("eth_balance", eth_balance), eth_balance)
- gc["max_gas_needed_wei"] = max(gc["max_gas_needed_wei"], int(required_wei))
-
- known_contracts = {token["contract"] for token in gc["tokens"]}
- if contract not in known_contracts:
- gc["tokens"].append({"contract": contract, "symbol": symbol, "value_usd": value_usd})
-
-
-def _hi(v) -> int:
- """Парсит hex (0x-префикс) или decimal строку/int в int."""
- if not v:
- return 0
- if isinstance(v, str):
- return int(v, 16) if v.startswith("0x") else int(v)
- return int(v)
-
-
-async def _estimate_swap_tx_cost(
- loop: asyncio.AbstractEventLoop,
- w3: Any,
- tx_req: dict,
-) -> tuple[int, int, int, int]:
- """
- Возвращает (gas_limit, effective_gas_price, tx_value, l1_data_fee) для swap tx.
- Логика зеркалирует sign_and_send и добавляет L1 data fee для OP-stack цепей.
- """
- from app.modules.token_collector._bridge_logic import _get_l1_fee_safe
-
- gas_limit = _hi(tx_req.get("gasLimit") or tx_req.get("gas"))
- tx_value = _hi(tx_req.get("value"))
-
- if "maxFeePerGas" in tx_req:
- priority = max(1, _hi(tx_req.get("maxPriorityFeePerGas")))
- try:
- base_fee = await loop.run_in_executor(
- None, lambda: w3.eth.get_block("latest")["baseFeePerGas"]
- )
- effective_gas_price = base_fee * 11 // 10 + priority
- except Exception:
- quote_max_fee = _hi(tx_req.get("maxFeePerGas"))
- effective_gas_price = max(quote_max_fee * 2, priority)
- else:
- quote_gas_price = _hi(tx_req.get("gasPrice"))
- try:
- base_fee = await loop.run_in_executor(
- None, lambda: w3.eth.get_block("latest").get("baseFeePerGas") or 0
- )
- effective_gas_price = max(quote_gas_price, base_fee * 2) if base_fee else quote_gas_price * 2
- except Exception:
- effective_gas_price = quote_gas_price * 2 if quote_gas_price else 0
-
- l1_data_fee = await loop.run_in_executor(None, _get_l1_fee_safe, w3, tx_req)
- return gas_limit, effective_gas_price, tx_value, l1_data_fee
-
-
-async def fetch_and_swap(
- wallet: dict, # {"raw": "0x...", "type": "private_key"}
- lifi_client: Any, # LiFiClient
- debank_client: Any, # DeBankClient
- rpc_resolver: Any, # RpcResolver
- settings: Any, # CollectorSettings
- native_token_by_id: dict[int, dict],
- relay_native_by_id: dict[int, dict],
- lifi_chain_ids: set[int],
- supported_chain_ids: set[int],
- stop_event: threading.Event,
- target_chain_ids: set[int] | None = None, # исключаем таргет-цепи из total_usd
-) -> dict:
- """
- ШАГ 1-2: получить балансы DeBank, отфильтровать,
- своп не-нативных токенов в нативный через LI.FI.
- Возвращает статистику: chains_processed, chains_skipped, tokens_swapped, total_usd.
- """
- from app.integrations.lifi_client import DEBANK_TO_CHAIN_ID, LiFiNoRouteError
- from app.modules.token_collector._signer import derive_address, sign_and_send, ensure_erc20_approval, InsufficientFundsError
-
- address, private_key = derive_address(wallet["raw"], wallet["type"])
- loop = asyncio.get_running_loop()
-
- # ШАГ 1: Получить балансы с подтверждением против фантомов DeBank.
- # Принимаем список токенов только когда >=2 независимые выборки сошлись по
- # суммарному total_usd (случайный фантом почти никогда не повторяется).
- DEBANK_RETRY = 10
- snapshots: list[dict] = [] # [{"total_usd": float, "tokens": list}]
- last_exc: Exception | None = None
- attempts = 0
- max_attempts = COLLECTOR_CORROBORATION_MAX_FETCHES + DEBANK_RETRY # запас на сетевые сбои
- corroborated = False
- tokens: list[dict] = []
-
- while attempts < max_attempts and len(snapshots) < COLLECTOR_CORROBORATION_MAX_FETCHES:
- if stop_event.is_set():
- return {}
- attempts += 1
- try:
- snap_tokens = await loop.run_in_executor(None, debank_client.get_tokens, address)
- except Exception as e:
- last_exc = e
- await asyncio.sleep(3)
- continue
- snapshots.append({
- "total_usd": _tokens_total_usd(snap_tokens),
- "tokens": snap_tokens if isinstance(snap_tokens, list) else [],
- })
- cluster = _agreeing_cluster(snapshots)
- if cluster is not None:
- tokens = _representative(cluster)["tokens"]
- corroborated = True
- break
-
- if not corroborated:
- if not snapshots:
- logger.error("[%s] DeBank failed after %d attempts: %s", address[:10], attempts, last_exc)
- return {}
- tokens = _conservative_pick(snapshots)["tokens"]
- logger.warning(
- "[Wallet %s] DeBank balances NOT corroborated after %d fetches "
- "(no >=%d agreement on total_usd) — берём консервативный снимок ($%.2f); "
- "возможен фантом, своп идёт только по on-chain balanceOf",
- address[:10], len(snapshots), COLLECTOR_CORROBORATION_MIN_AGREE,
- _tokens_total_usd(tokens),
- )
-
- # Группируем по chain
- chains: dict[str, list[dict]] = {}
- for t in tokens:
- chains.setdefault(t.get("chain", ""), []).append(t)
-
- chains_processed: list[str] = []
- chains_skipped: list[str] = []
- tokens_swapped = 0
- total_usd = 0.0
- gasless_map: dict[int, dict] = {} # chain_id → {chain_id, debank_key, eth_balance, max_gas_needed_wei, native_token_addr, tokens}
-
- all_chain_keys = sorted(chains.keys())
- logger.info(
- "[Wallet %s] Fetched %d tokens across %d chains (%s)",
- address[:10], len(tokens), len(all_chain_keys), ", ".join(all_chain_keys)
- )
-
- for debank_key, chain_tokens in chains.items():
- if stop_event.is_set():
- break
-
- # Фильтр: исключённые сети
- if debank_key.lower() in (s.lower() for s in settings.excluded_chains):
- chains_skipped.append(f"{debank_key} (excluded)")
- logger.info("[Wallet %s] Skipping %s: excluded by user", address[:10], debank_key)
- continue
-
- # Фильтр: нет в маппинге
- chain_id = DEBANK_TO_CHAIN_ID.get(debank_key)
- if chain_id is None:
- chains_skipped.append(f"{debank_key} (no mapping)")
- continue
-
- # Фильтр: нет в supported_chain_ids
- if chain_id not in supported_chain_ids:
- chains_skipped.append(f"{debank_key} (not supported)")
- logger.info("[Wallet %s] Skipping %s: chain not supported by LI.FI", address[:10], debank_key)
- continue
-
- # Определяем нативный адрес для этой сети
- native_addr = _get_native_addr(chain_id, native_token_by_id, relay_native_by_id)
- if native_addr:
- native_token_addr = native_addr
- else:
- native_token_addr = "0x0000000000000000000000000000000000000000"
-
- # ШАГ 2: своп не-нативных токенов
- chain_native_usd = 0.0
- chain_skipped_dust = 0
- chain_swapped = 0
-
- for token in chain_tokens:
- if stop_event.is_set():
- break
-
- symbol = token.get("symbol", "?")
- value_usd = token.get("price", 0) * token.get("amount", 0)
-
- if value_usd < settings.min_token_usd:
- logger.info(
- "[Wallet %s] [%s] Skip %s: $%.4f < min $%.2f",
- address[:10], debank_key, symbol, value_usd, settings.min_token_usd,
- )
- chain_skipped_dust += 1
- continue
-
- if _is_native_token(token, chain_id, native_token_by_id, relay_native_by_id, debank_key):
- logger.info(
- "[Wallet %s] [%s] Native %s $%.2f — no swap needed",
- address[:10], debank_key, symbol, value_usd,
- )
- chain_native_usd += value_usd
- # Нативный ETH на source-цепях не считаем как "собранный" здесь —
- # он будет учтён как sent_usd при успешном бридже.
- continue
-
- contract = _resolve_contract(token)
- decimals = token.get("decimals", 18)
-
- # Получаем w3 и реальный on-chain баланс — DeBank-кэш может быть устаревшим
- try:
- w3 = rpc_resolver.get_web3(chain_id)
- except Exception as e:
- logger.warning("[Wallet %s] [%s] No RPC for chain %d, skipping %s: %s",
- address[:10], debank_key, chain_id, symbol, e)
- continue
-
- _ERC20_BALANCE_ABI = [{"inputs": [{"name": "account", "type": "address"}],
- "name": "balanceOf", "outputs": [{"name": "", "type": "uint256"}],
- "type": "function", "stateMutability": "view"}]
-
- async def _get_balance(w3_inst) -> int:
- tc = w3_inst.eth.contract(
- address=w3_inst.to_checksum_address(contract), abi=_ERC20_BALANCE_ABI
- )
- return await loop.run_in_executor(
- None, tc.functions.balanceOf(w3_inst.to_checksum_address(address)).call
- )
-
- try:
- from_amount = await _get_balance(w3)
- except Exception as e:
- # Пробуем следующий RPC
- try:
- w3 = rpc_resolver.rotate(chain_id)
- from_amount = await _get_balance(w3)
- except Exception as e2:
- logger.warning("[Wallet %s] [%s] balanceOf failed for %s, using DeBank amount: %s",
- address[:10], debank_key, symbol, e2)
- amount = token.get("amount", 0)
- from_amount = int(Decimal(str(amount)) * Decimal(10 ** decimals))
-
- if from_amount == 0:
- logger.info("[Wallet %s] [%s] Skip %s: on-chain balance is 0", address[:10], debank_key, symbol)
- continue
-
- logger.info("[Wallet %s] [%s] Swapping %s ($%.2f) → native", address[:10], debank_key, symbol, value_usd)
-
- gas_limit = 0
- effective_gas_price = 0
- tx_value = 0
- eth_needed = 0
- eth_balance = 0
- l1_data_fee = 0
- spender = ""
- approval_done = False
- tx_req: dict[str, Any] = {}
- APPROVE_GAS_BUFFER = 100_000
-
- try:
- # Проверяем маршрут
- connections = await loop.run_in_executor(
- None, lifi_client.get_connections, chain_id, chain_id
- )
- if not connections:
- logger.info("[Wallet %s] [%s] No swap route for %s on %s", address[:10], debank_key, symbol, debank_key)
- continue
-
- # Получаем котировку
- quote = await loop.run_in_executor(
- None,
- lifi_client.get_quote,
- chain_id, chain_id,
- contract, native_token_addr,
- from_amount, address,
- address, settings.slippage,
- )
-
- tx_req = quote["transactionRequest"]
-
- gas_limit, effective_gas_price, tx_value, l1_data_fee = await _estimate_swap_tx_cost(
- loop, w3, tx_req
- )
- # Резерв на отдельный approve tx. На OP-stack учитываем и его L1 data fee.
- approve_reserve = APPROVE_GAS_BUFFER * effective_gas_price
- if tx_req.get("to"):
- approve_reserve += l1_data_fee
- eth_needed = tx_value + gas_limit * effective_gas_price + l1_data_fee + approve_reserve
- eth_balance = await loop.run_in_executor(None, w3.eth.get_balance, address)
-
- # +10% запас на флуктуацию baseFee между предпроверкой и отправкой
- if eth_balance < int(eth_needed * 1.1):
- logger.warning(
- "[Wallet %s] [%s] Skip %s swap: ETH balance %d < needed %d "
- "(gas_limit=%d gas_price=%d l1_fee=%d approve_buf=%d value=%d)",
- address[:10], debank_key, symbol,
- eth_balance, eth_needed,
- gas_limit, effective_gas_price,
- l1_data_fee,
- APPROVE_GAS_BUFFER * effective_gas_price,
- tx_value,
- )
- _remember_gasless_chain(
- gasless_map,
- chain_id=chain_id,
- debank_key=debank_key,
- eth_balance=eth_balance,
- required_wei=int(eth_needed * 1.1),
- native_token_addr=native_token_addr,
- contract=contract,
- symbol=symbol,
- value_usd=value_usd,
- )
- continue
-
- # ERC-20 approve: даём разрешение LI.FI diamond тратить токен
- spender = tx_req.get("to", "")
- approval_done = not bool(spender)
- if spender:
- approved = await loop.run_in_executor(
- None, ensure_erc20_approval,
- w3, contract, address, spender, from_amount, private_key,
- )
- if not approved:
- logger.error(
- "[Wallet %s] [%s] Approve failed for %s, skipping swap",
- address[:10], debank_key, symbol,
- )
- continue
- approval_done = True
-
- tx_hash, receipt = await loop.run_in_executor(
- None, sign_and_send, w3, tx_req, private_key, address
- )
-
- if receipt is None:
- # Таймаут ожидания — транзакция может быть pending, не reverted
- logger.warning(
- "[Wallet %s] [%s] Swap tx pending (receipt timeout): %s",
- address[:10], debank_key, tx_hash,
- )
- continue
-
- logger.info(
- "[Wallet %s] [%s] Swap %s → native | tx: %s | confirmed in block %s",
- address[:10], debank_key, symbol, tx_hash, receipt.blockNumber
- )
- tokens_swapped += 1
- chain_swapped += 1
- total_usd += value_usd
-
- # Задержка после каждого свапа
- delay = random.randint(settings.delay_min, settings.delay_max)
- logger.info("[Wallet %s] [%s] Delay %ds after swap", address[:10], debank_key, delay)
- for _ in range(delay):
- if stop_event.is_set():
- break
- await asyncio.sleep(1)
-
- except InsufficientFundsError:
- current_balance = eth_balance
- try:
- current_balance = await loop.run_in_executor(None, w3.eth.get_balance, address)
- except Exception as balance_error:
- logger.debug(
- "[Wallet %s] [%s] Could not refresh ETH balance after insufficient funds: %s",
- address[:10], debank_key, balance_error,
- )
-
- if tx_req:
- gas_limit, effective_gas_price, tx_value, l1_data_fee = await _estimate_swap_tx_cost(
- loop, w3, tx_req
- )
-
- remaining_needed = tx_value + gas_limit * effective_gas_price + l1_data_fee
- if approval_done:
- required_wei = remaining_needed
- else:
- approve_reserve = APPROVE_GAS_BUFFER * effective_gas_price
- if spender:
- approve_reserve += l1_data_fee
- required_wei = remaining_needed + approve_reserve
-
- # Нода уже отвергла tx, значит наша локальная оценка всё ещё занижена
- # (например из-за L1 fee или роста baseFee). Делаем гарантированно
- # положительный дефицит, чтобы refuel не ушёл в отрицательное значение.
- if required_wei <= current_balance:
- shortfall_floor = max(
- l1_data_fee,
- gas_limit * max(effective_gas_price, 1) // 10,
- 1,
- )
- required_wei = current_balance + shortfall_floor
-
- if required_wei > 0:
- _remember_gasless_chain(
- gasless_map,
- chain_id=chain_id,
- debank_key=debank_key,
- eth_balance=current_balance,
- required_wei=int(required_wei * 1.1),
- native_token_addr=native_token_addr,
- contract=contract,
- symbol=symbol,
- value_usd=value_usd,
- )
- logger.warning(
- "[Wallet %s] [%s] Skip %s swap: insufficient ETH for gas (node rejected)",
- address[:10], debank_key, symbol,
- )
- except LiFiNoRouteError as e:
- logger.info("[Wallet %s] [%s] No route for %s: %s", address[:10], debank_key, symbol, e)
- except Exception as e:
- logger.error("[Wallet %s] [%s] Swap error for %s: %s", address[:10], debank_key, symbol, e)
-
- logger.info(
- "[Wallet %s] [%s] Chain summary: native=$%.2f swapped=%d dust_skipped=%d",
- address[:10], debank_key, chain_native_usd, chain_swapped, chain_skipped_dust,
- )
- chains_processed.append(debank_key)
-
- return {
- "address": address,
- "private_key": private_key,
- "chains_processed": ", ".join(chains_processed),
- "chains_skipped": ", ".join(chains_skipped),
- "tokens_swapped": tokens_swapped,
- "total_collected_usd": round(total_usd, 2),
- "gasless_chains": list(gasless_map.values()),
- }
-
-
-async def retry_gasless_swaps(
- gasless_chains: list[dict],
- address: str,
- private_key: str,
- lifi_client: Any,
- rpc_resolver: Any,
- settings: Any,
- native_token_by_id: dict[int, dict],
- relay_native_by_id: dict[int, dict],
- lifi_chain_ids: set[int],
- stop_event: threading.Event,
-) -> dict:
- """
- ШАГ 2.6: повторный своп токенов на цепях, которые были рефьюелены.
- Не вызывает DeBank — использует список токенов из gasless_chains.
- Возвращает {chains_processed, tokens_swapped, total_usd}.
- """
- from app.integrations.lifi_client import DEBANK_TO_CHAIN_ID, LiFiNoRouteError
- from app.modules.token_collector._signer import sign_and_send, ensure_erc20_approval, InsufficientFundsError
-
- loop = asyncio.get_running_loop()
- chains_processed: list[str] = []
- tokens_swapped = 0
- total_usd = 0.0
-
- _ERC20_BALANCE_ABI = [{"inputs": [{"name": "account", "type": "address"}],
- "name": "balanceOf", "outputs": [{"name": "", "type": "uint256"}],
- "type": "function", "stateMutability": "view"}]
-
- for gc in gasless_chains:
- if stop_event.is_set():
- break
-
- chain_id: int = gc["chain_id"]
- debank_key: str = gc["debank_key"]
- native_token_addr: str = gc["native_token_addr"]
-
- if chain_id not in lifi_chain_ids:
- continue
-
- try:
- w3 = rpc_resolver.get_web3(chain_id)
- except Exception as e:
- logger.warning("[Retry] No RPC for chain %s: %s", chain_id, e)
- continue
-
- chain_swapped = 0
-
- for token_info in gc.get("tokens", []):
- if stop_event.is_set():
- break
-
- contract: str = token_info["contract"]
- symbol: str = token_info["symbol"]
- value_usd: float = token_info["value_usd"]
-
- if value_usd < settings.min_token_usd:
- continue
-
- # Актуальный on-chain баланс
- try:
- tc = w3.eth.contract(
- address=w3.to_checksum_address(contract), abi=_ERC20_BALANCE_ABI
- )
- from_amount = await loop.run_in_executor(
- None, tc.functions.balanceOf(w3.to_checksum_address(address)).call
- )
- except Exception as e:
- logger.warning("[Retry] [%s] balanceOf failed for %s: %s", debank_key, symbol, e)
- continue
-
- if from_amount == 0:
- logger.info("[Retry] [%s] %s on-chain balance is 0, skipping", debank_key, symbol)
- continue
-
- logger.info("[Retry] [%s] Swapping %s ($%.2f) → native after refuel", debank_key, symbol, value_usd)
-
- try:
- connections = await loop.run_in_executor(
- None, lifi_client.get_connections, chain_id, chain_id
- )
- if not connections:
- continue
-
- quote = await loop.run_in_executor(
- None, lifi_client.get_quote,
- chain_id, chain_id,
- contract, native_token_addr,
- from_amount, address, address, settings.slippage,
- )
- tx_req = quote["transactionRequest"]
-
- # Простая проверка газа
- def _hi(v) -> int:
- if not v:
- return 0
- if isinstance(v, str):
- return int(v, 16) if v.startswith("0x") else int(v)
- return int(v)
-
- gas_limit = _hi(tx_req.get("gasLimit") or tx_req.get("gas"))
- gas_price = _hi(tx_req.get("maxFeePerGas") or tx_req.get("gasPrice") or 0)
- tx_value = _hi(tx_req.get("value"))
- eth_needed = tx_value + gas_limit * gas_price * 2
- eth_balance = await loop.run_in_executor(None, w3.eth.get_balance, address)
-
- if eth_balance < eth_needed:
- logger.warning(
- "[Retry] [%s] Still not enough ETH for %s: have %d need %d",
- debank_key, symbol, eth_balance, eth_needed,
- )
- continue
-
- spender = tx_req.get("to", "")
- if spender:
- approved = await loop.run_in_executor(
- None, ensure_erc20_approval,
- w3, contract, address, spender, from_amount, private_key,
- )
- if not approved:
- continue
-
- tx_hash, receipt = await loop.run_in_executor(
- None, sign_and_send, w3, tx_req, private_key, address
- )
- if receipt is None:
- continue
-
- logger.info(
- "[Retry] [%s] Swap %s → native | tx: %s | block %s",
- debank_key, symbol, tx_hash, receipt.blockNumber,
- )
- tokens_swapped += 1
- chain_swapped += 1
- total_usd += value_usd
-
- delay = random.randint(settings.delay_min, settings.delay_max)
- for _ in range(delay):
- if stop_event.is_set():
- break
- await asyncio.sleep(1)
-
- except InsufficientFundsError:
- logger.warning("[Retry] [%s] Insufficient ETH for %s swap (node rejected)", debank_key, symbol)
- except LiFiNoRouteError as e:
- logger.info("[Retry] [%s] No route for %s: %s", debank_key, symbol, e)
- except Exception as e:
- logger.error("[Retry] [%s] Swap error for %s: %s", debank_key, symbol, e)
-
- if chain_swapped > 0:
- chains_processed.append(debank_key)
- logger.info("[Retry] [%s] Swapped %d tokens after refuel", debank_key, chain_swapped)
-
- return {
- "chains_processed": ", ".join(chains_processed),
- "tokens_swapped": tokens_swapped,
- "total_usd": round(total_usd, 2),
- }
diff --git a/app/modules/token_collector/_signer.py b/app/modules/token_collector/_signer.py
deleted file mode 100644
index d0cd341..0000000
--- a/app/modules/token_collector/_signer.py
+++ /dev/null
@@ -1,220 +0,0 @@
-# app/modules/token_collector/_signer.py
-from __future__ import annotations
-import logging
-from typing import Any
-
-from eth_account import Account
-from web3 import Web3
-
-logger = logging.getLogger(__name__)
-
-# BIP44 деривационный путь для Ethereum
-BIP44_PATH = "m/44'/60'/0'/0/0"
-
-
-class TransactionReverted(RuntimeError):
- """Транзакция отправлена и подтверждена, но reverted (status=0)."""
- def __init__(self, tx_hash: str) -> None:
- super().__init__(tx_hash)
- self.tx_hash = tx_hash
-
-
-class InsufficientFundsError(ValueError):
- """Нода отклонила транзакцию: недостаточно ETH для gas * price + value."""
-
-_ERC20_ABI = [
- {
- "inputs": [{"name": "owner", "type": "address"}, {"name": "spender", "type": "address"}],
- "name": "allowance",
- "outputs": [{"name": "", "type": "uint256"}],
- "type": "function",
- "stateMutability": "view",
- },
- {
- "inputs": [{"name": "spender", "type": "address"}, {"name": "amount", "type": "uint256"}],
- "name": "approve",
- "outputs": [{"name": "", "type": "bool"}],
- "type": "function",
- "stateMutability": "nonpayable",
- },
-]
-_MAX_UINT256 = 2 ** 256 - 1
-
-
-def ensure_erc20_approval(
- w3: Web3,
- token_address: str,
- owner: str,
- spender: str,
- amount: int,
- private_key: str,
-) -> bool:
- """
- Проверяет allowance ERC-20 и при необходимости отправляет approve(spender, MAX_UINT256).
- Возвращает True если allowance достаточен или approve прошёл успешно.
- """
- token = w3.eth.contract(
- address=Web3.to_checksum_address(token_address),
- abi=_ERC20_ABI,
- )
- allowance = token.functions.allowance(
- Web3.to_checksum_address(owner),
- Web3.to_checksum_address(spender),
- ).call()
-
- if allowance >= amount:
- return True
-
- logger.info("Approving %s → spender %s...", token_address[:10], spender[:10])
-
- nonce = w3.eth.get_transaction_count(Web3.to_checksum_address(owner), "pending")
- try:
- base_fee = w3.eth.get_block("latest")["baseFeePerGas"]
- tx = token.functions.approve(
- Web3.to_checksum_address(spender), _MAX_UINT256
- ).build_transaction({
- "from": Web3.to_checksum_address(owner),
- "nonce": nonce,
- "maxFeePerGas": base_fee * 11 // 10,
- "maxPriorityFeePerGas": 1, # минимум 1 wei — некоторые RPC отклоняют 0
- })
- except Exception:
- tx = token.functions.approve(
- Web3.to_checksum_address(spender), _MAX_UINT256
- ).build_transaction({
- "from": Web3.to_checksum_address(owner),
- "nonce": nonce,
- "gasPrice": w3.eth.gas_price * 2,
- })
-
- signed = w3.eth.account.sign_transaction(tx, private_key)
- try:
- tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
- except Exception as e:
- if "insufficient funds" in str(e).lower():
- raise InsufficientFundsError(str(e))
- raise
-
- try:
- receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=60)
- except Exception as e:
- logger.warning("Approve receipt timeout for %s: %s", tx_hash.hex(), e)
- return True # tx отправлена — считаем что одобрено, swap попробует сам
-
- if receipt.status == 0:
- logger.error("Approve reverted: %s", tx_hash.hex())
- return False
-
- logger.info("Approve confirmed: %s", tx_hash.hex())
- return True
-
-
-def derive_address(wallet_raw: str, wallet_type: str) -> tuple[str, str]:
- """
- Возвращает (address, private_key_hex).
- wallet_type: "private_key" | "mnemonic"
- Бросает ValueError для неизвестного типа.
- """
- if wallet_type == "private_key":
- acct = Account.from_key(wallet_raw)
- return acct.address, wallet_raw
- elif wallet_type == "mnemonic":
- Account.enable_unaudited_hdwallet_features()
- acct = Account.from_mnemonic(wallet_raw, account_path=BIP44_PATH)
- return acct.address, acct.key.hex()
- else:
- raise ValueError(f"Неизвестный тип кошелька: {wallet_type}")
-
-
-def sign_and_send(
- w3: Web3,
- tx_req: dict,
- private_key: str,
- address: str,
-) -> tuple[str, Any] | tuple[str, None]:
- """
- Подписывает и отправляет транзакцию. Возвращает (tx_hash_hex, receipt).
- Если receipt.status == 0 (reverted) — логирует и возвращает (tx_hash_hex, None).
- """
- nonce = w3.eth.get_transaction_count(address, "pending")
-
- def _parse(v) -> int:
- """Парсит hex (0x-префикс) или decimal строку/int в int."""
- if isinstance(v, str):
- return int(v, 16) if v.startswith("0x") else int(v)
- return int(v)
-
- # EIP-1559 (если есть maxFeePerGas)
- if "maxFeePerGas" in tx_req:
- tx = {
- "from": address,
- "to": Web3.to_checksum_address(tx_req["to"]),
- "data": tx_req.get("data", "0x"),
- "value": _parse(tx_req["value"]),
- "gas": _parse(tx_req.get("gasLimit") or tx_req.get("gas")),
- "maxFeePerGas": _parse(tx_req["maxFeePerGas"]),
- "maxPriorityFeePerGas": _parse(tx_req["maxPriorityFeePerGas"]),
- "nonce": nonce,
- "chainId": _parse(tx_req["chainId"]),
- }
- # Берём актуальный baseFee из сети и ставим maxFeePerGas = baseFee×2 + priority.
- # На L2 (OP, ARB, Base) LI.FI выставляет priority=0 — это нормально, sequencer не требует чаевых.
- # НЕ форсируем минимум 1 gwei: 0 or 1e9 завышает газ в 100–1000x на L2.
- try:
- base_fee = w3.eth.get_block("latest")["baseFeePerGas"]
- # max(1, ...) — некоторые RPC (publicnode/OP и др.) отклоняют tip=0
- priority = max(1, tx["maxPriorityFeePerGas"])
- tx["maxPriorityFeePerGas"] = priority
- tx["maxFeePerGas"] = base_fee * 11 // 10 + priority
- logger.info("maxFeePerGas set to %d (baseFee=%d priority=%d)", tx["maxFeePerGas"], base_fee, priority)
- except Exception:
- tx["maxFeePerGas"] = int(tx["maxFeePerGas"] * 2)
- else:
- # Legacy
- tx = {
- "from": address,
- "to": Web3.to_checksum_address(tx_req["to"]),
- "data": tx_req.get("data", "0x"),
- "value": _parse(tx_req["value"]),
- "gas": _parse(tx_req.get("gasLimit") or tx_req.get("gas")),
- "gasPrice": _parse(tx_req["gasPrice"]),
- "nonce": nonce,
- "chainId": _parse(tx_req["chainId"]),
- }
- # Бампаем gasPrice на случай роста baseFee
- try:
- base_fee = w3.eth.get_block("latest").get("baseFeePerGas") or 0
- if base_fee:
- tx["gasPrice"] = max(tx["gasPrice"], base_fee * 2)
- else:
- tx["gasPrice"] = int(tx["gasPrice"] * 2)
- except Exception:
- tx["gasPrice"] = int(tx["gasPrice"] * 2)
-
- for _attempt in range(3):
- signed = w3.eth.account.sign_transaction(tx, private_key)
- try:
- tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
- break
- except Exception as e:
- e_str = str(e)
- if "nonce too low" in e_str and _attempt < 2:
- tx["nonce"] = w3.eth.get_transaction_count(address, "latest")
- logger.warning("Nonce too low, retrying with nonce=%d (attempt %d)", tx["nonce"], _attempt + 2)
- continue
- if "insufficient funds" in e_str.lower():
- raise InsufficientFundsError(e_str)
- raise
- tx_hash_hex = "0x" + tx_hash.hex()
-
- try:
- receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=60)
- except Exception as e:
- logger.warning("Receipt fetch failed for %s (%s), will rely on bridge poller", tx_hash_hex, e)
- return tx_hash_hex, None
-
- if receipt.status == 0:
- logger.error("Транзакция reverted: %s", tx_hash_hex)
- raise TransactionReverted(tx_hash_hex)
-
- return tx_hash_hex, receipt
diff --git a/app/modules/twitter_checker/__init__.py b/app/modules/twitter_checker/__init__.py
deleted file mode 100644
index 4d4565d..0000000
--- a/app/modules/twitter_checker/__init__.py
+++ /dev/null
@@ -1,147 +0,0 @@
-from __future__ import annotations
-import asyncio
-import threading
-from typing import AsyncIterator
-
-from PySide6.QtCore import QObject, Signal
-from PySide6.QtWidgets import QWidget
-
-from app.core.base_module import BaseModule
-from app.core.models import RunContext, Result, ResultStatus, ColumnDef
-from app.integrations.proxy_utils import ProxyRotator
-from app.integrations.twitter_client import (
- TwitterClient,
- TwitterTokenStatus,
-)
-
-RETRY_ATTEMPTS = 3
-
-
-def _check_token_sync(
- token: str,
- rotator: ProxyRotator,
- stop_event: threading.Event,
-) -> Result:
- """Module-level sync function for run_in_executor. Checks one auth_token."""
- last_error: str = "Unknown error"
-
- for _ in range(RETRY_ATTEMPTS):
- if stop_event.is_set():
- return Result(
- item=token,
- status=ResultStatus.ERROR,
- error="Stopped",
- data={"username": None, "account_status": "error"},
- )
-
- proxy = rotator.next()
- if proxy is None:
- return Result(
- item=token,
- status=ResultStatus.ERROR,
- error="No proxies available",
- data={"username": None, "account_status": "error"},
- )
-
- try:
- r = TwitterClient(proxy.to_url()).check_token(token)
-
- if r.status == TwitterTokenStatus.OK:
- return Result(
- item=token,
- status=ResultStatus.OK,
- data={"username": r.username, "account_status": "ok"},
- )
-
- if r.status in (
- TwitterTokenStatus.INVALID,
- TwitterTokenStatus.SUSPENDED,
- TwitterTokenStatus.LOCKED,
- ):
- # Definitive answer — do not retry
- return Result(
- item=token,
- status=ResultStatus.SKIP,
- error=r.status.value,
- data={"username": None, "account_status": r.status.value},
- )
-
- last_error = "API error"
- except Exception as e:
- last_error = str(e)
-
- return Result(
- item=token,
- status=ResultStatus.ERROR,
- error=last_error,
- data={"username": None, "account_status": "error"},
- )
-
-
-class _TwitterSignals(QObject):
- # Created in __init__ (main thread) for correct Qt thread affinity
- run_complete = Signal(list) # list[Result]
-
-
-class TwitterCheckerModule(BaseModule):
- name = "Twitter Checker"
-
- def column_schema(self) -> list[ColumnDef]:
- return [
- ColumnDef(key="item", label="Token", width=200),
- ColumnDef(key="account_status", label="Status"),
- ColumnDef(key="username", label="Username"),
- ]
-
- def __init__(self) -> None:
- from app.ui.module_views.twitter_checker_view import TwitterCheckerConfigWidget
- self._signals = _TwitterSignals()
- self._results: list[Result] = []
- self._widget = TwitterCheckerConfigWidget()
- self._signals.run_complete.connect(self._widget.on_run_complete)
- self._stop_event = threading.Event()
-
- def get_config_widget(self) -> QWidget:
- return self._widget
-
- def get_item_count(self) -> int:
- return len(self._widget.get_tokens())
-
- async def run(self, ctx: RunContext) -> AsyncIterator[Result]:
- self._results.clear()
- self._stop_event.clear()
-
- tokens = self._widget.get_tokens()
- proxies = self._widget.get_proxies()
- rotator = ProxyRotator(proxies)
- semaphore = asyncio.Semaphore(ctx.concurrency)
- loop = asyncio.get_running_loop()
-
- async def _indexed_check(idx: int, token: str) -> tuple[int, Result]:
- async with semaphore:
- result = await loop.run_in_executor(
- None, _check_token_sync, token, rotator, self._stop_event
- )
- return idx, result
-
- tasks = [asyncio.create_task(_indexed_check(i, t)) for i, t in enumerate(tokens)]
- buffer: dict[int, Result] = {}
- next_idx = 0
- try:
- for fut in asyncio.as_completed(tasks):
- if self._stop_event.is_set():
- for t in tasks:
- t.cancel()
- break
- idx, result = await fut
- buffer[idx] = result
- while next_idx in buffer:
- r = buffer.pop(next_idx)
- self._results.append(r)
- yield r
- next_idx += 1
- finally:
- self._signals.run_complete.emit(list(self._results))
-
- async def stop(self) -> None:
- self._stop_event.set()
diff --git a/app/resources/.gitkeep b/app/resources/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/app/resources/config.yaml b/app/resources/config.yaml
deleted file mode 100644
index 91591bc..0000000
--- a/app/resources/config.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
-concurrency: 10
-language: ru
-log_level: INFO
-retry_attempts: 3
-retry_backoff: 2.0
-rpc_evm_default:
-- https://eth.llamarpc.com
-- https://bsc-dataseed.binance.org
-rpc_solana_default:
-- https://api.mainnet-beta.solana.com
-timeout: 30
diff --git a/app/resources/icon.png b/app/resources/icon.png
deleted file mode 100644
index 887edcc..0000000
Binary files a/app/resources/icon.png and /dev/null differ
diff --git a/app/resources/translations/__init__.py b/app/resources/translations/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/app/resources/translations/en.py b/app/resources/translations/en.py
deleted file mode 100644
index 00296a7..0000000
--- a/app/resources/translations/en.py
+++ /dev/null
@@ -1,127 +0,0 @@
-TRANSLATIONS: dict[str, str] = {
- # Toolbar
- "start_btn": "▶ Start",
- "stop_btn": "■ Stop",
- "faq_btn": "FAQ",
-
- # File inputs
- "wallets_label": "Wallets:",
- "proxy_label": "Proxy: ",
- "tokens_label_input": "Tokens: ",
- "browse_btn": "Browse",
- "file_not_loaded": "File not loaded",
- "n_addresses_loaded": "✓ {n} addresses loaded",
- "n_wallets_loaded": "✓ {n} wallets loaded",
- "n_proxies_loaded": "✓ {n} proxies loaded",
- "n_tokens_loaded": "✓ {n} tokens loaded",
- "error_fmt": "Error: {e}",
-
- # Files header (collector)
- "files_header": "Files",
-
- # Export group
- "export_group": "Export",
- "tokens_checkbox": "Tokens",
- "tokens_filter_label": "Tokens:",
- "filter_all": "All",
- "export_btn": "💾 Export",
-
- # Export dialogs
- "save_csv": "Save CSV",
- "save_json": "Save JSON",
- "save_xlsx": "Save XLSX",
- "save_error_title": "Save Error",
- "save_error_msg": "Could not save file:\n{path}\n\nClose the file if it is open in Excel.",
-
- # Filter group (collector)
- "filters_group": "Filters",
- "min_value_label": "Min. token value ($):",
- "exclude_chains_label": "Exclude chains:",
- "slippage_label": "Slippage (%):",
-
- # Bridge group (collector)
- "bridge_group": "Bridge",
- "target_chains_label": "Target chains:",
-
- # Delays group (collector)
- "delays_group": "Delays",
- "delay_between_wallets_label": "Between wallets (sec):",
-
- # Exchange group (collector)
- "exchange_group": "Exchange Subaccount",
- "send_to_exchange_checkbox": "Send to exchange subaccount",
- "subaccounts_label": "Subaccounts:",
- "after_bridge_delay_label": "Delay after bridge (sec):",
- "wallets_subaccounts_mismatch": "⚠ Wallets: {w}, subaccounts: {s}",
- "n_subaccounts_loaded": "✓ {s} subaccounts loaded",
-
- # Twitter/Discord checker
- "status_label": "Status:",
- "format_label": "Format:",
- "proxy_label_checker": "Proxy: ",
- "tokens_label_checker": "Tokens: ",
-
- # Results table
- "search_placeholder": "Search...",
- "total_fmt": "Total: ${total:,.2f}",
- "export_csv_btn": "Export CSV",
- "export_json_btn": "Export JSON",
- "export_xlsx_btn": "Export XLSX",
-
- # Log widget
- "clear_log_btn": "Clear log",
-
- # File dialogs
- "select_wallets_file": "Select wallets file",
- "select_proxy_file": "Select proxy file",
- "select_subaccounts_file": "Select subaccounts file",
- "select_tokens_file": "Select tokens file",
-
- # RPC
- "rpc_url_label": "RPC URL:",
-
- # Chain picker
- "pick_chains_placeholder": "select chains...",
- "chain_search_placeholder": "Search…",
-
- # Placeholder view
- "placeholder_module_msg": "Module: {module_name}\n\nSettings will be added in the next iteration.",
-
- # SVM token filter
- "all_tokens": "All",
- "empty_results_title": "No results yet",
- "empty_results_subtitle": "Load a file and press Start to begin",
- "empty_log_title": "Log is empty",
- "empty_log_subtitle": "Activity will appear here during execution",
-
- # Drop zone
- "drop_hint": "Drop file here or click Browse",
- "select_file": "Select file",
-
- # Collector tooltips
- "min_value_tooltip": "Tokens below this USD value will be skipped",
- "slippage_tooltip": "Maximum allowed price slippage for swaps",
- "delay_min_tooltip": "Minimum delay between processing wallets",
- "delay_max_tooltip": "Maximum delay between processing wallets",
- "after_bridge_delay_tooltip": "Wait time after bridge before next operation",
- "min_bridge_tooltip": "Skip bridge if balance is below this USD value",
-
- # Sidebar
- "sidebar_collapse_tooltip": "Collapse sidebar",
- "sidebar_expand_tooltip": "Expand sidebar",
-
- "freeze_log_tooltip": "Freeze log (pause auto-scroll)",
-
- "toast_finished_ok": "✓ Completed successfully",
- "toast_finished_errors": "⚠ Completed with errors",
-
- # Validation
- "validation_no_wallets": "Load wallets file first",
- "validation_no_proxies": "Load proxies file first",
- "validation_no_tokens": "Load tokens file first",
- "validation_no_items": "Load input file first",
-
- # Log collapse
- "log_expand_btn": "▲ Log",
- "log_collapse_btn": "▼ Log",
-}
diff --git a/app/resources/translations/ru.py b/app/resources/translations/ru.py
deleted file mode 100644
index 6f17bad..0000000
--- a/app/resources/translations/ru.py
+++ /dev/null
@@ -1,127 +0,0 @@
-TRANSLATIONS: dict[str, str] = {
- # Toolbar
- "start_btn": "▶ Старт",
- "stop_btn": "■ Стоп",
- "faq_btn": "FAQ",
-
- # File inputs
- "wallets_label": "Кошельки:",
- "proxy_label": "Прокси: ",
- "tokens_label_input": "Токены: ",
- "browse_btn": "Обзор",
- "file_not_loaded": "Файл не загружен",
- "n_addresses_loaded": "✓ {n} адресов загружено",
- "n_wallets_loaded": "✓ {n} кошельков загружено",
- "n_proxies_loaded": "✓ {n} прокси загружено",
- "n_tokens_loaded": "✓ {n} токенов загружено",
- "error_fmt": "Ошибка: {e}",
-
- # Files header (collector)
- "files_header": "Файлы",
-
- # Export group
- "export_group": "Экспорт",
- "tokens_checkbox": "Токены",
- "tokens_filter_label": "Токены:",
- "filter_all": "Все",
- "export_btn": "💾 Экспорт",
-
- # Export dialogs
- "save_csv": "Сохранить CSV",
- "save_json": "Сохранить JSON",
- "save_xlsx": "Сохранить XLSX",
- "save_error_title": "Ошибка сохранения",
- "save_error_msg": "Не удалось сохранить файл:\n{path}\n\nЗакройте файл если он открыт в Excel.",
-
- # Filter group (collector)
- "filters_group": "Фильтры",
- "min_value_label": "Мин. стоимость токена ($):",
- "exclude_chains_label": "Исключить сети:",
- "slippage_label": "Slippage (%):",
-
- # Bridge group (collector)
- "bridge_group": "Бридж",
- "target_chains_label": "Целевые сети:",
-
- # Delays group (collector)
- "delays_group": "Задержки",
- "delay_between_wallets_label": "Между кошельками (сек):",
-
- # Exchange group (collector)
- "exchange_group": "Субаккаунт биржи",
- "send_to_exchange_checkbox": "Отправить на субаккаунт биржи",
- "subaccounts_label": "Субаккаунты:",
- "after_bridge_delay_label": "Задержка после бриджа (сек):",
- "wallets_subaccounts_mismatch": "⚠ Кошельков: {w}, субаккаунтов: {s}",
- "n_subaccounts_loaded": "✓ {s} субаккаунтов загружено",
-
- # Twitter/Discord checker
- "status_label": "Статус:",
- "format_label": "Формат:",
- "proxy_label_checker": "Прокси: ",
- "tokens_label_checker": "Токены: ",
-
- # Results table
- "search_placeholder": "Поиск...",
- "total_fmt": "Итого: ${total:,.2f}",
- "export_csv_btn": "Экспорт CSV",
- "export_json_btn": "Экспорт JSON",
- "export_xlsx_btn": "Экспорт XLSX",
-
- # Log widget
- "clear_log_btn": "Очистить лог",
-
- # File dialogs
- "select_wallets_file": "Выбрать файл кошельков",
- "select_proxy_file": "Выбрать файл прокси",
- "select_subaccounts_file": "Выбрать файл субаккаунтов",
- "select_tokens_file": "Выбрать файл токенов",
-
- # RPC
- "rpc_url_label": "RPC URL:",
-
- # Chain picker
- "pick_chains_placeholder": "выберите сети...",
- "chain_search_placeholder": "Поиск…",
-
- # Placeholder view
- "placeholder_module_msg": "Модуль: {module_name}\n\nНастройки будут добавлены в следующей итерации.",
-
- # SVM token filter
- "all_tokens": "Все",
- "empty_results_title": "Результатов пока нет",
- "empty_results_subtitle": "Загрузите файл и нажмите Старт",
- "empty_log_title": "Лог пуст",
- "empty_log_subtitle": "Активность появится здесь во время выполнения",
-
- # Drop zone
- "drop_hint": "Перетащите файл сюда или нажмите Обзор",
- "select_file": "Выбрать файл",
-
- # Collector tooltips
- "min_value_tooltip": "Токены дешевле этой суммы в USD будут пропущены",
- "slippage_tooltip": "Максимально допустимое проскальзывание цены при свапе",
- "delay_min_tooltip": "Минимальная задержка между обработкой кошельков",
- "delay_max_tooltip": "Максимальная задержка между обработкой кошельков",
- "after_bridge_delay_tooltip": "Время ожидания после бриджа перед следующей операцией",
- "min_bridge_tooltip": "Пропустить бридж если баланс ниже этой суммы в USD",
-
- # Sidebar
- "sidebar_collapse_tooltip": "Свернуть панель",
- "sidebar_expand_tooltip": "Развернуть панель",
-
- "freeze_log_tooltip": "Заморозить лог (пауза авто-прокрутки)",
-
- "toast_finished_ok": "✓ Выполнено успешно",
- "toast_finished_errors": "⚠ Выполнено с ошибками",
-
- # Validation
- "validation_no_wallets": "Сначала загрузите файл кошельков",
- "validation_no_proxies": "Сначала загрузите файл прокси",
- "validation_no_tokens": "Сначала загрузите файл токенов",
- "validation_no_items": "Сначала загрузите входной файл",
-
- # Log collapse
- "log_expand_btn": "▲ Лог",
- "log_collapse_btn": "▼ Лог",
-}
diff --git a/app/storage/__init__.py b/app/storage/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/app/storage/discord_exporter.py b/app/storage/discord_exporter.py
deleted file mode 100644
index 6fcbdc0..0000000
--- a/app/storage/discord_exporter.py
+++ /dev/null
@@ -1,71 +0,0 @@
-from __future__ import annotations
-import csv
-import json
-from dataclasses import dataclass
-
-import openpyxl
-
-from app.core.models import Result
-
-
-@dataclass
-class DiscordExportConfig:
- status_filter: str | None = None # None = all; "ok"/"invalid"/"disabled"
-
-
-class DiscordExporter:
- _COLUMNS = ["token", "username", "email", "has_phone", "account_status"]
-
- def build(
- self,
- results: list[Result],
- config: DiscordExportConfig,
- ) -> list[dict]:
- rows = []
- for r in results:
- account_status = r.data.get("account_status", "")
- if config.status_filter and account_status != config.status_filter:
- continue
- rows.append({
- "token": r.item,
- "username": r.data.get("username") or "",
- "email": r.data.get("email") or "",
- "has_phone": "yes" if r.data.get("has_phone") else "no",
- "account_status": account_status,
- })
- return rows
-
- def export(
- self,
- results: list[Result],
- config: DiscordExportConfig,
- path: str,
- fmt: str,
- ) -> None:
- rows = self.build(results, config)
- if fmt == "csv":
- self._export_csv(rows, path)
- elif fmt == "json":
- self._export_json(rows, path)
- else:
- self._export_xlsx(rows, path)
-
- def _export_csv(self, rows: list[dict], path: str) -> None:
- with open(path, "w", newline="", encoding="utf-8") as f:
- writer = csv.DictWriter(f, fieldnames=self._COLUMNS)
- writer.writeheader()
- writer.writerows(rows)
-
- def _export_json(self, rows: list[dict], path: str) -> None:
- json_rows = [{**row, "has_phone": row["has_phone"] == "yes"} for row in rows]
- with open(path, "w", encoding="utf-8") as f:
- json.dump(json_rows, f, ensure_ascii=False, indent=2)
-
- def _export_xlsx(self, rows: list[dict], path: str) -> None:
- wb = openpyxl.Workbook()
- ws = wb.active
- ws.title = "Results"
- ws.append(self._COLUMNS)
- for row in rows:
- ws.append([row.get(c, "") for c in self._COLUMNS])
- wb.save(path)
diff --git a/app/storage/evm_exporter.py b/app/storage/evm_exporter.py
deleted file mode 100644
index d4819c5..0000000
--- a/app/storage/evm_exporter.py
+++ /dev/null
@@ -1,157 +0,0 @@
-from __future__ import annotations
-import csv
-import json
-from dataclasses import dataclass
-from pathlib import Path
-
-import openpyxl
-
-from app.core.models import Result
-
-
-@dataclass
-class EvmExportConfig:
- summary: bool = True
- tokens: bool = True
- token_filter: str | None = None
-
-
-def _parse_filter(f: str | None) -> tuple[str, str] | None:
- """
- Разбирает фильтр "name:chain" по первому ':'.
- Возвращает (name_part, chain_part) или None если фильтр отключён.
- None/"" → None. Строка без ':' → None (фильтр отключён).
- """
- if not f:
- return None
- if ":" not in f:
- return None # без ':' фильтр не работает
- idx = f.index(":")
- return f[:idx].strip(), f[idx + 1:].strip()
-
-
-def _match_token(t: dict, flt: tuple[str, str] | None) -> bool:
- if flt is None:
- return True
- name_part, chain_part = flt
- if name_part and (t.get("symbol") or "").upper() != name_part.upper():
- return False
- if chain_part and (t.get("chain") or "").lower() != chain_part.lower():
- return False
- return True
-
-
-class EvmExporter:
- """Строит и экспортирует данные EVM Balance по конфигурации."""
-
- def build(
- self,
- results: list[Result],
- details: dict[str, dict],
- config: EvmExportConfig,
- ) -> dict[str, list[dict]]:
- tok_flt = _parse_filter(config.token_filter)
- data: dict[str, list[dict]] = {"summary": [], "tokens": []}
-
- for r in results:
- if config.summary:
- data["summary"].append({
- "address": r.item,
- "total_usd": r.data.get("total_usd", ""),
- "tokens_usd": r.data.get("tokens_usd", ""),
- "tokens": r.data.get("tokens", ""),
- "chains": r.data.get("chains", ""),
- "status": r.status.value,
- })
-
- if r.status.value != "ok":
- continue
-
- detail = details.get(r.item, {})
- if config.tokens:
- for t in detail.get("tokens_data", []):
- if _match_token(t, tok_flt):
- data["tokens"].append({
- "address": r.item,
- "symbol": t.get("symbol", ""),
- "chain": t.get("chain", ""),
- "amount": t.get("amount", 0),
- "price": t.get("price", 0),
- "value": t.get("value", 0),
- })
-
- return data
-
- def export(
- self,
- results: list[Result],
- details: dict[str, dict],
- config: EvmExportConfig,
- path: str,
- fmt: str,
- ) -> None:
- data = self.build(results, details, config)
- if fmt == "csv":
- self._export_csv(data, config, path)
- elif fmt == "json":
- self._export_json(data, path)
- else:
- self._export_xlsx(data, config, path)
-
- # --- CSV ---
-
- _SECTION_COLUMNS = {
- "summary": ["address", "total_usd", "tokens_usd", "tokens", "chains", "status"],
- "tokens": ["address", "symbol", "chain", "amount", "price", "value"],
- }
- _SECTION_LABELS = {
- "summary": "Summary",
- "tokens": "Tokens",
- }
- _SECTION_FLAGS = {
- "summary": "summary",
- "tokens": "tokens",
- }
-
- def _active_sections(self, config: EvmExportConfig) -> list[str]:
- return [k for k in ("summary", "tokens") if getattr(config, self._SECTION_FLAGS[k])]
-
- def _export_csv(self, data: dict, config: EvmExportConfig, path: str) -> None:
- active = self._active_sections(config)
- with open(path, "w", newline="", encoding="utf-8") as f:
- writer = csv.writer(f)
- for i, section in enumerate(active):
- if i > 0:
- writer.writerow([]) # пустая строка-разделитель
- writer.writerow([f"=== {self._SECTION_LABELS[section]} ==="])
- cols = self._SECTION_COLUMNS[section]
- writer.writerow(cols)
- for row in data[section]:
- writer.writerow([row.get(c, "") for c in cols])
-
- # --- JSON ---
-
- def _export_json(self, data: dict, path: str) -> None:
- with open(path, "w", encoding="utf-8") as f:
- json.dump(data, f, ensure_ascii=False, indent=2)
-
- # --- XLSX ---
-
- def _export_xlsx(self, data: dict, config: EvmExportConfig, path: str) -> None:
- active = self._active_sections(config)
- wb = openpyxl.Workbook()
- wb.remove(wb.active) # удаляем дефолтный лист
-
- if not active:
- ws = wb.create_sheet("Summary")
- ws.append(self._SECTION_COLUMNS["summary"])
- else:
- sheet_names = {"summary": "Summary", "tokens": "Tokens"}
- for section in active:
- ws = wb.create_sheet(sheet_names[section])
- cols = self._SECTION_COLUMNS[section]
- ws.append(cols)
- for row in data[section]:
- ws.append([row.get(c, "") for c in cols])
-
- wb.save(path)
diff --git a/app/storage/exporters.py b/app/storage/exporters.py
deleted file mode 100644
index 9904548..0000000
--- a/app/storage/exporters.py
+++ /dev/null
@@ -1,61 +0,0 @@
-from __future__ import annotations
-import csv
-import json
-from abc import ABC, abstractmethod
-from pathlib import Path
-import openpyxl
-from app.core.models import Result
-
-
-def get_columns(results: list[Result]) -> list[str]:
- """Определяет колонки из первого непустого result.data. Fallback: item, status."""
- for r in results:
- if r.data:
- base = ["item", "status"]
- extra = [k for k in r.data.keys() if k not in base]
- return base + extra
- return ["item", "status"]
-
-
-def _result_to_row(result: Result, columns: list[str]) -> dict:
- row = {
- "item": result.item,
- "status": result.status.value,
- }
- row.update(result.data)
- return {col: row.get(col, "") for col in columns}
-
-
-class BaseExporter(ABC):
- @abstractmethod
- def export(self, results: list[Result], path: str) -> None: ...
-
-
-class CsvExporter(BaseExporter):
- def export(self, results: list[Result], path: str) -> None:
- columns = get_columns(results)
- with open(path, "w", newline="", encoding="utf-8") as f:
- writer = csv.DictWriter(f, fieldnames=columns)
- writer.writeheader()
- for r in results:
- writer.writerow(_result_to_row(r, columns))
-
-
-class JsonExporter(BaseExporter):
- def export(self, results: list[Result], path: str) -> None:
- columns = get_columns(results)
- rows = [_result_to_row(r, columns) for r in results]
- with open(path, "w", encoding="utf-8") as f:
- json.dump(rows, f, ensure_ascii=False, indent=2)
-
-
-class XlsxExporter(BaseExporter):
- def export(self, results: list[Result], path: str) -> None:
- columns = get_columns(results)
- wb = openpyxl.Workbook()
- ws = wb.active
- ws.append(columns)
- for r in results:
- row = _result_to_row(r, columns)
- ws.append([row.get(col, "") for col in columns])
- wb.save(path)
diff --git a/app/storage/parsers.py b/app/storage/parsers.py
deleted file mode 100644
index db0fae7..0000000
--- a/app/storage/parsers.py
+++ /dev/null
@@ -1,83 +0,0 @@
-from __future__ import annotations
-from pathlib import Path
-from urllib.parse import urlparse
-from app.core.models import ProxyConfig
-from app.core.exceptions import ParseError
-
-
-def parse_lines(filepath: str) -> list[str]:
- """Читает файл, удаляет пустые строки и комментарии (#)."""
- path = Path(filepath)
- if not path.exists():
- raise FileNotFoundError(f"File not found: {filepath}")
- lines = []
- for line in path.read_text(encoding="utf-8").splitlines():
- line = line.strip()
- if line and not line.startswith("#"):
- lines.append(line)
- return lines
-
-
-def parse_proxies(filepath: str) -> list[ProxyConfig]:
- """Парсит файл с прокси в произвольном формате."""
- return [_parse_proxy_line(line) for line in parse_lines(filepath)
- if _parse_proxy_line(line) is not None]
-
-
-def _parse_proxy_line(line: str) -> ProxyConfig | None:
- """
- Алгоритм (приоритет сверху вниз):
- 1. Содержит :// → формат с протоколом
- 2. Содержит @ (без ://) → user:pass@host:port
- 3. Разбить по : → 2 части = host:port, 4 части = host:port:user:pass
- """
- try:
- if "://" in line:
- parsed = urlparse(line)
- protocol = parsed.scheme or "http"
- host = parsed.hostname or ""
- port = parsed.port or 8080
- user = parsed.username
- password = parsed.password
- return ProxyConfig(host=host, port=int(port), user=user, password=password, protocol=protocol)
-
- if "@" in line:
- credentials, hostport = line.rsplit("@", 1)
- user, password = credentials.split(":", 1)
- host, port_str = hostport.rsplit(":", 1)
- return ProxyConfig(host=host, port=int(port_str), user=user, password=password)
-
- parts = line.split(":")
- if len(parts) == 2:
- return ProxyConfig(host=parts[0], port=int(parts[1]))
- if len(parts) == 4:
- return ProxyConfig(host=parts[0], port=int(parts[1]), user=parts[2], password=parts[3])
-
- except (ValueError, AttributeError):
- pass
- return None
-
-
-def parse_wallets(filepath: str) -> list[dict]:
- """
- Определяет тип каждого кошелька:
- - private_key: 0x + 64 hex символа
- - mnemonic: 12 или 24 слова
- - address: 0x + 40 hex символа
- """
- result = []
- for line in parse_lines(filepath):
- result.append({"raw": line, "type": _detect_wallet_type(line)})
- return result
-
-
-def _detect_wallet_type(value: str) -> str:
- import re
- if re.fullmatch(r"0x[0-9a-fA-F]{64}", value):
- return "private_key"
- if re.fullmatch(r"0x[0-9a-fA-F]{40}", value):
- return "address"
- word_count = len(value.split())
- if word_count in (12, 24):
- return "mnemonic"
- return "unknown"
diff --git a/app/storage/svm_exporter.py b/app/storage/svm_exporter.py
deleted file mode 100644
index fce1934..0000000
--- a/app/storage/svm_exporter.py
+++ /dev/null
@@ -1,117 +0,0 @@
-from __future__ import annotations
-import csv
-import json
-from dataclasses import dataclass
-from pathlib import Path
-
-import openpyxl
-
-from app.core.models import Result, ResultStatus
-
-
-@dataclass
-class SvmExportConfig:
- summary: bool = True
- tokens: bool = True
- token_filter: str | None = None # None = all; plain symbol e.g. "USDC"
-
-
-class SvmExporter:
- _SECTION_COLUMNS = {
- "summary": ["address", "sol_balance", "sol_usd", "total_usd", "tokens", "status"],
- "tokens": ["address", "symbol", "mint", "amount", "price", "value"],
- }
- _SECTION_LABELS = {"summary": "Summary", "tokens": "Tokens"}
-
- def build(
- self,
- results: list[Result],
- details: dict[str, dict],
- config: SvmExportConfig,
- ) -> dict[str, list[dict]]:
- data: dict[str, list[dict]] = {"summary": [], "tokens": []}
-
- for r in results:
- if config.summary:
- data["summary"].append({
- "address": r.item,
- "sol_balance": r.data.get("sol_balance", ""),
- "sol_usd": r.data.get("sol_usd", ""),
- "total_usd": r.data.get("total_usd", ""),
- "tokens": r.data.get("tokens", ""),
- "status": r.status.value,
- })
-
- if r.status != ResultStatus.OK or not config.tokens:
- continue
-
- detail = details.get(r.item, {})
- for token in detail.get("tokens_data", []):
- if config.token_filter is not None:
- if token.get("symbol", "").upper() != config.token_filter.upper():
- continue
- data["tokens"].append({
- "address": r.item,
- "symbol": token.get("symbol", ""),
- "mint": token.get("mint", ""),
- "amount": token.get("amount", 0),
- "price": token.get("price", 0),
- "value": token.get("value", 0),
- })
-
- return data
-
- def export(
- self,
- results: list[Result],
- details: dict[str, dict],
- config: SvmExportConfig,
- path: str,
- fmt: str,
- ) -> None:
- data = self.build(results, details, config)
- if fmt == "csv":
- self._export_csv(data, config, path)
- elif fmt == "json":
- self._export_json(data, path)
- else:
- self._export_xlsx(data, config, path)
-
- def _active_sections(self, config: SvmExportConfig) -> list[str]:
- return [k for k in ("summary", "tokens") if getattr(config, k)]
-
- def _export_csv(self, data: dict, config: SvmExportConfig, path: str) -> None:
- active = self._active_sections(config)
- with open(path, "w", newline="", encoding="utf-8") as f:
- writer = csv.writer(f)
- for i, section in enumerate(active):
- if i > 0:
- writer.writerow([])
- writer.writerow([f"=== {self._SECTION_LABELS[section]} ==="])
- cols = self._SECTION_COLUMNS[section]
- writer.writerow(cols)
- for row in data[section]:
- writer.writerow([row.get(c, "") for c in cols])
-
- def _export_json(self, data: dict, path: str) -> None:
- with open(path, "w", encoding="utf-8") as f:
- json.dump(data, f, ensure_ascii=False, indent=2)
-
- def _export_xlsx(self, data: dict, config: SvmExportConfig, path: str) -> None:
- active = self._active_sections(config)
- wb = openpyxl.Workbook()
- wb.remove(wb.active)
-
- if not active:
- ws = wb.create_sheet("Summary")
- ws.append(self._SECTION_COLUMNS["summary"])
- else:
- sheet_names = {"summary": "Summary", "tokens": "Tokens"}
- for section in active:
- ws = wb.create_sheet(sheet_names[section])
- cols = self._SECTION_COLUMNS[section]
- ws.append(cols)
- for row in data[section]:
- ws.append([row.get(c, "") for c in cols])
-
- wb.save(path)
diff --git a/app/storage/twitter_exporter.py b/app/storage/twitter_exporter.py
deleted file mode 100644
index c06891e..0000000
--- a/app/storage/twitter_exporter.py
+++ /dev/null
@@ -1,69 +0,0 @@
-from __future__ import annotations
-import csv
-import json
-from dataclasses import dataclass
-from pathlib import Path
-
-import openpyxl
-
-from app.core.models import Result
-
-
-@dataclass
-class TwitterExportConfig:
- status_filter: str | None = None # None = all; "ok"/"invalid"/"suspended"/"locked"
-
-
-class TwitterExporter:
- _COLUMNS = ["token", "username", "account_status"]
-
- def build(
- self,
- results: list[Result],
- config: TwitterExportConfig,
- ) -> list[dict]:
- rows = []
- for r in results:
- account_status = r.data.get("account_status", "")
- if config.status_filter and account_status != config.status_filter:
- continue
- rows.append({
- "token": r.item,
- "username": r.data.get("username") or "",
- "account_status": account_status,
- })
- return rows
-
- def export(
- self,
- results: list[Result],
- config: TwitterExportConfig,
- path: str,
- fmt: str,
- ) -> None:
- rows = self.build(results, config)
- if fmt == "csv":
- self._export_csv(rows, path)
- elif fmt == "json":
- self._export_json(rows, path)
- else:
- self._export_xlsx(rows, path)
-
- def _export_csv(self, rows: list[dict], path: str) -> None:
- with open(path, "w", newline="", encoding="utf-8") as f:
- writer = csv.DictWriter(f, fieldnames=self._COLUMNS)
- writer.writeheader()
- writer.writerows(rows)
-
- def _export_json(self, rows: list[dict], path: str) -> None:
- with open(path, "w", encoding="utf-8") as f:
- json.dump(rows, f, ensure_ascii=False, indent=2)
-
- def _export_xlsx(self, rows: list[dict], path: str) -> None:
- wb = openpyxl.Workbook()
- ws = wb.active
- ws.title = "Results"
- ws.append(self._COLUMNS)
- for row in rows:
- ws.append([row.get(c, "") for c in self._COLUMNS])
- wb.save(path)
diff --git a/app/ui/__init__.py b/app/ui/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/app/ui/log_widget.py b/app/ui/log_widget.py
deleted file mode 100644
index fd2cbab..0000000
--- a/app/ui/log_widget.py
+++ /dev/null
@@ -1,178 +0,0 @@
-from __future__ import annotations
-
-from PySide6.QtWidgets import (
- QWidget, QVBoxLayout, QHBoxLayout, QPlainTextEdit,
- QPushButton, QLineEdit, QStackedWidget,
-)
-from PySide6.QtGui import QColor, QTextCharFormat, QTextCursor
-from PySide6.QtCore import Qt
-
-from app.ui.widgets.empty_state import EmptyState
-from app.i18n import tr, i18n
-
-
-class LogWidget(QWidget):
- """Виджет лога с цветовой индикацией, фильтрацией, поиском и freeze."""
-
- INFO_COLOR = "#8E8E93"
- WARN_COLOR = "#FFD60A"
- ERROR_COLOR = "#FF453A"
- SUCCESS_COLOR = "#30D158"
-
- def __init__(self, parent=None) -> None:
- super().__init__(parent)
- self._all_lines: list[tuple[str, str]] = [] # (line, level)
- self._frozen = False
- self._active_filter: str = "all"
-
- layout = QVBoxLayout(self)
- layout.setContentsMargins(0, 0, 0, 0)
- layout.setSpacing(4)
-
- # Controls row
- controls = QHBoxLayout()
- controls.setSpacing(4)
-
- self._btn_all = QPushButton("All")
- self._btn_info = QPushButton("Info")
- self._btn_warn = QPushButton("Warn")
- self._btn_error = QPushButton("Error")
-
- for btn, filt in [
- (self._btn_all, "all"),
- (self._btn_info, "info"),
- (self._btn_warn, "warn"),
- (self._btn_error, "error"),
- ]:
- btn.setCheckable(True)
- btn.setProperty("logFilter", True)
- btn.setFixedHeight(26)
- btn.clicked.connect(lambda checked, f=filt: self._set_filter(f))
- controls.addWidget(btn)
- self._btn_all.setChecked(True)
-
- controls.addStretch()
-
- self._search = QLineEdit()
- self._search.setObjectName("logSearch")
- self._search.setFixedWidth(180)
- self._search.setClearButtonEnabled(True)
- self._search.textChanged.connect(self._refilter)
- controls.addWidget(self._search)
-
- self._freeze_btn = QPushButton("❄")
- self._freeze_btn.setCheckable(True)
- self._freeze_btn.setProperty("logFilter", True)
- self._freeze_btn.setFixedSize(26, 26)
- self._freeze_btn.setToolTip(tr("freeze_log_tooltip"))
- self._freeze_btn.toggled.connect(self._on_freeze)
- controls.addWidget(self._freeze_btn)
-
- self._clear_btn = QPushButton()
- self._clear_btn.setProperty("logFilter", True)
- self._clear_btn.setFixedHeight(26)
- self._clear_btn.clicked.connect(self._clear)
- controls.addWidget(self._clear_btn)
-
- layout.addLayout(controls)
-
- # Text display
- self._text = QPlainTextEdit()
- self._text.setReadOnly(True)
- self._text.setMaximumBlockCount(5000)
- self._text.setObjectName("logText")
-
- # Empty state
- self._empty = EmptyState(
- icon_text="📝",
- title=tr("empty_log_title"),
- subtitle=tr("empty_log_subtitle"),
- )
-
- self._stack = QStackedWidget()
- self._stack.addWidget(self._empty)
- self._stack.addWidget(self._text)
- self._stack.setCurrentIndex(0)
-
- layout.addWidget(self._stack)
-
- self.retranslate_ui()
- i18n.language_changed.connect(self.retranslate_ui)
-
- def retranslate_ui(self) -> None:
- self._clear_btn.setText(tr("clear_log_btn"))
- self._search.setPlaceholderText(tr("search_placeholder"))
- self._freeze_btn.setToolTip(tr("freeze_log_tooltip"))
- self._empty.set_texts(
- title=tr("empty_log_title"),
- subtitle=tr("empty_log_subtitle"),
- )
-
- def append(self, line: str) -> None:
- level = "info"
- if "ERROR" in line:
- level = "error"
- elif "WARN" in line:
- level = "warn"
- elif "SUCCESS" in line or "✓" in line:
- level = "success"
-
- self._all_lines.append((line, level))
- self._stack.setCurrentIndex(1)
-
- if self._frozen:
- return
-
- search = self._search.text().strip().lower()
- if self._active_filter != "all" and level != self._active_filter:
- return
- if search and search not in line.lower():
- return
-
- self._append_colored(line, level)
-
- def _append_colored(self, line: str, level: str) -> None:
- colors = {
- "info": self.INFO_COLOR,
- "warn": self.WARN_COLOR,
- "error": self.ERROR_COLOR,
- "success": self.SUCCESS_COLOR,
- }
- color = colors.get(level, self.INFO_COLOR)
- cursor = self._text.textCursor()
- cursor.movePosition(QTextCursor.End)
- fmt = QTextCharFormat()
- fmt.setForeground(QColor(color))
- cursor.setCharFormat(fmt)
- cursor.insertText(line + "\n")
- self._text.setTextCursor(cursor)
- self._text.ensureCursorVisible()
-
- def _set_filter(self, filt: str) -> None:
- self._active_filter = filt
- for btn, f in [
- (self._btn_all, "all"),
- (self._btn_info, "info"),
- (self._btn_warn, "warn"),
- (self._btn_error, "error"),
- ]:
- btn.setChecked(f == filt)
- self._refilter()
-
- def _refilter(self) -> None:
- self._text.clear()
- search = self._search.text().strip().lower()
- for line, level in self._all_lines:
- if self._active_filter != "all" and level != self._active_filter:
- continue
- if search and search not in line.lower():
- continue
- self._append_colored(line, level)
-
- def _on_freeze(self, checked: bool) -> None:
- self._frozen = checked
-
- def _clear(self) -> None:
- self._all_lines.clear()
- self._text.clear()
- self._stack.setCurrentIndex(0)
diff --git a/app/ui/main_window.py b/app/ui/main_window.py
deleted file mode 100644
index f17d44b..0000000
--- a/app/ui/main_window.py
+++ /dev/null
@@ -1,434 +0,0 @@
-from __future__ import annotations
-
-from PySide6.QtWidgets import (
- QMainWindow, QWidget, QHBoxLayout, QVBoxLayout, QSplitter,
- QLabel, QPushButton, QStackedWidget, QProgressBar,
-)
-from PySide6.QtCore import Qt, QTimer, QUrl, QSettings
-from PySide6.QtGui import QDesktopServices, QShortcut, QKeySequence
-
-from app.core.base_module import BaseModule
-from app.core.module_registry import ModuleRegistry
-from app.core.models import RunContext, Result
-from app.core.logger import Logger
-from app.core.task_runner import TaskRunner
-from app.ui.log_widget import LogWidget
-from app.ui.results_table import ResultsTable
-from app.ui.sidebar import Sidebar
-from app.ui.widgets.toast import show_toast
-from app.i18n import i18n, tr
-
-
-class MainWindow(QMainWindow):
- def __init__(self, registry: ModuleRegistry) -> None:
- super().__init__()
- self.setWindowTitle("FarmerPro")
- self.setMinimumSize(1200, 700)
- self.setWindowState(self.windowState() | Qt.WindowMaximized)
-
- self._registry = registry
- self._task_runner = TaskRunner(self)
- self._task_runner.on_result.connect(self._on_result)
- self._task_runner.on_log.connect(self._on_log)
- self._task_runner.on_finished.connect(self._on_finished)
-
- self._current_module: BaseModule | None = None
- self._total_count: int = 0
- self._done_count: int = 0
- self._config_widgets: dict[int, QWidget] = {}
- self._results_cache: dict[int, list] = {}
-
- self._settings = QSettings("FarmerPro", "FarmerPro")
-
- # ── Sidebar ──
- self._sidebar = Sidebar(registry.get_modules())
- self._sidebar.module_selected.connect(self._on_module_selected)
-
- # ── Top toolbar (simplified — FAQ + language only) ──
- # Language toggle
- self._lang_en_btn = QPushButton("EN")
- self._lang_ru_btn = QPushButton("RU")
- self._lang_en_btn.setCheckable(True)
- self._lang_ru_btn.setCheckable(True)
- self._lang_en_btn.setProperty("langToggle", True)
- self._lang_ru_btn.setProperty("langToggle", True)
- self._lang_en_btn.setFixedWidth(36)
- self._lang_ru_btn.setFixedWidth(36)
- self._lang_en_btn.clicked.connect(lambda: self._set_lang("en"))
- self._lang_ru_btn.clicked.connect(lambda: self._set_lang("ru"))
- self._update_lang_buttons()
-
- # FAQ button
- self._faq_btn = QPushButton()
- self._faq_btn.setProperty("langToggle", True)
- self._faq_btn.setFixedWidth(46)
- self._faq_btn.clicked.connect(self._open_faq)
-
- top_bar = QWidget()
- top_bar.setObjectName("topToolbar")
- top_layout = QHBoxLayout(top_bar)
- top_layout.setContentsMargins(12, 8, 12, 8)
- top_layout.setSpacing(10)
- top_layout.addStretch()
- top_layout.addWidget(self._faq_btn)
- top_layout.addWidget(self._lang_en_btn)
- top_layout.addWidget(self._lang_ru_btn)
-
- # ── Progress (improved: 6px height, percentage) ──
- self._progress_bar = QProgressBar()
- self._progress_bar.setTextVisible(False)
- self._progress_bar.setFixedHeight(6)
- self._progress_bar.setObjectName("mainProgress")
- self._progress_label = QLabel("")
- self._progress_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
- self._progress_label.setMinimumWidth(90)
- self._progress_label.setObjectName("progressLabel")
-
- progress_row = QHBoxLayout()
- progress_row.setContentsMargins(8, 2, 8, 2)
- progress_row.addWidget(self._progress_bar)
- progress_row.addWidget(self._progress_label)
-
- self._progress_widget = QWidget()
- self._progress_widget.setLayout(progress_row)
- self._progress_widget.setVisible(False)
-
- # ── Module config stack (LEFT pane now) ──
- self._module_stack = QStackedWidget()
- self._module_stack.setObjectName("moduleStack")
-
- # ── Start / Stop buttons — sticky footer inside config pane ──
- self._start_btn = QPushButton()
- self._start_btn.setProperty("primary", True)
- self._stop_btn = QPushButton()
- self._stop_btn.setEnabled(False)
-
- btn_row = QHBoxLayout()
- btn_row.setContentsMargins(12, 8, 12, 8)
- btn_row.setSpacing(8)
- btn_row.addWidget(self._start_btn, 1)
- btn_row.addWidget(self._stop_btn, 1)
-
- inspector_pane = QWidget()
- inspector_pane.setObjectName("inspectorPane")
- inspector_pane.setMinimumWidth(340)
- inspector_layout = QVBoxLayout(inspector_pane)
- inspector_layout.setContentsMargins(12, 12, 12, 0)
- inspector_layout.addWidget(self._module_stack, 1)
- inspector_layout.addLayout(btn_row)
-
- # ── Results & Log (RIGHT pane now) ──
- self._results_table = ResultsTable()
- self._log_widget = LogWidget()
- self._log_widget.setObjectName("logPane")
-
- results_pane = QWidget()
- results_pane.setObjectName("resultsPane")
- results_layout = QVBoxLayout(results_pane)
- results_layout.setContentsMargins(12, 12, 12, 12)
- results_layout.addWidget(self._results_table)
-
- # ── Layout: Config LEFT | Results RIGHT ──
- main_splitter = QSplitter(Qt.Horizontal)
- main_splitter.setObjectName("mainSplitter")
- main_splitter.addWidget(inspector_pane)
- main_splitter.addWidget(results_pane)
- main_splitter.setSizes([380, 720])
-
- # ── Log: collapsed by default ──
- self._log_widget.setMinimumHeight(36)
- self._log_collapsed = True
-
- self._log_toggle_btn = QPushButton()
- self._log_toggle_btn.setProperty("logFilter", True)
- self._log_toggle_btn.setFixedHeight(28)
- self._log_toggle_btn.clicked.connect(self._toggle_log)
-
- self._log_last_line = QLabel("")
- self._log_last_line.setObjectName("statsLabel")
- self._log_last_line.setStyleSheet("font-family: monospace; font-size: 9pt;")
-
- log_header = QHBoxLayout()
- log_header.setContentsMargins(8, 4, 8, 4)
- log_header.addWidget(self._log_toggle_btn)
- log_header.addWidget(self._log_last_line, 1)
-
- log_container = QWidget()
- log_container_layout = QVBoxLayout(log_container)
- log_container_layout.setContentsMargins(0, 0, 0, 0)
- log_container_layout.setSpacing(0)
- log_container_layout.addLayout(log_header)
- log_container_layout.addWidget(self._log_widget)
- self._log_widget.setVisible(False)
-
- self._vertical_splitter = QSplitter(Qt.Vertical)
- self._vertical_splitter.addWidget(main_splitter)
- self._vertical_splitter.addWidget(log_container)
- self._vertical_splitter.setSizes([660, 36])
-
- # ── Right content area ──
- content = QWidget()
- content_layout = QVBoxLayout(content)
- content_layout.setContentsMargins(0, 0, 0, 0)
- content_layout.setSpacing(0)
- content_layout.addWidget(top_bar)
- content_layout.addWidget(self._progress_widget)
- content_layout.addWidget(self._vertical_splitter)
-
- # ── Root: Sidebar + Content ──
- root = QWidget()
- root_layout = QHBoxLayout(root)
- root_layout.setContentsMargins(0, 0, 0, 0)
- root_layout.setSpacing(0)
- root_layout.addWidget(self._sidebar)
- root_layout.addWidget(content, 1)
- self.setCentralWidget(root)
-
- # ── Signals ──
- self._start_btn.clicked.connect(self._on_start)
- self._stop_btn.clicked.connect(self._on_stop)
- i18n.language_changed.connect(self.retranslate_ui)
-
- # ── Keyboard shortcuts ──
- for i in range(min(9, len(registry.get_modules()))):
- QShortcut(QKeySequence(f"Ctrl+{i+1}"), self).activated.connect(
- lambda idx=i: self._sidebar.select_module(idx)
- )
- QShortcut(QKeySequence("Ctrl+Return"), self).activated.connect(self._on_start)
- QShortcut(QKeySequence("Escape"), self).activated.connect(self._on_stop)
- QShortcut(QKeySequence("Ctrl+E"), self).activated.connect(self._quick_export)
-
- # Initial translation
- self.retranslate_ui()
-
- # Restore splitter sizes
- self._restore_splitter_sizes()
-
- # Show first module
- if registry.get_modules():
- self._on_module_selected(registry.get_modules()[0])
-
- # ── Language ──
-
- def _set_lang(self, lang: str) -> None:
- from app.core.config import Config
- i18n.set_language(lang)
- Config.instance().set("language", lang)
- self._update_lang_buttons()
-
- def _update_lang_buttons(self) -> None:
- self._lang_en_btn.setChecked(i18n.language == "en")
- self._lang_ru_btn.setChecked(i18n.language == "ru")
-
- def retranslate_ui(self) -> None:
- self._start_btn.setText(tr("start_btn"))
- self._stop_btn.setText(tr("stop_btn"))
- self._faq_btn.setText(tr("faq_btn"))
- self._log_toggle_btn.setText(
- tr("log_expand_btn") if self._log_collapsed else tr("log_collapse_btn")
- )
- for widget in self._config_widgets.values():
- if hasattr(widget, "retranslate_ui"):
- widget.retranslate_ui()
- self._results_table.retranslate_ui()
- self._log_widget.retranslate_ui()
-
- def _open_faq(self) -> None:
- urls = {
- "en": "https://privatekey7.gitbook.io/farmerpro-en/",
- "ru": "https://privatekey7.gitbook.io/farmerpro-ru/",
- }
- QDesktopServices.openUrl(QUrl(urls.get(i18n.language, urls["en"])))
-
- # ── Log collapse / expand ──
-
- def _toggle_log(self) -> None:
- self._log_collapsed = not self._log_collapsed
- self._log_widget.setVisible(not self._log_collapsed)
- self._log_last_line.setVisible(self._log_collapsed)
- if self._log_collapsed:
- self._vertical_splitter.setSizes([660, 36])
- self._log_toggle_btn.setText(tr("log_expand_btn"))
- else:
- self._vertical_splitter.setSizes([480, 220])
- self._log_toggle_btn.setText(tr("log_collapse_btn"))
-
- # ── Splitter persistence ──
-
- def _restore_splitter_sizes(self) -> None:
- main_sizes = self._settings.value("mainSplitter")
- if main_sizes:
- try:
- splitter = self._vertical_splitter.widget(0)
- if isinstance(splitter, QSplitter):
- splitter.setSizes([int(s) for s in main_sizes])
- except (ValueError, TypeError):
- pass
-
- def _save_splitter_sizes(self) -> None:
- splitter = self._vertical_splitter.widget(0)
- if isinstance(splitter, QSplitter):
- self._settings.setValue("mainSplitter", splitter.sizes())
-
- def closeEvent(self, event) -> None:
- self._save_splitter_sizes()
- super().closeEvent(event)
-
- # ── Module selection ──
-
- def _on_module_selected(self, module: BaseModule) -> None:
- if module is self._current_module:
- return
- if self._current_module is not None:
- self._results_cache[id(self._current_module)] = self._results_table.snapshot()
- self._current_module = module
- cached = self._results_cache.get(id(module))
- if cached:
- self._results_table.restore(cached)
- else:
- self._results_table.clear_results()
- key = id(module)
- widget = self._config_widgets.get(key)
- if widget is None:
- widget = module.get_config_widget()
- if widget is None:
- from app.ui.module_views.placeholder_view import PlaceholderView
- widget = PlaceholderView(module.name)
- self._config_widgets[key] = widget
- self._module_stack.addWidget(widget)
- self._module_stack.setCurrentWidget(widget)
-
- # ── Validation ──
-
- def _validate_start(self) -> bool:
- """Check that required inputs are loaded. Show toast on failure."""
- config_widget = self._config_widgets.get(id(self._current_module))
- if config_widget is None:
- return True
-
- # Modules that need wallets
- if hasattr(config_widget, "get_wallets"):
- wallets = config_widget.get_wallets()
- if not wallets:
- show_toast(self, tr("validation_no_wallets"), level="warning")
- return False
-
- # Modules that need tokens (Twitter/Discord)
- if hasattr(config_widget, "get_tokens"):
- tokens = config_widget.get_tokens()
- if not tokens:
- show_toast(self, tr("validation_no_tokens"), level="warning")
- return False
-
- # Proxy checker needs proxies
- if hasattr(config_widget, "get_proxies") and not hasattr(config_widget, "get_wallets") and not hasattr(config_widget, "get_tokens"):
- proxies = config_widget.get_proxies()
- if not proxies:
- show_toast(self, tr("validation_no_proxies"), level="warning")
- return False
-
- return True
-
- # ── Start / Stop ──
-
- def _on_start(self) -> None:
- if self._current_module is None:
- return
- if not self._start_btn.isEnabled():
- return
- if not self._validate_start():
- return
-
- self._results_table.clear_results()
- # Apply module column schema before any rows arrive
- schema = self._current_module.column_schema()
- if schema:
- self._results_table.set_schema(schema)
- self._start_btn.setEnabled(False)
- self._stop_btn.setEnabled(True)
-
- self._sidebar.set_module_status(self._current_module, "running")
-
- self._done_count = 0
- self._total_count = self._current_module.get_item_count()
- if self._total_count > 0:
- self._progress_bar.setRange(0, self._total_count)
- self._progress_bar.setValue(0)
- self._progress_label.setText("0 / {0} (0%)".format(self._total_count))
- else:
- self._progress_bar.setRange(0, 0)
- self._progress_label.setText("")
- self._progress_widget.setVisible(True)
-
- config_widget = self._config_widgets.get(id(self._current_module))
- proxies = (
- config_widget.get_proxies()
- if config_widget and hasattr(config_widget, "get_proxies")
- else []
- )
- ctx = RunContext(
- items=[],
- proxies=proxies,
- rpc_urls=[],
- concurrency=min(len(proxies), 50) if proxies else 10,
- )
- logger = Logger(on_log_signal=self._task_runner.on_log)
- ctx.extra["logger"] = logger
- self._task_runner.submit(self._current_module, ctx)
-
- def _on_stop(self) -> None:
- if self._stop_btn.isEnabled():
- self._task_runner.stop_module()
-
- def _on_result(self, result: Result) -> None:
- self._results_table.add_row(result)
- self._done_count += 1
- if self._total_count > 0:
- display = min(self._done_count, self._total_count)
- pct = int(display / self._total_count * 100)
- self._progress_bar.setValue(display)
- self._progress_label.setText(f"{display} / {self._total_count} ({pct}%)")
- # Update sidebar with live count
- if self._current_module:
- self._sidebar.set_module_progress(
- self._current_module, display, self._total_count
- )
-
- def _on_log(self, line: str) -> None:
- self._log_widget.append(line)
- # Update collapsed log preview
- if self._log_collapsed:
- truncated = line[:120] + "…" if len(line) > 120 else line
- self._log_last_line.setText(truncated)
-
- def _on_finished(self) -> None:
- self._start_btn.setEnabled(True)
- self._stop_btn.setEnabled(False)
-
- cached = self._results_table.snapshot()
- has_errors = any(r.status.value == "error" for r in cached)
- status = "error" if has_errors else "done"
-
- if self._current_module:
- self._sidebar.set_module_status(self._current_module, status)
-
- if self._total_count > 0:
- self._progress_bar.setValue(self._total_count)
- pct = int(self._done_count / self._total_count * 100) if self._total_count else 100
- self._progress_label.setText(f"{self._done_count} / {self._total_count} ({pct}%)")
-
- # Toast notification
- if has_errors:
- show_toast(self, tr("toast_finished_errors"), level="warning")
- else:
- show_toast(self, tr("toast_finished_ok"), level="success")
-
- # Don't auto-hide progress — keep it visible for reference
-
- def _quick_export(self) -> None:
- """Ctrl+E — trigger XLSX export from config panel if available."""
- config_widget = self._config_widgets.get(
- id(self._current_module) if self._current_module else None
- )
- if config_widget and hasattr(config_widget, "_on_export"):
- config_widget._on_export("xlsx")
diff --git a/app/ui/module_views/__init__.py b/app/ui/module_views/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/app/ui/module_views/collector_view.py b/app/ui/module_views/collector_view.py
deleted file mode 100644
index 0f026ee..0000000
--- a/app/ui/module_views/collector_view.py
+++ /dev/null
@@ -1,436 +0,0 @@
-# app/ui/module_views/collector_view.py
-from __future__ import annotations
-from dataclasses import dataclass
-
-from PySide6.QtWidgets import (
- QWidget, QVBoxLayout, QHBoxLayout, QGroupBox,
- QLabel, QLineEdit, QFileDialog, QPushButton,
- QCheckBox, QDoubleSpinBox, QSpinBox, QScrollArea, QFrame,
-)
-
-from app.ui.widgets.chain_picker import ChainPickerWidget
-from app.ui.widgets.drop_zone import DropZone
-
-from app.core.models import ProxyConfig
-from app.storage.parsers import parse_wallets, parse_proxies, parse_lines
-from app.i18n import tr, i18n
-
-
-@dataclass
-class CollectorSettings:
- min_token_usd: float # default 1.0
- min_bridge_usd: float # default 1.0 — пропустить бридж если баланс меньше
- excluded_chains: list[str] # DeBank keys в lowercase
- target_chains: list[str] # DeBank keys или названия сетей
- slippage: float # десятичная (0.005 = 0.5%)
- delay_min: int # default 10
- delay_max: int # default 30
- send_to_exchange: bool
- delay_after_bridge: int # default 60
-
-
-class CollectorConfigWidget(QWidget):
- """Панель настроек модуля Collector."""
-
- def __init__(self, parent=None) -> None:
- super().__init__(parent)
- self._wallets: list[dict] = [] # [{"raw": ..., "type": ...}]
- self._proxies: list[ProxyConfig] = []
- self._subaccounts: list[str] = []
- self._export_results: list = []
- self._export_details: dict = {}
-
- root_layout = QVBoxLayout(self)
- root_layout.setContentsMargins(0, 0, 0, 0)
- root_layout.setSpacing(0)
-
- scroll = QScrollArea(self)
- scroll.setWidgetResizable(True)
- scroll.setFrameShape(QFrame.NoFrame)
-
- content = QWidget()
- layout = QVBoxLayout(content)
- layout.setContentsMargins(16, 16, 16, 16)
- layout.setSpacing(8)
-
- scroll.setWidget(content)
- root_layout.addWidget(scroll)
-
- # --- Кошельки (приватные ключи / мнемоники) ---
- self._lbl_files_header = QLabel()
- layout.addWidget(self._lbl_files_header)
-
- self._wallet_drop = DropZone(
- label=tr("wallets_label"),
- placeholder="private_keys.txt",
- )
- self._wallet_drop.file_dropped.connect(self._on_wallet_file)
- layout.addWidget(self._wallet_drop)
-
- # --- Прокси ---
- self._proxy_drop = DropZone(
- label=tr("proxy_label"),
- placeholder="proxy.txt",
- )
- self._proxy_drop.file_dropped.connect(self._on_proxy_file)
- layout.addWidget(self._proxy_drop)
-
- # --- Фильтры ---
- self._grp_filters = QGroupBox()
- fg = QVBoxLayout(self._grp_filters)
-
- min_row = QHBoxLayout()
- self._lbl_min_value = QLabel()
- min_row.addWidget(self._lbl_min_value)
- self._min_token_usd = QDoubleSpinBox()
- self._min_token_usd.setRange(0.01, 10000.0)
- self._min_token_usd.setValue(0.03)
- self._min_token_usd.setDecimals(2)
- self._min_token_usd.setFixedWidth(104)
- self._min_token_usd.setToolTip(tr("min_value_tooltip"))
- min_row.addWidget(self._min_token_usd)
- min_row.addStretch()
- fg.addLayout(min_row)
-
- excl_row = QHBoxLayout()
- self._lbl_exclude_chains = QLabel()
- excl_row.addWidget(self._lbl_exclude_chains)
- self._excluded_chains = ChainPickerWidget(parent=self)
- excl_row.addWidget(self._excluded_chains)
- fg.addLayout(excl_row)
-
- slippage_row = QHBoxLayout()
- self._lbl_slippage = QLabel()
- slippage_row.addWidget(self._lbl_slippage)
- self._slippage = QDoubleSpinBox()
- self._slippage.setRange(0.1, 50.0)
- self._slippage.setValue(3.0)
- self._slippage.setDecimals(1)
- self._slippage.setFixedWidth(104)
- self._slippage.setToolTip(tr("slippage_tooltip"))
- slippage_row.addWidget(self._slippage)
- slippage_row.addStretch()
- fg.addLayout(slippage_row)
-
- layout.addWidget(self._grp_filters)
-
- # --- Бридж ---
- self._grp_bridge = QGroupBox()
- bg = QVBoxLayout(self._grp_bridge)
-
- target_row = QHBoxLayout()
- self._lbl_target_chains = QLabel()
- target_row.addWidget(self._lbl_target_chains)
- self._target_chains = ChainPickerWidget(parent=self)
- target_row.addWidget(self._target_chains)
- bg.addLayout(target_row)
-
- min_bridge_row = QHBoxLayout()
- self._lbl_min_bridge = QLabel()
- min_bridge_row.addWidget(self._lbl_min_bridge)
- self._min_bridge_usd = QDoubleSpinBox()
- self._min_bridge_usd.setRange(0.0, 100000.0)
- self._min_bridge_usd.setValue(0.03)
- self._min_bridge_usd.setDecimals(2)
- self._min_bridge_usd.setFixedWidth(104)
- self._min_bridge_usd.setToolTip(tr("min_bridge_tooltip"))
- min_bridge_row.addWidget(self._min_bridge_usd)
- min_bridge_row.addStretch()
- bg.addLayout(min_bridge_row)
-
- layout.addWidget(self._grp_bridge)
-
- # --- Задержки ---
- self._grp_delays = QGroupBox()
- dg = QVBoxLayout(self._grp_delays)
-
- delay_row = QHBoxLayout()
- self._lbl_delay_between_wallets = QLabel()
- delay_row.addWidget(self._lbl_delay_between_wallets)
- self._delay_min = QSpinBox()
- self._delay_min.setRange(0, 3600)
- self._delay_min.setValue(60)
- self._delay_min.setFixedWidth(86)
- self._delay_min.setToolTip(tr("delay_min_tooltip"))
- delay_row.addWidget(self._delay_min)
- delay_row.addWidget(QLabel("—"))
- self._delay_max = QSpinBox()
- self._delay_max.setRange(0, 3600)
- self._delay_max.setValue(180)
- self._delay_max.setFixedWidth(86)
- self._delay_max.setToolTip(tr("delay_max_tooltip"))
- delay_row.addWidget(self._delay_max)
- delay_row.addStretch()
- dg.addLayout(delay_row)
-
- layout.addWidget(self._grp_delays)
-
- # --- Субаккаунт биржи ---
- self._grp_exchange = QGroupBox()
- eg = QVBoxLayout(self._grp_exchange)
-
- self._send_to_exchange = QCheckBox()
- self._send_to_exchange.toggled.connect(self._on_exchange_toggled)
- eg.addWidget(self._send_to_exchange)
-
- self._sub_drop = DropZone(
- label=tr("subaccounts_label"),
- placeholder="subaccounts.txt",
- )
- self._sub_drop.file_dropped.connect(self._on_subaccount_file)
- self._sub_drop.setEnabled(False)
- eg.addWidget(self._sub_drop)
-
- delay_bridge_row = QHBoxLayout()
- self._lbl_after_bridge_delay = QLabel()
- delay_bridge_row.addWidget(self._lbl_after_bridge_delay)
- self._delay_after_bridge = QSpinBox()
- self._delay_after_bridge.setRange(0, 3600)
- self._delay_after_bridge.setValue(60)
- self._delay_after_bridge.setFixedWidth(86)
- self._delay_after_bridge.setEnabled(False)
- self._delay_after_bridge.setToolTip(tr("after_bridge_delay_tooltip"))
- delay_bridge_row.addWidget(self._delay_after_bridge)
- delay_bridge_row.addStretch()
- eg.addLayout(delay_bridge_row)
-
- layout.addWidget(self._grp_exchange)
-
- # --- Экспорт ---
- self._export_group = QGroupBox()
- self._grp_export = self._export_group
- self._export_group.setEnabled(False)
- exp_layout = QHBoxLayout(self._export_group)
- self._btn_csv = QPushButton()
- self._btn_json = QPushButton()
- self._btn_xlsx = QPushButton()
- self._btn_csv.clicked.connect(lambda: self._on_export("csv"))
- self._btn_json.clicked.connect(lambda: self._on_export("json"))
- self._btn_xlsx.clicked.connect(lambda: self._on_export("xlsx"))
- exp_layout.addWidget(self._btn_csv)
- exp_layout.addWidget(self._btn_json)
- exp_layout.addWidget(self._btn_xlsx)
- layout.addWidget(self._export_group)
-
- layout.addStretch()
-
- i18n.language_changed.connect(self.retranslate_ui)
- self.retranslate_ui()
-
- def retranslate_ui(self) -> None:
- self._lbl_files_header.setText(tr("files_header"))
- self._wallet_drop.set_label(tr("wallets_label"))
- self._proxy_drop.set_label(tr("proxy_label"))
- self._grp_filters.setTitle(tr("filters_group"))
- self._lbl_min_value.setText(tr("min_value_label"))
- self._lbl_exclude_chains.setText(tr("exclude_chains_label"))
- self._lbl_slippage.setText(tr("slippage_label"))
- self._grp_bridge.setTitle(tr("bridge_group"))
- self._lbl_target_chains.setText(tr("target_chains_label"))
- self._lbl_min_bridge.setText(tr("min_value_label"))
- self._grp_delays.setTitle(tr("delays_group"))
- self._lbl_delay_between_wallets.setText(tr("delay_between_wallets_label"))
- self._grp_exchange.setTitle(tr("exchange_group"))
- self._send_to_exchange.setText(tr("send_to_exchange_checkbox"))
- self._sub_drop.set_label(tr("subaccounts_label"))
- self._lbl_after_bridge_delay.setText(tr("after_bridge_delay_label"))
- self._grp_export.setTitle(tr("export_group"))
- self._btn_csv.setText(tr("save_csv"))
- self._btn_json.setText(tr("save_json"))
- self._btn_xlsx.setText(tr("save_xlsx"))
-
- # --- Загрузка файлов ---
-
- def _on_wallet_file(self, path: str) -> None:
- try:
- parsed = parse_wallets(path)
- self._wallets = [w for w in parsed if w["type"] in ("private_key", "mnemonic")]
- self._wallet_drop.set_status(tr("n_wallets_loaded").format(n=len(self._wallets)))
- self._check_wallet_subaccount_match()
- except Exception as e:
- self._wallets = []
- self._wallet_drop.set_status(tr("error_fmt").format(e=e))
-
- def _on_proxy_file(self, path: str) -> None:
- try:
- self._proxies = parse_proxies(path)
- self._proxy_drop.set_status(tr("n_proxies_loaded").format(n=len(self._proxies)))
- except Exception as e:
- self._proxies = []
- self._proxy_drop.set_status(tr("error_fmt").format(e=e))
-
- def _on_subaccount_file(self, path: str) -> None:
- import re
- try:
- lines = parse_lines(path)
- invalid = [l for l in lines if not re.fullmatch(r"0x[0-9a-fA-F]{40}", l)]
- if invalid:
- self._subaccounts = []
- self._sub_drop.set_status(
- tr("error_fmt").format(e=f"Invalid EVM addresses: {', '.join(invalid[:3])}{'…' if len(invalid) > 3 else ''}")
- )
- return
- self._subaccounts = lines
- self._check_wallet_subaccount_match()
- except Exception as e:
- self._subaccounts = []
- self._sub_drop.set_status(tr("error_fmt").format(e=e))
-
- def _check_wallet_subaccount_match(self) -> None:
- """Показывает предупреждение если кол-во кошельков != субаккаунтов."""
- if not self._send_to_exchange.isChecked():
- return
- w = len(self._wallets)
- s = len(self._subaccounts)
- if w == 0 or s == 0:
- self._sub_drop.set_status("")
- return
- if w != s:
- self._sub_drop.set_status(tr("wallets_subaccounts_mismatch").format(w=w, s=s))
- else:
- self._sub_drop.set_status(tr("n_subaccounts_loaded").format(s=s))
-
- def _on_exchange_toggled(self, checked: bool) -> None:
- self._sub_drop.setEnabled(checked)
- self._delay_after_bridge.setEnabled(checked)
- self._check_wallet_subaccount_match()
-
- # --- Публичные методы ---
-
- def get_wallets(self) -> list[dict]:
- return self._wallets
-
- def get_proxies(self) -> list[ProxyConfig]:
- return self._proxies
-
- def get_subaccounts(self) -> list[str]:
- return self._subaccounts
-
- def get_settings(self) -> CollectorSettings:
- excluded = self._excluded_chains.get_selected()
- target = self._target_chains.get_selected()
- return CollectorSettings(
- min_token_usd=self._min_token_usd.value(),
- min_bridge_usd=self._min_bridge_usd.value(),
- excluded_chains=excluded,
- target_chains=target,
- slippage=self._slippage.value() / 100.0,
- delay_min=self._delay_min.value(),
- delay_max=self._delay_max.value(),
- send_to_exchange=self._send_to_exchange.isChecked(),
- delay_after_bridge=self._delay_after_bridge.value(),
- )
-
- def on_run_complete(self, results: list, details: dict) -> None:
- """Слот: активирует экспорт после завершения run()."""
- self._export_results = results
- self._export_details = details
- self._export_group.setEnabled(True)
-
- def _on_export(self, fmt: str) -> None:
- if not self._export_results:
- return
- extensions = {
- "csv": (tr("save_csv"), "collector_results.csv", "CSV (*.csv)"),
- "json": (tr("save_json"), "collector_results.json", "JSON (*.json)"),
- "xlsx": (tr("save_xlsx"), "collector_results.xlsx", "Excel (*.xlsx)"),
- }
- title, default_name, file_filter = extensions[fmt]
- path, _ = QFileDialog.getSaveFileName(self, title, default_name, file_filter)
- if not path:
- return
- import json, csv
-
- # Build summary rows (bridge_ops excluded — shown in separate Bridges sheet/section)
- summary_rows = []
- bridge_rows = []
- for r in self._export_results:
- data = dict(r.data)
- ops = data.pop("bridge_ops", []) or []
- bridge_count = len(ops)
- summary_rows.append({"item": r.item, "status": r.status.value,
- "bridges": bridge_count, **data})
- for op in ops:
- bridge_rows.append({
- "address": r.item,
- "src_chain": op.get("src", ""),
- "tgt_chain": op.get("tgt", ""),
- "tx_hash": op.get("tx", ""),
- "status": op.get("status", ""),
- "sent_usd": op.get("usd", 0),
- })
-
- total_usd = sum(r.data.get("total_collected_usd", 0) or 0 for r in self._export_results)
-
- if fmt == "json":
- with open(path, "w", encoding="utf-8") as f:
- json.dump({
- "total_collected_usd": round(total_usd, 2),
- "summary": summary_rows,
- "bridges": bridge_rows,
- }, f, ensure_ascii=False, indent=2)
-
- elif fmt == "csv":
- if summary_rows:
- with open(path, "w", newline="", encoding="utf-8-sig") as f:
- writer = csv.DictWriter(f, fieldnames=summary_rows[0].keys())
- writer.writeheader()
- writer.writerows(summary_rows)
- writer.writerow({})
- writer.writerow({"item": "TOTAL", "total_collected_usd": round(total_usd, 2)})
- if bridge_rows:
- writer.writerow({})
- writer.writerow({"item": "=== BRIDGES ==="})
- with open(path, "a", newline="", encoding="utf-8-sig") as f:
- if bridge_rows:
- writer = csv.DictWriter(f, fieldnames=bridge_rows[0].keys())
- writer.writeheader()
- writer.writerows(bridge_rows)
-
- elif fmt == "xlsx":
- try:
- import openpyxl
- from openpyxl.styles import Font, PatternFill, Alignment
- except ImportError:
- import subprocess, sys
- subprocess.check_call([sys.executable, "-m", "pip", "install", "openpyxl"])
- import openpyxl
- from openpyxl.styles import Font, PatternFill, Alignment
- wb = openpyxl.Workbook()
-
- # ── Sheet 1: Summary ──────────────────────────────────────────
- ws1 = wb.active
- ws1.title = "Summary"
- if summary_rows:
- header = list(summary_rows[0].keys())
- ws1.append(header)
- for cell in ws1[1]:
- cell.font = Font(bold=True)
- for row in summary_rows:
- ws1.append(list(row.values()))
- ws1.append([])
- total_row = ["TOTAL"] + [""] * (len(header) - 1)
- if "total_collected_usd" in header:
- total_row[header.index("total_collected_usd")] = round(total_usd, 2)
- ws1.append(total_row)
- for cell in ws1[ws1.max_row]:
- cell.font = Font(bold=True)
-
- # ── Sheet 2: Bridges ─────────────────────────────────────────
- ws2 = wb.create_sheet("Bridges")
- if bridge_rows:
- b_header = list(bridge_rows[0].keys())
- ws2.append(b_header)
- for cell in ws2[1]:
- cell.font = Font(bold=True)
- for row in bridge_rows:
- ws2.append(list(row.values()))
-
- try:
- wb.save(path)
- except PermissionError:
- from PySide6.QtWidgets import QMessageBox
- QMessageBox.warning(
- self, tr("save_error_title"),
- tr("save_error_msg").format(path=path),
- )
diff --git a/app/ui/module_views/discord_checker_view.py b/app/ui/module_views/discord_checker_view.py
deleted file mode 100644
index 77c070a..0000000
--- a/app/ui/module_views/discord_checker_view.py
+++ /dev/null
@@ -1,134 +0,0 @@
-from __future__ import annotations
-from PySide6.QtWidgets import (
- QWidget, QVBoxLayout, QHBoxLayout, QGroupBox,
- QLabel, QFileDialog, QComboBox, QPushButton,
-)
-from app.ui.widgets.drop_zone import DropZone
-from app.core.models import ProxyConfig
-from app.storage.parsers import parse_proxies, parse_lines
-from app.i18n import tr, i18n
-
-
-class DiscordCheckerConfigWidget(QWidget):
- """Config panel for Discord Checker module."""
-
- def __init__(self, parent=None) -> None:
- super().__init__(parent)
- self._tokens: list[str] = []
- self._proxies: list[ProxyConfig] = []
- self._export_results: list = []
-
- layout = QVBoxLayout(self)
- layout.setContentsMargins(16, 16, 16, 16)
- layout.setSpacing(8)
-
- # --- Tokens ---
- self._token_drop = DropZone(
- label=tr("tokens_label_checker"),
- placeholder="tokens.txt",
- )
- self._token_drop.file_dropped.connect(self._on_token_file)
- layout.addWidget(self._token_drop)
-
- # --- Proxies ---
- self._proxy_drop = DropZone(
- label=tr("proxy_label_checker"),
- placeholder="proxy.txt",
- )
- self._proxy_drop.file_dropped.connect(self._on_proxy_file)
- layout.addWidget(self._proxy_drop)
-
- # --- Export (disabled until run completes) ---
- self._export_group = QGroupBox()
- self._export_group.setEnabled(False)
- export_layout = QVBoxLayout(self._export_group)
-
- filter_row = QHBoxLayout()
- self._lbl_status = QLabel()
- filter_row.addWidget(self._lbl_status)
- self._status_combo = QComboBox()
- self._status_combo.addItem(tr("filter_all"), None)
- for s in ("ok", "invalid", "disabled"):
- self._status_combo.addItem(s, s)
- filter_row.addWidget(self._status_combo)
- filter_row.addSpacing(16)
- self._lbl_format = QLabel()
- filter_row.addWidget(self._lbl_format)
- self._fmt_combo = QComboBox()
- for fmt in ("xlsx", "csv", "json"):
- self._fmt_combo.addItem(fmt, fmt)
- filter_row.addWidget(self._fmt_combo)
- filter_row.addStretch()
- export_layout.addLayout(filter_row)
-
- self._export_btn = QPushButton()
- self._export_btn.clicked.connect(self._on_export)
- export_layout.addWidget(self._export_btn)
-
- layout.addWidget(self._export_group)
- layout.addStretch()
-
- self.retranslate_ui()
- i18n.language_changed.connect(self.retranslate_ui)
-
- def retranslate_ui(self) -> None:
- self._token_drop.set_label(tr("tokens_label_checker"))
- self._proxy_drop.set_label(tr("proxy_label_checker"))
- self._export_group.setTitle(tr("export_group"))
- self._lbl_status.setText(tr("status_label"))
- self._lbl_format.setText(tr("format_label"))
- self._export_btn.setText(tr("export_btn"))
- self._status_combo.setItemText(0, tr("filter_all"))
-
- # --- File loading ---
-
- def _on_token_file(self, path: str) -> None:
- try:
- self._tokens = parse_lines(path)
- self._token_drop.set_status(tr("n_tokens_loaded").format(n=len(self._tokens)))
- except Exception as e:
- self._tokens = []
- self._token_drop.set_status(tr("error_fmt").format(e=e))
-
- def _on_proxy_file(self, path: str) -> None:
- try:
- self._proxies = parse_proxies(path)
- self._proxy_drop.set_status(tr("n_proxies_loaded").format(n=len(self._proxies)))
- except Exception as e:
- self._proxies = []
- self._proxy_drop.set_status(tr("error_fmt").format(e=e))
-
- # --- Accessors (called by module) ---
-
- def get_tokens(self) -> list[str]:
- return self._tokens
-
- def get_proxies(self) -> list[ProxyConfig]:
- return self._proxies
-
- def on_run_complete(self, results: list) -> None:
- """Slot: called via Qt queued connection after run() finishes."""
- self._export_results = results
- self._export_group.setEnabled(True)
-
- # --- Export ---
-
- def _on_export(self) -> None:
- if not self._export_results:
- return
- from app.storage.discord_exporter import DiscordExporter, DiscordExportConfig
-
- status_filter = self._status_combo.currentData()
- fmt = self._fmt_combo.currentData()
- config = DiscordExportConfig(status_filter=status_filter)
-
- extensions = {
- "csv": (tr("save_csv"), "discord_results.csv", "CSV (*.csv)"),
- "json": (tr("save_json"), "discord_results.json", "JSON (*.json)"),
- "xlsx": (tr("save_xlsx"), "discord_results.xlsx", "Excel (*.xlsx)"),
- }
- title, default_name, file_filter = extensions[fmt]
- path, _ = QFileDialog.getSaveFileName(self, title, default_name, file_filter)
- if not path:
- return
- DiscordExporter().export(self._export_results, config, path, fmt)
diff --git a/app/ui/module_views/evm_balance_view.py b/app/ui/module_views/evm_balance_view.py
deleted file mode 100644
index 2504872..0000000
--- a/app/ui/module_views/evm_balance_view.py
+++ /dev/null
@@ -1,161 +0,0 @@
-from __future__ import annotations
-from PySide6.QtWidgets import (
- QWidget, QVBoxLayout, QHBoxLayout, QGroupBox,
- QLabel, QFileDialog, QCheckBox, QComboBox, QPushButton,
-)
-from app.ui.widgets.drop_zone import DropZone
-from app.core.models import ProxyConfig
-from app.storage.parsers import parse_wallets, parse_proxies
-from app.i18n import tr, i18n
-
-
-class EvmBalanceConfigWidget(QWidget):
- """Панель настроек модуля EVM Balance: файлы + секция экспорта."""
-
- def __init__(self, parent=None) -> None:
- super().__init__(parent)
- self._wallets: list[str] = []
- self._proxies: list[ProxyConfig] = []
- self._export_results: list = []
- self._export_details: dict = {}
-
- layout = QVBoxLayout(self)
- layout.setContentsMargins(16, 16, 16, 16)
- layout.setSpacing(8)
-
- # --- Кошельки ---
- self._wallet_drop = DropZone(
- label=tr("wallets_label"),
- placeholder="wallets.txt",
- )
- self._wallet_drop.file_dropped.connect(self._on_wallet_file)
- layout.addWidget(self._wallet_drop)
-
- # --- Прокси ---
- self._proxy_drop = DropZone(
- label=tr("proxy_label"),
- placeholder="proxy.txt",
- )
- self._proxy_drop.file_dropped.connect(self._on_proxy_file)
- layout.addWidget(self._proxy_drop)
-
- # --- Секция экспорта (выключена до завершения проверки) ---
- self._export_group = QGroupBox()
- self._export_group.setEnabled(False)
- export_layout = QVBoxLayout(self._export_group)
-
- # Галочки секций (Summary экспортируется из таблицы результатов слева)
- cb_row = QHBoxLayout()
- self._cb_tokens = QCheckBox()
- for cb in (self._cb_tokens,):
- cb.setChecked(True)
- cb_row.addWidget(cb)
- export_layout.addLayout(cb_row)
-
- # Фильтр токенов — выпадающий список (заполняется после проверки)
- token_row = QHBoxLayout()
- self._lbl_tokens_filter = QLabel()
- token_row.addWidget(self._lbl_tokens_filter)
- self._filter_tokens = QComboBox()
- self._filter_tokens.setEditable(False)
- self._filter_tokens.setMinimumWidth(160)
- token_row.addWidget(self._filter_tokens)
- export_layout.addLayout(token_row)
-
- # Кнопки экспорта
- btn_row = QHBoxLayout()
- self._btn_csv = QPushButton("CSV")
- self._btn_json = QPushButton("JSON")
- self._btn_xlsx = QPushButton("XLSX")
- self._btn_csv.clicked.connect(lambda: self._on_export("csv"))
- self._btn_json.clicked.connect(lambda: self._on_export("json"))
- self._btn_xlsx.clicked.connect(lambda: self._on_export("xlsx"))
- btn_row.addWidget(self._btn_csv)
- btn_row.addWidget(self._btn_json)
- btn_row.addWidget(self._btn_xlsx)
- export_layout.addLayout(btn_row)
-
- layout.addWidget(self._export_group)
- layout.addStretch()
-
- self.retranslate_ui()
- i18n.language_changed.connect(self.retranslate_ui)
-
- def retranslate_ui(self) -> None:
- self._wallet_drop.set_label(tr("wallets_label"))
- self._proxy_drop.set_label(tr("proxy_label"))
- self._export_group.setTitle(tr("export_group"))
- self._cb_tokens.setText(tr("tokens_checkbox"))
- self._lbl_tokens_filter.setText(tr("tokens_filter_label"))
-
- # --- Загрузка файлов ---
-
- def _on_wallet_file(self, path: str) -> None:
- try:
- parsed = parse_wallets(path)
- self._wallets = [w["raw"] for w in parsed if w["type"] == "address"]
- self._wallet_drop.set_status(tr("n_addresses_loaded").format(n=len(self._wallets)))
- except Exception as e:
- self._wallets = []
- self._wallet_drop.set_status(tr("error_fmt").format(e=e))
-
- def _on_proxy_file(self, path: str) -> None:
- try:
- self._proxies = parse_proxies(path)
- self._proxy_drop.set_status(tr("n_proxies_loaded").format(n=len(self._proxies)))
- except Exception as e:
- self._proxies = []
- self._proxy_drop.set_status(tr("error_fmt").format(e=e))
-
- def get_wallets(self) -> list[str]:
- return self._wallets
-
- def get_proxies(self) -> list[ProxyConfig]:
- return self._proxies
-
- # --- Экспорт ---
-
- def on_run_complete(self, results: list, details: dict) -> None:
- """Слот: вызывается Qt через queued connection после завершения run()."""
- self._export_results = results
- self._export_details = details
- self._export_group.setEnabled(True)
- # Собираем уникальные токены из кошельков для выпадающего списка
- token_keys: set[tuple[str, str]] = set()
- for addr_detail in details.values():
- for t in addr_detail.get("tokens_data", []):
- sym = (t.get("symbol") or "?").strip()
- ch = (t.get("chain") or "?").strip()
- if sym and ch:
- token_keys.add((sym, ch))
- self._filter_tokens.clear()
- self._filter_tokens.addItem(tr("all_tokens"), None)
- for sym, ch in sorted(token_keys):
- display = f"{sym} ({ch.capitalize()})"
- value = f"{sym}:{ch}"
- self._filter_tokens.addItem(display, value)
-
- def _build_config(self):
- from app.storage.evm_exporter import EvmExportConfig
- token_filter = self._filter_tokens.currentData()
- return EvmExportConfig(
- summary=False,
- tokens=self._cb_tokens.isChecked(),
- token_filter=token_filter,
- )
-
- def _on_export(self, fmt: str) -> None:
- if not self._export_results:
- return
- config = self._build_config()
- extensions = {
- "csv": (tr("save_csv"), "evm_results.csv", "CSV (*.csv)"),
- "json": (tr("save_json"), "evm_results.json", "JSON (*.json)"),
- "xlsx": (tr("save_xlsx"), "evm_results.xlsx", "Excel (*.xlsx)"),
- }
- title, default_name, file_filter = extensions[fmt]
- path, _ = QFileDialog.getSaveFileName(self, title, default_name, file_filter)
- if not path:
- return
- from app.storage.evm_exporter import EvmExporter
- EvmExporter().export(self._export_results, self._export_details, config, path, fmt)
diff --git a/app/ui/module_views/placeholder_view.py b/app/ui/module_views/placeholder_view.py
deleted file mode 100644
index 2d37836..0000000
--- a/app/ui/module_views/placeholder_view.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from PySide6.QtWidgets import QLabel, QVBoxLayout, QWidget
-from PySide6.QtCore import Qt
-from app.i18n import tr, i18n
-
-
-class PlaceholderView(QWidget):
- """Заглушка панели настроек для модулей без реализации."""
-
- def __init__(self, module_name: str, parent=None) -> None:
- super().__init__(parent)
- self._module_name = module_name
- self._label = QLabel()
- self._label.setAlignment(Qt.AlignCenter)
- layout = QVBoxLayout(self)
- layout.addWidget(self._label)
- i18n.language_changed.connect(self.retranslate_ui)
- self.retranslate_ui()
-
- def retranslate_ui(self) -> None:
- self._label.setText(tr("placeholder_module_msg").format(module_name=self._module_name))
diff --git a/app/ui/module_views/proxy_checker_view.py b/app/ui/module_views/proxy_checker_view.py
deleted file mode 100644
index ffca9d3..0000000
--- a/app/ui/module_views/proxy_checker_view.py
+++ /dev/null
@@ -1,45 +0,0 @@
-from __future__ import annotations
-from PySide6.QtWidgets import QWidget, QVBoxLayout
-from app.ui.widgets.drop_zone import DropZone
-from app.core.models import ProxyConfig
-from app.storage.parsers import parse_proxies
-from app.i18n import tr, i18n
-
-
-class ProxyCheckerConfigWidget(QWidget):
- """Панель настроек модуля Proxy Checker: выбор файла прокси."""
-
- def __init__(self, parent=None) -> None:
- super().__init__(parent)
- self._proxies: list[ProxyConfig] = []
-
- layout = QVBoxLayout(self)
- layout.setContentsMargins(16, 16, 16, 16)
- layout.setSpacing(8)
-
- self._proxy_drop = DropZone(
- label=tr("proxy_label"),
- placeholder="proxies.txt",
- )
- self._proxy_drop.file_dropped.connect(self._on_proxy_file)
- layout.addWidget(self._proxy_drop)
-
- layout.addStretch()
-
- self.retranslate_ui()
- i18n.language_changed.connect(self.retranslate_ui)
-
- def retranslate_ui(self) -> None:
- self._proxy_drop.set_label(tr("proxy_label"))
-
- def _on_proxy_file(self, path: str) -> None:
- try:
- self._proxies = parse_proxies(path)
- self._proxy_drop.set_status(tr("n_proxies_loaded").format(n=len(self._proxies)))
- except Exception as e:
- self._proxies = []
- self._proxy_drop.set_status(tr("error_fmt").format(e=e))
-
- def get_proxies(self) -> list[ProxyConfig]:
- """Возвращает список прокси."""
- return self._proxies
diff --git a/app/ui/module_views/svm_balance_view.py b/app/ui/module_views/svm_balance_view.py
deleted file mode 100644
index 08d5f12..0000000
--- a/app/ui/module_views/svm_balance_view.py
+++ /dev/null
@@ -1,165 +0,0 @@
-from __future__ import annotations
-
-from PySide6.QtWidgets import (
- QWidget, QVBoxLayout, QHBoxLayout, QGroupBox,
- QLabel, QLineEdit, QFileDialog, QComboBox, QPushButton,
-)
-
-from app.ui.widgets.drop_zone import DropZone
-from app.core.models import ProxyConfig, Result
-from app.storage.parsers import parse_lines, parse_proxies
-from app.i18n import tr, i18n
-
-DEFAULT_RPC_URL = "https://api.mainnet-beta.solana.com"
-
-
-class SvmBalanceConfigWidget(QWidget):
- """Config panel for the SVM Balance module: file inputs + export section."""
-
- def __init__(self, parent=None) -> None:
- super().__init__(parent)
- self._wallets: list[str] = []
- self._proxies: list[ProxyConfig] = []
- self._export_results: list[Result] = []
- self._export_details: dict = {}
-
- layout = QVBoxLayout(self)
- layout.setContentsMargins(16, 16, 16, 16)
- layout.setSpacing(8)
-
- # --- Кошельки ---
- self._wallet_drop = DropZone(
- label=tr("wallets_label"),
- placeholder="wallets.txt",
- )
- self._wallet_drop.file_dropped.connect(self._on_wallet_file)
- layout.addWidget(self._wallet_drop)
-
- # --- Прокси ---
- self._proxy_drop = DropZone(
- label=tr("proxy_label"),
- placeholder="proxy.txt",
- )
- self._proxy_drop.file_dropped.connect(self._on_proxy_file)
- layout.addWidget(self._proxy_drop)
-
- # --- RPC URL ---
- self._lbl_rpc = QLabel()
- layout.addWidget(self._lbl_rpc)
- self._rpc_url_input = QLineEdit(DEFAULT_RPC_URL)
- layout.addWidget(self._rpc_url_input)
-
- # --- Экспорт ---
- self._export_group = QGroupBox()
- self._export_group.setEnabled(False)
- export_layout = QVBoxLayout(self._export_group)
-
- token_row = QHBoxLayout()
- self._lbl_tokens = QLabel()
- token_row.addWidget(self._lbl_tokens)
- self._filter_tokens = QComboBox()
- self._filter_tokens.setEditable(False)
- self._filter_tokens.setMinimumWidth(160)
- token_row.addWidget(self._filter_tokens)
- export_layout.addLayout(token_row)
-
- btn_row = QHBoxLayout()
- self._btn_csv = QPushButton("CSV")
- self._btn_json = QPushButton("JSON")
- self._btn_xlsx = QPushButton("XLSX")
- self._btn_csv.clicked.connect(lambda: self._on_export("csv"))
- self._btn_json.clicked.connect(lambda: self._on_export("json"))
- self._btn_xlsx.clicked.connect(lambda: self._on_export("xlsx"))
- btn_row.addWidget(self._btn_csv)
- btn_row.addWidget(self._btn_json)
- btn_row.addWidget(self._btn_xlsx)
- export_layout.addLayout(btn_row)
-
- layout.addWidget(self._export_group)
- layout.addStretch()
-
- self.retranslate_ui()
- i18n.language_changed.connect(self.retranslate_ui)
-
- def retranslate_ui(self) -> None:
- self._wallet_drop.set_label(tr("wallets_label"))
- self._proxy_drop.set_label(tr("proxy_label"))
- self._lbl_rpc.setText(tr("rpc_url_label"))
- self._export_group.setTitle(tr("export_group"))
- self._lbl_tokens.setText(tr("tokens_filter_label"))
-
- # --- File loading ---
-
- def _on_wallet_file(self, path: str) -> None:
- try:
- self._wallets = parse_lines(path)
- self._wallet_drop.set_status(tr("n_addresses_loaded").format(n=len(self._wallets)))
- except Exception as e:
- self._wallets = []
- self._wallet_drop.set_status(tr("error_fmt").format(e=e))
-
- def _on_proxy_file(self, path: str) -> None:
- try:
- self._proxies = parse_proxies(path)
- self._proxy_drop.set_status(tr("n_proxies_loaded").format(n=len(self._proxies)))
- except Exception as e:
- self._proxies = []
- self._proxy_drop.set_status(tr("error_fmt").format(e=e))
-
- # --- Accessors ---
-
- def get_wallets(self) -> list[str]:
- return self._wallets
-
- def get_proxies(self) -> list[ProxyConfig]:
- return self._proxies
-
- def get_rpc_url(self) -> str:
- return self._rpc_url_input.text().strip() or DEFAULT_RPC_URL
-
- # --- Run complete slot ---
-
- def on_run_complete(self, results: list[Result], details: dict) -> None:
- """Called via Qt queued connection after module.run() finishes."""
- self._export_results = results
- self._export_details = details
- self._export_group.setEnabled(True)
-
- # Populate token filter combobox with unique symbols
- symbols: set[str] = set()
- for addr_detail in details.values():
- for t in addr_detail.get("tokens_data", []):
- sym = (t.get("symbol") or "").strip()
- if sym:
- symbols.add(sym)
-
- self._filter_tokens.clear()
- self._filter_tokens.addItem(tr("all_tokens"), None)
- for sym in sorted(symbols):
- self._filter_tokens.addItem(sym, sym)
-
- # --- Export ---
-
- def _build_config(self):
- from app.storage.svm_exporter import SvmExportConfig
- return SvmExportConfig(
- summary=True,
- tokens=True,
- token_filter=self._filter_tokens.currentData(),
- )
-
- def _on_export(self, fmt: str) -> None:
- if not self._export_results:
- return
- config = self._build_config()
- extensions = {
- "csv": (tr("save_csv"), "svm_results.csv", "CSV (*.csv)"),
- "json": (tr("save_json"), "svm_results.json", "JSON (*.json)"),
- "xlsx": (tr("save_xlsx"), "svm_results.xlsx", "Excel (*.xlsx)"),
- }
- title, default_name, file_filter = extensions[fmt]
- path, _ = QFileDialog.getSaveFileName(self, title, default_name, file_filter)
- if not path:
- return
- from app.storage.svm_exporter import SvmExporter
- SvmExporter().export(self._export_results, self._export_details, config, path, fmt)
diff --git a/app/ui/module_views/twitter_checker_view.py b/app/ui/module_views/twitter_checker_view.py
deleted file mode 100644
index d3edf92..0000000
--- a/app/ui/module_views/twitter_checker_view.py
+++ /dev/null
@@ -1,134 +0,0 @@
-from __future__ import annotations
-from PySide6.QtWidgets import (
- QWidget, QVBoxLayout, QHBoxLayout, QGroupBox,
- QLabel, QFileDialog, QComboBox, QPushButton,
-)
-from app.ui.widgets.drop_zone import DropZone
-from app.core.models import ProxyConfig
-from app.storage.parsers import parse_proxies, parse_lines
-from app.i18n import tr, i18n
-
-
-class TwitterCheckerConfigWidget(QWidget):
- """Config panel for Twitter Checker module."""
-
- def __init__(self, parent=None) -> None:
- super().__init__(parent)
- self._tokens: list[str] = []
- self._proxies: list[ProxyConfig] = []
- self._export_results: list = []
-
- layout = QVBoxLayout(self)
- layout.setContentsMargins(16, 16, 16, 16)
- layout.setSpacing(8)
-
- # --- Tokens ---
- self._token_drop = DropZone(
- label=tr("tokens_label_checker"),
- placeholder="tokens.txt",
- )
- self._token_drop.file_dropped.connect(self._on_token_file)
- layout.addWidget(self._token_drop)
-
- # --- Proxies ---
- self._proxy_drop = DropZone(
- label=tr("proxy_label_checker"),
- placeholder="proxy.txt",
- )
- self._proxy_drop.file_dropped.connect(self._on_proxy_file)
- layout.addWidget(self._proxy_drop)
-
- # --- Export (disabled until run completes) ---
- self._export_group = QGroupBox()
- self._export_group.setEnabled(False)
- export_layout = QVBoxLayout(self._export_group)
-
- filter_row = QHBoxLayout()
- self._lbl_status = QLabel()
- filter_row.addWidget(self._lbl_status)
- self._status_combo = QComboBox()
- self._status_combo.addItem(tr("filter_all"), None)
- for s in ("ok", "invalid", "suspended", "locked"):
- self._status_combo.addItem(s, s)
- filter_row.addWidget(self._status_combo)
- filter_row.addSpacing(16)
- self._lbl_format = QLabel()
- filter_row.addWidget(self._lbl_format)
- self._fmt_combo = QComboBox()
- for fmt in ("xlsx", "csv", "json"):
- self._fmt_combo.addItem(fmt, fmt)
- filter_row.addWidget(self._fmt_combo)
- filter_row.addStretch()
- export_layout.addLayout(filter_row)
-
- self._export_btn = QPushButton()
- self._export_btn.clicked.connect(self._on_export)
- export_layout.addWidget(self._export_btn)
-
- layout.addWidget(self._export_group)
- layout.addStretch()
-
- self.retranslate_ui()
- i18n.language_changed.connect(self.retranslate_ui)
-
- def retranslate_ui(self) -> None:
- self._token_drop.set_label(tr("tokens_label_checker"))
- self._proxy_drop.set_label(tr("proxy_label_checker"))
- self._export_group.setTitle(tr("export_group"))
- self._lbl_status.setText(tr("status_label"))
- self._lbl_format.setText(tr("format_label"))
- self._export_btn.setText(tr("export_btn"))
- self._status_combo.setItemText(0, tr("filter_all"))
-
- # --- File loading ---
-
- def _on_token_file(self, path: str) -> None:
- try:
- self._tokens = parse_lines(path)
- self._token_drop.set_status(tr("n_tokens_loaded").format(n=len(self._tokens)))
- except Exception as e:
- self._tokens = []
- self._token_drop.set_status(tr("error_fmt").format(e=e))
-
- def _on_proxy_file(self, path: str) -> None:
- try:
- self._proxies = parse_proxies(path)
- self._proxy_drop.set_status(tr("n_proxies_loaded").format(n=len(self._proxies)))
- except Exception as e:
- self._proxies = []
- self._proxy_drop.set_status(tr("error_fmt").format(e=e))
-
- # --- Accessors (called by module) ---
-
- def get_tokens(self) -> list[str]:
- return self._tokens
-
- def get_proxies(self) -> list[ProxyConfig]:
- return self._proxies
-
- def on_run_complete(self, results: list) -> None:
- """Slot: called via Qt queued connection after run() finishes."""
- self._export_results = results
- self._export_group.setEnabled(True)
-
- # --- Export ---
-
- def _on_export(self) -> None:
- if not self._export_results:
- return
- from app.storage.twitter_exporter import TwitterExporter, TwitterExportConfig
-
- status_filter = self._status_combo.currentData()
- fmt = self._fmt_combo.currentData()
- config = TwitterExportConfig(status_filter=status_filter)
-
- extensions = {
- "csv": (tr("save_csv"), "twitter_results.csv", "CSV (*.csv)"),
- "json": (tr("save_json"), "twitter_results.json", "JSON (*.json)"),
- "xlsx": (tr("save_xlsx"), "twitter_results.xlsx", "Excel (*.xlsx)"),
- }
- title, default_name, file_filter = extensions[fmt]
- path, _ = QFileDialog.getSaveFileName(self, title, default_name, file_filter)
- if not path:
- return
- TwitterExporter().export(self._export_results, config, path, fmt)
diff --git a/app/ui/results_table.py b/app/ui/results_table.py
deleted file mode 100644
index a509e18..0000000
--- a/app/ui/results_table.py
+++ /dev/null
@@ -1,232 +0,0 @@
-from __future__ import annotations
-
-from PySide6.QtWidgets import (
- QWidget, QVBoxLayout, QHBoxLayout, QTableWidget, QTableWidgetItem,
- QLineEdit, QPushButton, QHeaderView, QLabel, QComboBox, QStackedWidget,
-)
-from PySide6.QtCore import Qt
-from PySide6.QtGui import QColor
-
-from app.core.models import Result, ResultStatus
-from app.storage.exporters import get_columns, CsvExporter, JsonExporter, XlsxExporter
-from app.ui.widgets.empty_state import EmptyState
-from app.i18n import tr, i18n
-
-# Status colors
-_STATUS_COLORS = {
- "ok": QColor("#30D158"),
- "error": QColor("#FF453A"),
- "skip": QColor("#F0C040"),
-}
-
-_STATUS_BG = {
- "ok": QColor(48, 209, 88, 25),
- "error": QColor(255, 69, 58, 25),
- "skip": QColor(240, 192, 64, 25),
-}
-
-_ALT_ROW_COLOR = QColor(255, 255, 255, 6)
-
-
-class ResultsTable(QWidget):
- """Таблица результатов с поиском, фильтром, статус-бейджами и empty state."""
-
- def __init__(self, parent=None) -> None:
- super().__init__(parent)
- self._results: list[Result] = []
- self._columns: list[str] = ["item", "status"]
-
- # Search bar
- self._search = QLineEdit()
- self._search.setObjectName("resultsSearch")
- self._search.setClearButtonEnabled(True)
- self._search.textChanged.connect(self._apply_filter)
-
- # Table
- self._table = QTableWidget()
- self._table.setAlternatingRowColors(True)
- self._table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
- self._table.verticalHeader().setVisible(False)
- self._table.setSelectionBehavior(QTableWidget.SelectRows)
- self._table.setShowGrid(False)
-
- # Empty state
- self._empty = EmptyState(
- icon_text="📋",
- title=tr("empty_results_title"),
- subtitle=tr("empty_results_subtitle"),
- )
-
- # Stacked: empty ↔ table
- self._stack = QStackedWidget()
- self._stack.addWidget(self._empty) # index 0
- self._stack.addWidget(self._table) # index 1
- self._stack.setCurrentIndex(0)
-
- # Quality filter
- self._quality_filter = QComboBox()
- self._quality_filter.addItem(tr("filter_all"), "all")
- for q in ("high", "medium", "low"):
- self._quality_filter.addItem(q, q)
- self._quality_filter.setVisible(False)
-
- # Export buttons
- self._export_csv = QPushButton()
- self._export_json = QPushButton()
- self._export_xlsx = QPushButton()
- self._export_csv.clicked.connect(self._on_export_csv)
- self._export_json.clicked.connect(self._on_export_json)
- self._export_xlsx.clicked.connect(self._on_export_xlsx)
- self._export_csv.setVisible(False)
- self._export_json.setVisible(False)
- self._export_xlsx.setVisible(False)
-
- # Footer stats
- self._total_label = QLabel("")
- self._total_label.setVisible(False)
- self._stats_label = QLabel("")
- self._stats_label.setObjectName("statsLabel")
- self._stats_label.setVisible(False)
-
- btn_row = QHBoxLayout()
- btn_row.addWidget(self._quality_filter)
- btn_row.addWidget(self._export_csv)
- btn_row.addWidget(self._export_json)
- btn_row.addWidget(self._export_xlsx)
- btn_row.addStretch()
- btn_row.addWidget(self._stats_label)
- btn_row.addWidget(self._total_label)
-
- layout = QVBoxLayout(self)
- layout.setContentsMargins(0, 0, 0, 0)
- layout.addWidget(self._search)
- layout.addWidget(self._stack)
- layout.addLayout(btn_row)
-
- self.retranslate_ui()
- i18n.language_changed.connect(self.retranslate_ui)
-
- def retranslate_ui(self) -> None:
- self._search.setPlaceholderText(tr("search_placeholder"))
- self._export_csv.setText(tr("export_csv_btn"))
- self._export_json.setText(tr("export_json_btn"))
- self._export_xlsx.setText(tr("export_xlsx_btn"))
- self._quality_filter.setItemText(0, tr("filter_all"))
- self._empty.set_texts(
- title=tr("empty_results_title"),
- subtitle=tr("empty_results_subtitle"),
- )
-
- def add_row(self, result: Result) -> None:
- self._results.append(result)
- self._stack.setCurrentIndex(1) # show table
-
- if not self._table.columnCount() or (result.data and self._columns == ["item", "status"]):
- self._columns = get_columns(self._results)
- self._table.setColumnCount(len(self._columns))
- self._table.setHorizontalHeaderLabels(self._columns)
-
- row = self._table.rowCount()
- self._table.insertRow(row)
- row_data = {"item": result.item, "status": result.status.value}
- row_data.update(result.data)
-
- for col_idx, col in enumerate(self._columns):
- cell_text = str(row_data.get(col, ""))
- item = QTableWidgetItem(cell_text)
- item.setTextAlignment(Qt.AlignCenter)
-
- # Color status column
- if col == "status":
- status_val = result.status.value
- fg = _STATUS_COLORS.get(status_val)
- bg = _STATUS_BG.get(status_val)
- if fg:
- item.setForeground(fg)
- if bg:
- item.setBackground(bg)
-
- self._table.setItem(row, col_idx, item)
-
- if any(r.data.get("quality") for r in self._results):
- self._quality_filter.setVisible(True)
- self._export_csv.setVisible(True)
- self._export_json.setVisible(True)
- self._export_xlsx.setVisible(True)
- self._update_total()
- self._update_stats()
-
- def _update_total(self) -> None:
- total = sum(r.data.get("total_usd", 0) for r in self._results if r.data)
- if total > 0:
- self._total_label.setText(tr("total_fmt").format(total=total))
- self._total_label.setVisible(True)
- else:
- self._total_label.setVisible(False)
-
- def _update_stats(self) -> None:
- ok = sum(1 for r in self._results if r.status == ResultStatus.OK)
- err = sum(1 for r in self._results if r.status == ResultStatus.ERROR)
- skip = sum(1 for r in self._results if r.status == ResultStatus.SKIP)
- parts = [f"✓ {ok}"]
- if err:
- parts.append(f"✗ {err}")
- if skip:
- parts.append(f"⊘ {skip}")
- self._stats_label.setText(" │ ".join(parts))
- self._stats_label.setVisible(True)
-
- def snapshot(self) -> list[Result]:
- return list(self._results)
-
- def restore(self, results: list[Result]) -> None:
- self.clear_results()
- for r in results:
- self.add_row(r)
-
- def clear_results(self) -> None:
- self._results.clear()
- self._table.setRowCount(0)
- self._table.setColumnCount(0)
- self._columns = ["item", "status"]
- self._quality_filter.setCurrentIndex(0)
- self._quality_filter.setVisible(False)
- self._export_csv.setVisible(False)
- self._export_json.setVisible(False)
- self._export_xlsx.setVisible(False)
- self._total_label.setVisible(False)
- self._stats_label.setVisible(False)
- self._stack.setCurrentIndex(0) # show empty state
-
- def _apply_filter(self, text: str) -> None:
- text = text.lower()
- for row in range(self._table.rowCount()):
- match = any(
- text in (self._table.item(row, col).text().lower() if self._table.item(row, col) else "")
- for col in range(self._table.columnCount())
- )
- self._table.setRowHidden(row, not match)
-
- def _filtered_results(self) -> list[Result]:
- quality = self._quality_filter.currentData()
- if quality == "all":
- return self._results
- return [r for r in self._results if r.data.get("quality") == quality]
-
- def _on_export_csv(self) -> None:
- from PySide6.QtWidgets import QFileDialog
- path, _ = QFileDialog.getSaveFileName(self, tr("save_csv"), "results.csv", "CSV (*.csv)")
- if path:
- CsvExporter().export(self._filtered_results(), path)
-
- def _on_export_json(self) -> None:
- from PySide6.QtWidgets import QFileDialog
- path, _ = QFileDialog.getSaveFileName(self, tr("save_json"), "results.json", "JSON (*.json)")
- if path:
- JsonExporter().export(self._filtered_results(), path)
-
- def _on_export_xlsx(self) -> None:
- from PySide6.QtWidgets import QFileDialog
- path, _ = QFileDialog.getSaveFileName(self, tr("save_xlsx"), "results.xlsx", "Excel (*.xlsx)")
- if path:
- XlsxExporter().export(self._filtered_results(), path)
diff --git a/app/ui/segmented_tabs.py b/app/ui/segmented_tabs.py
deleted file mode 100644
index 8d320d6..0000000
--- a/app/ui/segmented_tabs.py
+++ /dev/null
@@ -1,56 +0,0 @@
-from __future__ import annotations
-
-from PySide6.QtCore import Signal
-from PySide6.QtWidgets import QButtonGroup, QHBoxLayout, QToolButton, QWidget
-
-from app.core.base_module import BaseModule
-
-
-class SegmentedModuleTabs(QWidget):
- module_selected = Signal(object) # BaseModule
-
- def __init__(self, modules: list[BaseModule], parent: QWidget | None = None) -> None:
- super().__init__(parent)
- self._modules = list(modules)
- self._buttons: list[QToolButton] = []
-
- layout = QHBoxLayout(self)
- layout.setContentsMargins(0, 0, 0, 0)
- layout.setSpacing(0)
-
- self._group = QButtonGroup(self)
- self._group.setExclusive(True)
- self._group.idClicked.connect(self._on_id_clicked)
-
- self.setProperty("segmented", True)
-
- for idx, module in enumerate(self._modules):
- btn = QToolButton(self)
- btn.setText(module.name)
- btn.setCheckable(True)
- btn.setAutoExclusive(True)
- btn.setProperty("segmentedItem", True)
- self._group.addButton(btn, idx)
- self._buttons.append(btn)
- layout.addWidget(btn)
-
- if self._buttons:
- self._buttons[0].setChecked(True)
-
- def set_current_index(self, idx: int) -> None:
- if idx < 0 or idx >= len(self._buttons):
- return
- self._buttons[idx].setChecked(True)
- self.module_selected.emit(self._modules[idx])
-
- def current_module(self) -> BaseModule | None:
- checked_id = self._group.checkedId()
- if checked_id < 0:
- return None
- if checked_id >= len(self._modules):
- return None
- return self._modules[checked_id]
-
- def _on_id_clicked(self, idx: int) -> None:
- if 0 <= idx < len(self._modules):
- self.module_selected.emit(self._modules[idx])
diff --git a/app/ui/sidebar.py b/app/ui/sidebar.py
deleted file mode 100644
index ad456df..0000000
--- a/app/ui/sidebar.py
+++ /dev/null
@@ -1,166 +0,0 @@
-from __future__ import annotations
-
-from pathlib import Path
-
-from PySide6.QtCore import (
- Qt, Signal, QSize, QPropertyAnimation, QEasingCurve, Property,
-)
-from PySide6.QtGui import QIcon, QColor, QPainter
-from PySide6.QtWidgets import (
- QWidget, QVBoxLayout, QPushButton, QLabel, QSizePolicy,
-)
-
-from app.core.base_module import BaseModule
-from app.i18n import tr, i18n
-
-_ICONS_DIR = Path(__file__).parent / "theme" / "icons"
-
-# Map module name → icon filename (without extension)
-_MODULE_ICON: dict[str, str] = {
- "EVM Balance": "evm",
- "SVM Balance": "svm",
- "Collector": "collector",
- "Proxy Check": "proxy",
- "Twitter Checker": "twitter",
- "Discord Checker": "discord",
-}
-
-
-class _SidebarButton(QPushButton):
- """One sidebar button: icon + text + status indicator."""
-
- def __init__(self, module: BaseModule, parent: QWidget | None = None) -> None:
- super().__init__(parent)
- self.module = module
- self.setCheckable(True)
- self.setObjectName("sidebarButton")
- self.setCursor(Qt.PointingHandCursor)
-
- icon_file = _ICONS_DIR / f"{_MODULE_ICON.get(module.name, 'evm')}.svg"
- if icon_file.exists():
- self.setIcon(QIcon(str(icon_file)))
- self.setIconSize(QSize(22, 22))
-
- self.setText(module.name)
- self._status: str = "" # "", "running", "done", "error"
-
- def set_status(self, status: str) -> None:
- self._status = status
- self.setProperty("runStatus", status)
- self.style().unpolish(self)
- self.style().polish(self)
- self.update()
-
- def paintEvent(self, event):
- super().paintEvent(event)
- if not self._status:
- return
- painter = QPainter(self)
- painter.setRenderHint(QPainter.Antialiasing)
- colors = {
- "running": QColor("#F0C040"),
- "done": QColor("#30D158"),
- "error": QColor("#FF453A"),
- }
- color = colors.get(self._status)
- if color:
- painter.setBrush(color)
- painter.setPen(Qt.NoPen)
- x = self.width() - 14
- y = 8
- painter.drawEllipse(x, y, 8, 8)
- painter.end()
-
-
-class Sidebar(QWidget):
- """Vertical sidebar with module icons, collapse animation, and status badges."""
-
- module_selected = Signal(object) # BaseModule
- EXPANDED_WIDTH = 180
- COLLAPSED_WIDTH = 56
-
- def __init__(self, modules: list[BaseModule], parent: QWidget | None = None) -> None:
- super().__init__(parent)
- self.setObjectName("sidebar")
- self._modules = modules
- self._buttons: list[_SidebarButton] = []
- self._expanded = True
-
- self.setFixedWidth(self.EXPANDED_WIDTH)
- self.setMinimumHeight(200)
-
- layout = QVBoxLayout(self)
- layout.setContentsMargins(8, 12, 8, 12)
- layout.setSpacing(4)
-
- # Logo / title
- self._title = QLabel("FarmerPro")
- self._title.setObjectName("sidebarTitle")
- self._title.setAlignment(Qt.AlignCenter)
- layout.addWidget(self._title)
- layout.addSpacing(12)
-
- # Module buttons
- for module in modules:
- btn = _SidebarButton(module, self)
- btn.clicked.connect(lambda checked, m=module, b=btn: self._on_clicked(m, b))
- self._buttons.append(btn)
- layout.addWidget(btn)
-
- layout.addStretch()
-
- # Collapse toggle
- self._toggle_btn = QPushButton("◀")
- self._toggle_btn.setObjectName("sidebarToggle")
- self._toggle_btn.setFixedSize(32, 32)
- self._toggle_btn.setCursor(Qt.PointingHandCursor)
- self._toggle_btn.clicked.connect(self._toggle_collapse)
- layout.addWidget(self._toggle_btn, alignment=Qt.AlignCenter)
-
- # Select first module
- if self._buttons:
- self._buttons[0].setChecked(True)
-
- # Animation
- self._anim = QPropertyAnimation(self, b"fixedWidth")
- self._anim.setDuration(200)
- self._anim.setEasingCurve(QEasingCurve.InOutCubic)
-
- def _on_clicked(self, module: BaseModule, btn: _SidebarButton) -> None:
- for b in self._buttons:
- if b is not btn:
- b.setChecked(False)
- btn.setChecked(True)
- self.module_selected.emit(module)
-
- def _toggle_collapse(self) -> None:
- self._expanded = not self._expanded
- target = self.EXPANDED_WIDTH if self._expanded else self.COLLAPSED_WIDTH
- self._anim.setStartValue(self.width())
- self._anim.setEndValue(target)
- self._anim.start()
- self._toggle_btn.setText("◀" if self._expanded else "▶")
- for btn in self._buttons:
- btn.setText(btn.module.name if self._expanded else "")
- self._title.setVisible(self._expanded)
-
- def set_module_status(self, module: BaseModule, status: str) -> None:
- """Set module status: 'running', 'done', 'error', '' (clear)."""
- for btn in self._buttons:
- if btn.module is module:
- btn.set_status(status)
- break
-
- def select_module(self, index: int) -> None:
- """Programmatically select a module by index."""
- if 0 <= index < len(self._buttons):
- self._buttons[index].click()
-
- # Animated fixedWidth property for QPropertyAnimation
- def _get_fixed_width(self) -> int:
- return self.width()
-
- def _set_fixed_width(self, w: int) -> None:
- self.setFixedWidth(w)
-
- fixedWidth = Property(int, _get_fixed_width, _set_fixed_width)
diff --git a/app/ui/theme.py b/app/ui/theme.py
deleted file mode 100644
index 5a7c5ea..0000000
--- a/app/ui/theme.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from __future__ import annotations
-
-from pathlib import Path
-
-
-def _theme_path() -> Path:
- return Path(__file__).resolve().parent / "theme" / "apple_dark.qss"
-
-
-def _theme_dir_qss_path() -> str:
- # QSS стабильнее работает с абсолютными путями вида C:/... чем с file:///...
- return _theme_path().parent.resolve().as_posix()
-
-
-def load_apple_dark_qss() -> str:
- qss = _theme_path().read_text(encoding="utf-8")
- return qss.replace("__THEME_DIR__", _theme_dir_qss_path())
-
-
-def apply_apple_dark_theme(app) -> None:
- """
- Applies the global Apple-like dark theme to the QApplication.
-
- `app` is intentionally untyped here to avoid importing Qt in non-Qt contexts.
- """
- app.setStyleSheet(load_apple_dark_qss())
diff --git a/app/ui/theme/apple_dark.qss b/app/ui/theme/apple_dark.qss
deleted file mode 100644
index 155c194..0000000
--- a/app/ui/theme/apple_dark.qss
+++ /dev/null
@@ -1,580 +0,0 @@
-/* Apple-like dark theme (QSS) — single source of truth */
-
-/* Base */
-QMainWindow,
-QWidget {
- background: #0B0B0F;
- color: rgba(245,245,247,0.92);
- font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display",
- "Segoe UI Variable", "Segoe UI", sans-serif;
- font-size: 10pt;
-}
-
-/* Containers by objectName */
-#topToolbar {
- background: #121217;
- border-bottom: 1px solid rgba(255,255,255,0.07);
-}
-
-#appTitle {
- font-weight: 650;
- font-size: 10pt;
- letter-spacing: 0.02em;
-}
-
-#resultsPane {
- background: #121217;
-}
-
-#inspectorPane {
- background: rgba(255,255,255,0.02);
- border-left: 1px solid rgba(255,255,255,0.07);
-}
-
-#logPane {
- background: rgba(255,255,255,0.02);
- border-top: 1px solid rgba(255,255,255,0.07);
-}
-
-/* ═══ Buttons — polished ═══ */
-QPushButton {
- background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
- stop:0 rgba(255,255,255,0.08), stop:1 rgba(255,255,255,0.04));
- border: 1px solid rgba(255,255,255,0.10);
- border-radius: 10px;
- padding: 7px 14px;
- font-weight: 600;
-}
-QPushButton:hover {
- background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
- stop:0 rgba(255,255,255,0.12), stop:1 rgba(255,255,255,0.07));
- border-color: rgba(255,255,255,0.14);
-}
-QPushButton:pressed {
- background: rgba(255,255,255,0.14);
-}
-QPushButton:disabled {
- background: rgba(255,255,255,0.03);
- color: rgba(245,245,247,0.30);
- border-color: rgba(255,255,255,0.05);
-}
-
-QPushButton[primary="true"] {
- background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
- stop:0 #1A8FFF, stop:1 #0A74E8);
- border-color: rgba(10,132,255,0.40);
- color: #FFFFFF;
-}
-QPushButton[primary="true"]:hover {
- background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
- stop:0 #409CFF, stop:1 #0A84FF);
-}
-QPushButton[primary="true"]:pressed {
- background: #0068D6;
-}
-
-/* Language toggle (EN / RU) */
-QPushButton[langToggle="true"] {
- background: rgba(255,255,255,0.04);
- border: 1px solid rgba(255,255,255,0.08);
- border-radius: 8px;
- padding: 4px 6px;
- font-size: 9pt;
- font-weight: 600;
- color: rgba(245,245,247,0.50);
-}
-QPushButton[langToggle="true"]:hover {
- background: rgba(255,255,255,0.08);
- color: rgba(245,245,247,0.75);
-}
-QPushButton[langToggle="true"]:checked {
- background: rgba(10,132,255,0.20);
- border-color: rgba(10,132,255,0.45);
- color: #0A84FF;
-}
-
-/* Segmented tabs (QToolButton) */
-QWidget[segmented="true"] {
- background: rgba(255,255,255,0.06);
- border: 1px solid rgba(255,255,255,0.10);
- border-radius: 12px;
- padding: 3px;
-}
-
-QToolButton[segmentedItem="true"] {
- background: transparent;
- border: none;
- border-radius: 10px;
- padding: 7px 10px;
- color: rgba(245,245,247,0.72);
- font-weight: 650;
-}
-QToolButton[segmentedItem="true"]:hover {
- background: rgba(255,255,255,0.06);
-}
-QToolButton[segmentedItem="true"]:checked {
- background: rgba(255,255,255,0.10);
- color: rgba(245,245,247,0.92);
-}
-
-/* Inputs */
-QLineEdit,
-QComboBox,
-QSpinBox,
-QDoubleSpinBox {
- background: rgba(255,255,255,0.06);
- border: 1px solid rgba(255,255,255,0.10);
- border-radius: 10px;
- padding: 6px 24px 6px 10px;
- selection-background-color: rgba(10,132,255,0.25);
-}
-
-QSpinBox::up-button,
-QDoubleSpinBox::up-button {
- subcontrol-origin: border;
- subcontrol-position: top right;
- width: 16px;
- height: 11px;
- background: rgba(255,255,255,0.03);
- border: none;
- border-left: 1px solid rgba(255,255,255,0.09);
- border-top-right-radius: 9px;
- margin: 1px 1px 0 0;
-}
-
-QSpinBox::down-button,
-QDoubleSpinBox::down-button {
- subcontrol-origin: border;
- subcontrol-position: bottom right;
- width: 16px;
- height: 11px;
- background: rgba(255,255,255,0.03);
- border: none;
- border-left: 1px solid rgba(255,255,255,0.09);
- border-bottom-right-radius: 9px;
- margin: 0 1px 1px 0;
-}
-
-QSpinBox::up-button:hover,
-QSpinBox::down-button:hover,
-QDoubleSpinBox::up-button:hover,
-QDoubleSpinBox::down-button:hover {
- background: rgba(255,255,255,0.065);
-}
-
-QSpinBox::up-button:pressed,
-QSpinBox::down-button:pressed,
-QDoubleSpinBox::up-button:pressed,
-QDoubleSpinBox::down-button:pressed {
- background: rgba(255,255,255,0.11);
-}
-
-QSpinBox::up-arrow,
-QDoubleSpinBox::up-arrow {
- image: url(__THEME_DIR__/up-arrow.svg);
- width: 7px;
- height: 5px;
-}
-
-QSpinBox::down-arrow,
-QDoubleSpinBox::down-arrow {
- image: url(__THEME_DIR__/down-arrow.svg);
- width: 7px;
- height: 5px;
-}
-QLineEdit:focus,
-QComboBox:focus,
-QSpinBox:focus,
-QDoubleSpinBox:focus,
-QPlainTextEdit:focus {
- border: 2px solid rgba(10,132,255,0.60);
-}
-
-/* ═══ GroupBox — glass card ═══ */
-QGroupBox {
- background: rgba(255,255,255,0.025);
- border: 1px solid rgba(255,255,255,0.08);
- border-radius: 12px;
- margin-top: 14px;
- padding: 12px 10px 8px 10px;
-}
-QGroupBox::title {
- subcontrol-origin: margin;
- subcontrol-position: top left;
- left: 12px;
- padding: 0 6px;
- color: rgba(245,245,247,0.55);
- font-size: 9pt;
- font-weight: 700;
- text-transform: uppercase;
- letter-spacing: 0.04em;
-}
-
-/* CheckBox */
-QCheckBox {
- spacing: 6px;
-}
-QCheckBox::indicator {
- width: 16px;
- height: 16px;
- border: 1px solid rgba(255,255,255,0.22);
- border-radius: 4px;
- background: rgba(255,255,255,0.06);
-}
-QCheckBox::indicator:checked {
- background: #0A84FF;
- border-color: #0A84FF;
-}
-QCheckBox::indicator:disabled {
- background: rgba(255,255,255,0.03);
- border-color: rgba(255,255,255,0.06);
-}
-
-/* Chain picker button — looks like an input field */
-QPushButton#chainPickerButton {
- background: rgba(255,255,255,0.06);
- border: 1px solid rgba(255,255,255,0.10);
- border-radius: 10px;
- padding: 6px 28px 6px 10px;
- font-weight: 400;
- color: rgba(245,245,247,0.92);
- text-align: left;
-}
-QPushButton#chainPickerButton:hover {
- background: rgba(255,255,255,0.09);
- border-color: rgba(255,255,255,0.14);
-}
-
-/* Chain picker popup */
-QFrame#chainPickerPopup {
- background: #1C1F28;
- border: 1px solid rgba(255,255,255,0.12);
- border-radius: 12px;
-}
-QFrame#chainPickerPopup QLineEdit {
- background: rgba(255,255,255,0.07);
- border: 1px solid rgba(255,255,255,0.10);
- border-radius: 8px;
- padding: 5px 10px;
-}
-QFrame#chainPickerPopup QListWidget {
- background: transparent;
- border: none;
- outline: none;
-}
-QFrame#chainPickerPopup QListWidget::item {
- padding: 4px 6px;
- border-radius: 6px;
- color: rgba(245,245,247,0.85);
-}
-QFrame#chainPickerPopup QListWidget::item:hover {
- background: rgba(255,255,255,0.06);
-}
-QFrame#chainPickerPopup QListWidget::item:selected {
- background: transparent;
-}
-
-QComboBox QAbstractItemView {
- background: #171A22;
- color: rgba(245,245,247,0.92);
- border: 1px solid rgba(255,255,255,0.10);
- selection-background-color: rgba(10,132,255,0.22);
-}
-
-/* ═══ Splitter — visible handles ═══ */
-QSplitter::handle {
- background: rgba(255,255,255,0.04);
- margin: 0;
-}
-QSplitter::handle:horizontal {
- width: 3px;
-}
-QSplitter::handle:vertical {
- height: 3px;
-}
-QSplitter::handle:hover {
- background: rgba(10,132,255,0.30);
-}
-QSplitter::handle:pressed {
- background: rgba(10,132,255,0.50);
-}
-
-/* Table */
-QTableWidget {
- background: transparent;
- gridline-color: rgba(255,255,255,0.06);
- border: 1px solid rgba(255,255,255,0.07);
- border-radius: 12px;
-}
-QHeaderView::section {
- background: rgba(255,255,255,0.03);
- color: rgba(245,245,247,0.72);
- padding: 8px 10px;
- border: none;
- border-bottom: 1px solid rgba(255,255,255,0.07);
- font-weight: 700;
-}
-QTableWidget::item {
- padding: 6px 8px;
-}
-QTableWidget::item:selected {
- background: rgba(10,132,255,0.20);
-}
-
-/* Log */
-QPlainTextEdit {
- background: transparent;
- border: none;
- font-family: ui-monospace, "SF Mono", Menlo, Consolas, "Cascadia Mono", monospace;
- font-size: 9pt;
- color: rgba(245,245,247,0.78);
-}
-
-/* ═══ Toast notifications ═══ */
-#toast {
- background: rgba(30,30,38,0.92);
- border: 1px solid rgba(255,255,255,0.10);
- border-radius: 12px;
- padding: 10px 20px;
- font-weight: 600;
- font-size: 10pt;
- color: rgba(245,245,247,0.90);
-}
-#toast[level="success"] {
- background: rgba(48,209,88,0.18);
- border-color: rgba(48,209,88,0.35);
- color: #30D158;
-}
-#toast[level="error"] {
- background: rgba(255,69,58,0.18);
- border-color: rgba(255,69,58,0.35);
- color: #FF453A;
-}
-#toast[level="warning"] {
- background: rgba(255,214,10,0.14);
- border-color: rgba(255,214,10,0.30);
- color: #FFD60A;
-}
-
-/* ═══ Empty State ═══ */
-#emptyState {
- background: transparent;
-}
-#emptyStateIcon {
- font-size: 36pt;
- color: rgba(245,245,247,0.25);
-}
-#emptyStateTitle {
- font-size: 12pt;
- font-weight: 600;
- color: rgba(245,245,247,0.55);
-}
-#emptyStateSubtitle {
- font-size: 9pt;
- color: rgba(245,245,247,0.35);
- max-width: 300px;
-}
-
-/* ═══ Drop Zone ═══ */
-#dropArea {
- background: rgba(255,255,255,0.02);
- border: 2px dashed rgba(255,255,255,0.12);
- border-radius: 10px;
- margin: 4px 0;
-}
-#dropArea:hover {
- border-color: rgba(10,132,255,0.40);
- background: rgba(10,132,255,0.04);
-}
-#dropZone[dragOver="true"] #dropArea {
- border-color: rgba(10,132,255,0.60);
- background: rgba(10,132,255,0.08);
-}
-#dropHint {
- color: rgba(245,245,247,0.35);
- font-size: 9pt;
-}
-#dropZoneStatus {
- font-size: 9pt;
- color: rgba(245,245,247,0.55);
-}
-
-/* ═══ Sidebar ═══ */
-#sidebar {
- background: #0F0F14;
- border-right: 1px solid rgba(255,255,255,0.07);
-}
-
-#sidebarTitle {
- font-weight: 700;
- font-size: 13pt;
- color: rgba(245,245,247,0.92);
- padding: 4px 0;
- letter-spacing: 0.03em;
-}
-
-#sidebarButton {
- background: transparent;
- border: none;
- border-radius: 10px;
- padding: 10px 12px;
- text-align: left;
- font-weight: 500;
- font-size: 10pt;
- color: rgba(245,245,247,0.55);
-}
-#sidebarButton:hover {
- background: rgba(255,255,255,0.06);
- color: rgba(245,245,247,0.80);
-}
-#sidebarButton:checked {
- background: rgba(10,132,255,0.15);
- color: #0A84FF;
-}
-
-#sidebarToggle {
- background: rgba(255,255,255,0.04);
- border: 1px solid rgba(255,255,255,0.08);
- border-radius: 8px;
- color: rgba(245,245,247,0.40);
- font-size: 9pt;
-}
-#sidebarToggle:hover {
- background: rgba(255,255,255,0.08);
- color: rgba(245,245,247,0.70);
-}
-
-/* ═══ Results Table ═══ */
-#resultsSearch {
- border-radius: 10px;
- padding: 8px 12px;
- margin-bottom: 4px;
-}
-
-QTableWidget {
- background: transparent;
- gridline-color: transparent;
- border: 1px solid rgba(255,255,255,0.07);
- border-radius: 12px;
- alternate-background-color: rgba(255,255,255,0.02);
-}
-QHeaderView::section {
- background: rgba(255,255,255,0.03);
- color: rgba(245,245,247,0.72);
- padding: 8px 10px;
- border: none;
- border-bottom: 1px solid rgba(255,255,255,0.07);
- font-weight: 700;
- font-size: 9pt;
- text-transform: uppercase;
- letter-spacing: 0.04em;
-}
-QTableWidget::item {
- padding: 8px 10px;
- border-bottom: 1px solid rgba(255,255,255,0.03);
-}
-QTableWidget::item:selected {
- background: rgba(10,132,255,0.15);
-}
-
-#statsLabel {
- font-size: 9pt;
- color: rgba(245,245,247,0.50);
- font-weight: 600;
-}
-
-/* ═══ Log Widget ═══ */
-QPushButton[logFilter="true"] {
- background: rgba(255,255,255,0.04);
- border: 1px solid rgba(255,255,255,0.08);
- border-radius: 6px;
- padding: 2px 10px;
- font-size: 8pt;
- font-weight: 600;
- color: rgba(245,245,247,0.45);
-}
-QPushButton[logFilter="true"]:hover {
- background: rgba(255,255,255,0.07);
- color: rgba(245,245,247,0.70);
-}
-QPushButton[logFilter="true"]:checked {
- background: rgba(10,132,255,0.18);
- border-color: rgba(10,132,255,0.35);
- color: #0A84FF;
-}
-
-#logSearch {
- border-radius: 6px;
- padding: 3px 8px;
- font-size: 8pt;
-}
-
-#logText {
- background: transparent;
- border: none;
- font-family: ui-monospace, "SF Mono", Menlo, Consolas, "Cascadia Mono", monospace;
- font-size: 9pt;
- color: rgba(245,245,247,0.78);
-}
-
-/* ═══ Scrollbar — minimal ═══ */
-QScrollBar:vertical {
- background: transparent;
- width: 8px;
- margin: 0;
-}
-QScrollBar::handle:vertical {
- background: rgba(255,255,255,0.10);
- border-radius: 4px;
- min-height: 30px;
-}
-QScrollBar::handle:vertical:hover {
- background: rgba(255,255,255,0.18);
-}
-QScrollBar::add-line, QScrollBar::sub-line,
-QScrollBar::add-page, QScrollBar::sub-page {
- background: none;
- border: none;
- height: 0;
-}
-
-QScrollBar:horizontal {
- background: transparent;
- height: 8px;
- margin: 0;
-}
-QScrollBar::handle:horizontal {
- background: rgba(255,255,255,0.10);
- border-radius: 4px;
- min-width: 30px;
-}
-QScrollBar::handle:horizontal:hover {
- background: rgba(255,255,255,0.18);
-}
-
-/* ═══ Tooltips ═══ */
-QToolTip {
- background: #1C1F28;
- color: rgba(245,245,247,0.88);
- border: 1px solid rgba(255,255,255,0.12);
- border-radius: 8px;
- padding: 6px 10px;
- font-size: 9pt;
-}
-
-/* ═══ Progress ═══ */
-#mainProgress {
- background: rgba(255,255,255,0.04);
- border: none;
- border-radius: 2px;
-}
-#mainProgress::chunk {
- background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
- stop:0 #0A84FF, stop:1 #5AC8FA);
- border-radius: 2px;
-}
-#progressLabel {
- font-size: 9pt;
- color: rgba(245,245,247,0.50);
- font-weight: 600;
-}
diff --git a/app/ui/theme/down-arrow.svg b/app/ui/theme/down-arrow.svg
deleted file mode 100644
index 51ee52a..0000000
--- a/app/ui/theme/down-arrow.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/app/ui/theme/icons/collector.svg b/app/ui/theme/icons/collector.svg
deleted file mode 100644
index 99b6da6..0000000
--- a/app/ui/theme/icons/collector.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/app/ui/theme/icons/discord.svg b/app/ui/theme/icons/discord.svg
deleted file mode 100644
index 4e1a2c6..0000000
--- a/app/ui/theme/icons/discord.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/app/ui/theme/icons/drop.svg b/app/ui/theme/icons/drop.svg
deleted file mode 100644
index 7f95930..0000000
--- a/app/ui/theme/icons/drop.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/app/ui/theme/icons/evm.svg b/app/ui/theme/icons/evm.svg
deleted file mode 100644
index 5b6819b..0000000
--- a/app/ui/theme/icons/evm.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/app/ui/theme/icons/proxy.svg b/app/ui/theme/icons/proxy.svg
deleted file mode 100644
index 85d7366..0000000
--- a/app/ui/theme/icons/proxy.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/app/ui/theme/icons/svm.svg b/app/ui/theme/icons/svm.svg
deleted file mode 100644
index a80f5b5..0000000
--- a/app/ui/theme/icons/svm.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/app/ui/theme/icons/twitter.svg b/app/ui/theme/icons/twitter.svg
deleted file mode 100644
index 78e3520..0000000
--- a/app/ui/theme/icons/twitter.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/app/ui/theme/spinbox-chevron-down-disabled.svg b/app/ui/theme/spinbox-chevron-down-disabled.svg
deleted file mode 100644
index 8ded02d..0000000
--- a/app/ui/theme/spinbox-chevron-down-disabled.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
diff --git a/app/ui/theme/spinbox-chevron-down.svg b/app/ui/theme/spinbox-chevron-down.svg
deleted file mode 100644
index df4c321..0000000
--- a/app/ui/theme/spinbox-chevron-down.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
diff --git a/app/ui/theme/spinbox-chevron-up-disabled.svg b/app/ui/theme/spinbox-chevron-up-disabled.svg
deleted file mode 100644
index bb9ab32..0000000
--- a/app/ui/theme/spinbox-chevron-up-disabled.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
diff --git a/app/ui/theme/spinbox-chevron-up.svg b/app/ui/theme/spinbox-chevron-up.svg
deleted file mode 100644
index 3af528b..0000000
--- a/app/ui/theme/spinbox-chevron-up.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
diff --git a/app/ui/theme/up-arrow.svg b/app/ui/theme/up-arrow.svg
deleted file mode 100644
index ad431c6..0000000
--- a/app/ui/theme/up-arrow.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/app/ui/widgets/__init__.py b/app/ui/widgets/__init__.py
deleted file mode 100644
index dbf9827..0000000
--- a/app/ui/widgets/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from app.ui.widgets.drop_zone import DropZone
-from app.ui.widgets.toast import Toast, show_toast
-from app.ui.widgets.empty_state import EmptyState
-
-__all__ = ["DropZone", "Toast", "show_toast", "EmptyState"]
diff --git a/app/ui/widgets/chain_picker.py b/app/ui/widgets/chain_picker.py
deleted file mode 100644
index 1d492a8..0000000
--- a/app/ui/widgets/chain_picker.py
+++ /dev/null
@@ -1,251 +0,0 @@
-# app/ui/widgets/chain_picker.py
-from __future__ import annotations
-
-from PySide6.QtCore import Qt, Signal, QPoint
-from PySide6.QtWidgets import (
- QWidget, QVBoxLayout, QHBoxLayout, QFrame,
- QLineEdit, QListWidget, QListWidgetItem, QPushButton,
- QSizePolicy,
-)
-
-from app.integrations.lifi_client import DEBANK_TO_CHAIN_ID
-from app.i18n import tr, i18n
-
-# DeBank key → human readable display name
-_DISPLAY: dict[str, str] = {
- "eth": "Ethereum",
- "bsc": "BNB Chain",
- "matic": "Polygon",
- "avax": "Avalanche",
- "op": "Optimism",
- "arb": "Arbitrum",
- "base": "Base",
- "era": "zkSync Era",
- "linea": "Linea",
- "scrl": "Scroll",
- "blast": "Blast",
- "mnt": "Mantle",
- "mode": "Mode",
- "frax": "Fraxtal",
- "opbnb": "opBNB",
- "taiko": "Taiko",
- "abs": "Abstract",
- "ink": "Ink",
- "soneium": "Soneium",
- "uni": "Unichain",
- "world": "World Chain",
- "morph": "Morph",
- "swell": "Swellchain",
- "bob": "BOB",
- "sophon": "Sophon",
- "xdai": "Gnosis",
- "celo": "Celo",
- "cro": "Cronos",
- "boba": "Boba",
- "metis": "Metis",
- "mobm": "Moonbeam",
- "fuse": "Fuse",
- "klay": "Klaytn",
- "rsk": "RSK",
- "tlos": "Telos",
- "flr": "Flare",
- "ron": "Ronin",
- "sei": "Sei",
- "gravity": "Gravity",
- "lisk": "Lisk",
- "ape": "ApeChain",
- "ethlink": "Etherlink",
- "sonic": "Sonic",
- "corn": "Corn",
- "bera": "Berachain",
- "lens": "Lens",
- "hyper": "HyperEVM",
- "hemi": "Hemi",
- "plume": "Plume",
- "katana": "Katana",
- "plasma": "Plasma",
- "monad": "Monad",
- "stable": "Stable",
- "megaeth": "MegaETH",
- "itze": "Ithaca",
- "ftm": "Fantom",
- "movr": "Moonriver",
- "iotx": "IoTeX",
- "dfk": "DFK Chain",
- "nova": "Arbitrum Nova",
- "doge": "Dogechain",
- "kava": "Kava",
- "cfx": "Conflux",
- "core": "Core",
- "wemix": "WEMIX",
- "oas": "Oasys",
- "zora": "Zora",
- "manta": "Manta",
- "zeta": "ZetaChain",
- "merlin": "Merlin",
- "xlayer": "X Layer",
- "btr": "Bitlayer",
- "b2": "B2 Network",
- "croze": "Cronos zkEVM",
- "zircuit": "Zircuit",
- "hsk": "HashKey",
- "story": "Story",
- "cyber": "Cyber",
- "chiliz": "Chiliz",
- "orderly": "Orderly",
- "rari": "RARI Chain",
- "reya": "Reya",
- "bb": "BounceBit",
- "goat": "GOAT",
- "tac": "TAC",
- "botanix": "Botanix",
-}
-
-
-def _display_name(key: str) -> str:
- return _DISPLAY.get(key, key.capitalize())
-
-
-class _ChainPickerPopup(QFrame):
- """Floating popup with search field and checkbox list."""
-
- def __init__(self, picker: "ChainPickerWidget") -> None:
- super().__init__(None, Qt.Popup | Qt.FramelessWindowHint)
- self._picker = picker
- self.setObjectName("chainPickerPopup")
- self.setFixedWidth(260)
-
- layout = QVBoxLayout(self)
- layout.setContentsMargins(6, 6, 6, 6)
- layout.setSpacing(4)
-
- self._search = QLineEdit()
- self._search.setPlaceholderText(tr("chain_search_placeholder"))
- self._search.textChanged.connect(self._filter)
- layout.addWidget(self._search)
-
- self._list = QListWidget()
- self._list.setFixedHeight(240)
- self._list.itemChanged.connect(self._on_item_changed)
- layout.addWidget(self._list)
-
- self._populate()
-
- i18n.language_changed.connect(self.retranslate_ui)
-
- def retranslate_ui(self) -> None:
- self._search.setPlaceholderText(tr("chain_search_placeholder"))
-
- def _populate(self) -> None:
- self._list.blockSignals(True)
- self._list.clear()
- for key, name in self._picker._all_chains:
- item = QListWidgetItem(f"{name} ({key})")
- item.setData(Qt.UserRole, key)
- item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
- item.setCheckState(
- Qt.Checked if key in self._picker._selected else Qt.Unchecked
- )
- self._list.addItem(item)
- self._list.blockSignals(False)
-
- def refresh_checks(self) -> None:
- self._list.blockSignals(True)
- for i in range(self._list.count()):
- item = self._list.item(i)
- key = item.data(Qt.UserRole)
- item.setCheckState(
- Qt.Checked if key in self._picker._selected else Qt.Unchecked
- )
- self._list.blockSignals(False)
-
- def _filter(self, text: str) -> None:
- query = text.strip().lower()
- for i in range(self._list.count()):
- item = self._list.item(i)
- key = item.data(Qt.UserRole)
- name = _display_name(key).lower()
- item.setHidden(bool(query) and query not in key and query not in name)
-
- def _on_item_changed(self, item: QListWidgetItem) -> None:
- key = item.data(Qt.UserRole)
- if item.checkState() == Qt.Checked:
- self._picker._selected.add(key)
- else:
- self._picker._selected.discard(key)
- self._picker._update_summary()
-
- def show_below(self, widget: QWidget) -> None:
- pos = widget.mapToGlobal(QPoint(0, widget.height() + 2))
- self.move(pos)
- self._search.clear()
- self._filter("")
- self.show()
- self._search.setFocus()
-
-
-class ChainPickerWidget(QWidget):
- """Multi-select chain picker that looks like an input field with a dropdown."""
-
- selectionChanged = Signal(list) # list[str] of DeBank keys
-
- def __init__(self, placeholder: str = None, parent=None) -> None:
- super().__init__(parent)
- self._selected: set[str] = set()
- self._placeholder = placeholder or tr("pick_chains_placeholder")
- self._all_chains: list[tuple[str, str]] = [
- (key, _display_name(key)) for key in DEBANK_TO_CHAIN_ID
- ]
-
- layout = QHBoxLayout(self)
- layout.setContentsMargins(0, 0, 0, 0)
-
- self._btn = QPushButton(self._placeholder)
- self._btn.setObjectName("chainPickerButton")
- self._btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
- self._btn.clicked.connect(self._toggle_popup)
- layout.addWidget(self._btn)
-
- self._popup = _ChainPickerPopup(self)
-
- i18n.language_changed.connect(self.retranslate_ui)
-
- def retranslate_ui(self) -> None:
- self._placeholder = tr("pick_chains_placeholder")
- if not self._selected:
- self._update_summary()
-
- def _toggle_popup(self) -> None:
- if self._popup.isVisible():
- self._popup.hide()
- else:
- self._popup.refresh_checks()
- self._popup.show_below(self._btn)
-
- def _update_summary(self) -> None:
- if not self._selected:
- self._btn.setText(self._placeholder)
- else:
- keys = sorted(self._selected)
- # Show as many keys as fit (~40 chars), then "+N more"
- shown: list[str] = []
- total = 0
- for k in keys:
- if total + len(k) + 2 > 38:
- break
- shown.append(k)
- total += len(k) + 2
- remainder = len(keys) - len(shown)
- text = ", ".join(shown)
- if remainder:
- text += f" +{remainder}"
- self._btn.setText(text)
- self.selectionChanged.emit(list(self._selected))
-
- def get_selected(self) -> list[str]:
- return sorted(self._selected)
-
- def set_selected(self, keys: list[str]) -> None:
- self._selected = set(keys)
- self._update_summary()
- self._popup.refresh_checks()
diff --git a/app/ui/widgets/drop_zone.py b/app/ui/widgets/drop_zone.py
deleted file mode 100644
index 169d623..0000000
--- a/app/ui/widgets/drop_zone.py
+++ /dev/null
@@ -1,125 +0,0 @@
-from __future__ import annotations
-
-from pathlib import Path
-
-from PySide6.QtCore import Qt, Signal
-from PySide6.QtGui import QDragEnterEvent, QDropEvent
-from PySide6.QtWidgets import (
- QWidget, QVBoxLayout, QHBoxLayout, QLabel,
- QPushButton, QLineEdit, QFileDialog,
-)
-
-from app.i18n import tr, i18n
-
-
-class DropZone(QWidget):
- """Зона Drag & Drop + кнопка Browse. Заменяет стандартную строку выбора файла."""
-
- file_dropped = Signal(str) # Путь к файлу
-
- def __init__(
- self,
- label: str = "",
- placeholder: str = "file.txt",
- file_filter: str = "Text files (*.txt);;All files (*)",
- parent: QWidget | None = None,
- ) -> None:
- super().__init__(parent)
- self.setAcceptDrops(True)
- self.setObjectName("dropZone")
- self._file_filter = file_filter
- self._file_path: str = ""
-
- layout = QVBoxLayout(self)
- layout.setContentsMargins(0, 0, 0, 0)
- layout.setSpacing(4)
-
- # Row: Label + path + browse button
- row = QHBoxLayout()
- self._label = QLabel(label)
- self._label.setObjectName("dropZoneLabel")
- row.addWidget(self._label)
-
- self._path_edit = QLineEdit()
- self._path_edit.setPlaceholderText(placeholder)
- self._path_edit.setReadOnly(True)
- row.addWidget(self._path_edit)
-
- self._browse_btn = QPushButton(tr("browse_btn"))
- self._browse_btn.clicked.connect(self._browse)
- row.addWidget(self._browse_btn)
- layout.addLayout(row)
-
- # Drop area (hidden by default, shown when no file loaded)
- self._drop_area = QWidget()
- self._drop_area.setObjectName("dropArea")
- self._drop_area.setFixedHeight(64)
- drop_layout = QVBoxLayout(self._drop_area)
- drop_layout.setAlignment(Qt.AlignCenter)
- self._drop_hint = QLabel(tr("drop_hint"))
- self._drop_hint.setObjectName("dropHint")
- self._drop_hint.setAlignment(Qt.AlignCenter)
- drop_layout.addWidget(self._drop_hint)
- layout.addWidget(self._drop_area)
-
- # Status
- self._status = QLabel(tr("file_not_loaded"))
- self._status.setObjectName("dropZoneStatus")
- layout.addWidget(self._status)
-
- i18n.language_changed.connect(self._retranslate)
-
- def _retranslate(self) -> None:
- self._browse_btn.setText(tr("browse_btn"))
- self._drop_hint.setText(tr("drop_hint"))
- if not self._file_path:
- self._status.setText(tr("file_not_loaded"))
-
- def set_label(self, text: str) -> None:
- self._label.setText(text)
-
- def set_status(self, text: str) -> None:
- self._status.setText(text)
- if text and "✓" in text:
- self._drop_area.setVisible(False)
- else:
- self._drop_area.setVisible(True)
-
- def get_file_path(self) -> str:
- return self._file_path
-
- def _browse(self) -> None:
- path, _ = QFileDialog.getOpenFileName(
- self, tr("select_file"), "", self._file_filter,
- )
- if path:
- self._set_file(path)
-
- def _set_file(self, path: str) -> None:
- self._file_path = path
- self._path_edit.setText(path)
- self._drop_area.setVisible(False)
- self.file_dropped.emit(path)
-
- # --- Drag & Drop ---
- def dragEnterEvent(self, event: QDragEnterEvent) -> None:
- if event.mimeData().hasUrls():
- self.setProperty("dragOver", True)
- self.style().unpolish(self)
- self.style().polish(self)
- event.acceptProposedAction()
-
- def dragLeaveEvent(self, event) -> None:
- self.setProperty("dragOver", False)
- self.style().unpolish(self)
- self.style().polish(self)
-
- def dropEvent(self, event: QDropEvent) -> None:
- self.setProperty("dragOver", False)
- self.style().unpolish(self)
- self.style().polish(self)
- urls = event.mimeData().urls()
- if urls:
- path = urls[0].toLocalFile()
- if path and Path(path).is_file():
- self._set_file(path)
diff --git a/app/ui/widgets/empty_state.py b/app/ui/widgets/empty_state.py
deleted file mode 100644
index 96d9ae0..0000000
--- a/app/ui/widgets/empty_state.py
+++ /dev/null
@@ -1,47 +0,0 @@
-from __future__ import annotations
-
-from PySide6.QtCore import Qt
-from PySide6.QtWidgets import QWidget, QVBoxLayout, QLabel
-
-
-class EmptyState(QWidget):
- """Виджет пустого состояния — иконка + заголовок + подсказка."""
-
- def __init__(
- self,
- icon_text: str = "📋",
- title: str = "",
- subtitle: str = "",
- parent: QWidget | None = None,
- ) -> None:
- super().__init__(parent)
- self.setObjectName("emptyState")
-
- layout = QVBoxLayout(self)
- layout.setAlignment(Qt.AlignCenter)
- layout.setSpacing(8)
-
- self._icon = QLabel(icon_text)
- self._icon.setObjectName("emptyStateIcon")
- self._icon.setAlignment(Qt.AlignCenter)
- layout.addWidget(self._icon)
-
- self._title = QLabel(title)
- self._title.setObjectName("emptyStateTitle")
- self._title.setAlignment(Qt.AlignCenter)
- self._title.setWordWrap(True)
- layout.addWidget(self._title)
-
- self._subtitle = QLabel(subtitle)
- self._subtitle.setObjectName("emptyStateSubtitle")
- self._subtitle.setAlignment(Qt.AlignCenter)
- self._subtitle.setWordWrap(True)
- layout.addWidget(self._subtitle)
-
- def set_texts(self, icon: str = "", title: str = "", subtitle: str = "") -> None:
- if icon:
- self._icon.setText(icon)
- if title:
- self._title.setText(title)
- if subtitle:
- self._subtitle.setText(subtitle)
diff --git a/app/ui/widgets/toast.py b/app/ui/widgets/toast.py
deleted file mode 100644
index d883046..0000000
--- a/app/ui/widgets/toast.py
+++ /dev/null
@@ -1,70 +0,0 @@
-from __future__ import annotations
-
-from PySide6.QtCore import Qt, QTimer, QPropertyAnimation, QEasingCurve, Property
-from PySide6.QtWidgets import QLabel, QWidget, QGraphicsOpacityEffect
-
-
-class Toast(QLabel):
- """Всплывающее уведомление, исчезающее через несколько секунд."""
-
- def __init__(
- self,
- text: str,
- level: str = "info",
- duration_ms: int = 3000,
- parent: QWidget | None = None,
- ) -> None:
- super().__init__(text, parent)
- self.setObjectName("toast")
- self.setProperty("level", level)
- self.setAlignment(Qt.AlignCenter)
- self.setWordWrap(True)
- self.setFixedHeight(44)
- self.setMinimumWidth(280)
- self.adjustSize()
-
- self._opacity = QGraphicsOpacityEffect(self)
- self._opacity.setOpacity(0.0)
- self.setGraphicsEffect(self._opacity)
-
- # Fade in
- self._fade_in = QPropertyAnimation(self._opacity, b"opacity")
- self._fade_in.setDuration(250)
- self._fade_in.setStartValue(0.0)
- self._fade_in.setEndValue(1.0)
- self._fade_in.setEasingCurve(QEasingCurve.OutCubic)
-
- # Fade out → destroy
- self._fade_out = QPropertyAnimation(self._opacity, b"opacity")
- self._fade_out.setDuration(400)
- self._fade_out.setStartValue(1.0)
- self._fade_out.setEndValue(0.0)
- self._fade_out.setEasingCurve(QEasingCurve.InCubic)
- self._fade_out.finished.connect(self.deleteLater)
-
- # Auto-dismiss timer
- self._timer = QTimer(self)
- self._timer.setSingleShot(True)
- self._timer.setInterval(duration_ms)
- self._timer.timeout.connect(self._fade_out.start)
-
- def show_toast(self) -> None:
- """Показать toast. Вызывать после добавления в layout."""
- self.show()
- self._fade_in.start()
- self._timer.start()
-
-
-def show_toast(
- parent: QWidget,
- text: str,
- level: str = "info",
- duration_ms: int = 3000,
-) -> Toast:
- """Утилита: создаёт и показывает toast поверх parent."""
- toast = Toast(text, level=level, duration_ms=duration_ms, parent=parent)
- # Position at top center
- toast.setFixedWidth(min(400, parent.width() - 40))
- toast.move((parent.width() - toast.width()) // 2, 12)
- toast.show_toast()
- return toast
diff --git a/commit_msg.txt b/commit_msg.txt
deleted file mode 100644
index 0373e2d..0000000
--- a/commit_msg.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-Fix: Explicitly set status to ERROR for uncorroborated balances
-
-Currently, if the attempt budget is exhausted without reaching
-CORROBORATION_MIN_AGREE, the fallback logic selects the most conservative
-snapshot and returns it but leaves its status as "OK". This causes `main.py`
-to accept this potentially phantom balance as a valid result.
-
-This commit adds `chosen["status"] = "ERROR"` to the fallback logic so that
-uncorroborated balances are correctly flagged as errors and excluded from the
-successful totals.
diff --git a/debank_checker/__init__.py b/debank_checker/__init__.py
new file mode 100644
index 0000000..3f14aa0
--- /dev/null
+++ b/debank_checker/__init__.py
@@ -0,0 +1,5 @@
+"""
+DeBank Balance Checker — массовая проверка балансов кошельков через DeBank API.
+"""
+
+__version__ = "1.0.3"
diff --git a/debank_checker/api/__init__.py b/debank_checker/api/__init__.py
new file mode 100644
index 0000000..d27bfa5
--- /dev/null
+++ b/debank_checker/api/__init__.py
@@ -0,0 +1,5 @@
+"""API: DeBank клиент."""
+
+from debank_checker.api.client import DeBankClient
+
+__all__ = ["DeBankClient"]
diff --git a/debank_checker/api/client.py b/debank_checker/api/client.py
new file mode 100644
index 0000000..a725c04
--- /dev/null
+++ b/debank_checker/api/client.py
@@ -0,0 +1,182 @@
+"""
+DeBank API Client
+Подпись HMAC-SHA256, curl_cffi (impersonate chrome).
+Прокси обязателен.
+"""
+
+import hashlib
+import hmac as hmac_lib
+import json
+import random
+import time
+import uuid
+from typing import Optional
+
+import curl_cffi.requests as cffi_requests
+
+from debank_checker.config import (
+ API_KEY_INIT,
+ NFT_POLL_INTERVAL,
+ NFT_POLL_MAX_WAIT,
+ NFT_REQUEST_TIMEOUT,
+ REQUEST_TIMEOUT,
+)
+
+API_BASE = "https://api.debank.com"
+NONCE_ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz"
+NONCE_LENGTH = 40
+
+
+def sort_params(params: dict) -> str:
+ if not params:
+ return ""
+ return "&".join(f"{k}={v}" for k, v in sorted(params.items()))
+
+
+def sha256_hex(text: str) -> str:
+ return hashlib.sha256(text.encode("utf-8")).hexdigest()
+
+
+def hmac_sha256(key_str: str, msg_str: str) -> str:
+ return hmac_lib.new(
+ key_str.encode("utf-8"),
+ msg_str.encode("utf-8"),
+ hashlib.sha256,
+ ).hexdigest()
+
+
+def generate_nonce() -> str:
+ return "n_" + "".join(random.choices(NONCE_ALPHABET, k=NONCE_LENGTH))
+
+
+def sign_request(
+ params: dict,
+ method: str,
+ path: str,
+ nonce: str | None = None,
+ ts: int | None = None,
+ version: str = "v2",
+) -> dict:
+ ts = ts or int(time.time())
+ nonce = nonce or generate_nonce()
+ prefix = "debank-web\n" if version == "v2.1" else "debank-api\n"
+ sorted_p = sort_params(params)
+ K = sha256_hex(f"{prefix}{nonce}\n{ts}")
+ M = sha256_hex(f"{method.upper()}\n{path}\n{sorted_p}")
+ signature = hmac_sha256(K, M)
+ return {"signature": signature, "nonce": nonce, "ts": ts, "version": version}
+
+
+class DeBankClient:
+ """Клиент DeBank API. Прокси обязателен."""
+
+ def __init__(self, proxy: str, impersonate: str = "chrome124"):
+ if not proxy:
+ raise ValueError("Прокси обязателен для DeBank API")
+ self._api_key = API_KEY_INIT
+ self._init_ts = int(time.time())
+ self._random_at = self._init_ts
+ self._random_id = uuid.uuid4().hex
+ self._impersonate = impersonate
+ proxies = {"https": proxy, "http": proxy}
+ self._session = cffi_requests.Session(
+ impersonate=impersonate,
+ proxies=proxies,
+ )
+
+ def _build_headers(self, params: dict, method: str, path: str) -> dict:
+ sign = sign_request(params, method, path)
+ account = json.dumps(
+ {
+ "random_at": self._random_at,
+ "random_id": self._random_id,
+ "user_addr": None,
+ "connected_addr": None,
+ },
+ separators=(",", ":"),
+ )
+ return {
+ "Referer": "https://debank.com/",
+ "Origin": "https://debank.com",
+ "X-API-Key": self._api_key,
+ "X-API-Time": str(self._init_ts),
+ "x-api-ts": str(sign["ts"]),
+ "x-api-nonce": sign["nonce"],
+ "x-api-ver": sign["version"],
+ "x-api-sign": sign["signature"],
+ "source": "web",
+ "account": account,
+ }
+
+ def _get(self, path: str, params: dict | None = None, timeout: float | None = None) -> dict:
+ params = params or {}
+ headers = self._build_headers(params, "GET", path)
+ resp = self._session.get(
+ API_BASE + path,
+ params=params,
+ headers=headers,
+ timeout=timeout or REQUEST_TIMEOUT,
+ )
+ resp.raise_for_status()
+
+ new_key = resp.headers.get("x-set-api-key")
+ if new_key:
+ self._api_key = new_key
+
+ data = resp.json()
+ if isinstance(data, dict) and "data" in data:
+ return data["data"]
+ return data
+
+ def get_total_balance_cache(self, address: str) -> list:
+ """Кэшированный список токенов по всем сетям."""
+ result = self._get("/token/cache_balance_list", {"user_addr": address})
+ return result if isinstance(result, list) else []
+
+ def get_portfolio(self, address: str) -> list:
+ """DeFi протоколы с позициями."""
+ result = self._get("/portfolio/project_list", {"user_addr": address})
+ return result if isinstance(result, list) else []
+
+ def get_nft_used_chains(self, address: str) -> list:
+ """Сети, в которых у пользователя есть NFT."""
+ result = self._get("/nft/used_chains", {"user_addr": address})
+ if isinstance(result, list):
+ return [
+ c.get("id") if isinstance(c, dict) else str(c)
+ for c in result
+ if isinstance(c, (dict, str))
+ ]
+ return []
+
+ def get_nft_collection_list(self, address: str, chain: str) -> list:
+ """
+ NFT-коллекции по адресу и сети.
+ API может вернуть async job (pending) — тогда polling с retry.
+ Результат: list из result["data"] или result (если list).
+ """
+ params = {"user_addr": address, "chain": chain}
+ deadline = time.time() + NFT_POLL_MAX_WAIT
+
+ def _extract_list(val) -> list:
+ if isinstance(val, list):
+ return val
+ if isinstance(val, dict) and "data" in val:
+ d = val["data"]
+ return d if isinstance(d, list) else []
+ return []
+
+ while True:
+ result = self._get("/nft/collection_list", params, timeout=NFT_REQUEST_TIMEOUT)
+ if isinstance(result, list):
+ return result
+ if isinstance(result, dict):
+ job = result.get("job") or {}
+ status = job.get("status") if job else None
+ res = result.get("result")
+ if res is not None:
+ return _extract_list(res)
+ if status == "pending" and time.time() < deadline:
+ time.sleep(NFT_POLL_INTERVAL)
+ continue
+ return []
diff --git a/debank_checker/checker.py b/debank_checker/checker.py
new file mode 100644
index 0000000..5467d22
--- /dev/null
+++ b/debank_checker/checker.py
@@ -0,0 +1,363 @@
+"""
+Проверка балансов кошельков: tokens + portfolio (+ NFT заглушка)
+"""
+
+import time
+from typing import Any
+
+from debank_checker.api.client import DeBankClient
+from debank_checker.config import (
+ CORROBORATION_ABS_TOL,
+ CORROBORATION_ENABLED,
+ CORROBORATION_MAX_FETCHES,
+ CORROBORATION_MIN_AGREE,
+ CORROBORATION_REL_TOL,
+ DEBUG,
+ MIN_VALUE_DISPLAY,
+ RETRY_ATTEMPTS,
+)
+from debank_checker.proxy.manager import ProxyManager
+
+
+def _mask_proxy(proxy: str | None) -> str:
+ """Маскирует прокси для лога (оставляет ip:port)."""
+ if not proxy:
+ return "—"
+ try:
+ if "@" in proxy:
+ return proxy.split("@")[-1]
+ return proxy
+ except Exception:
+ return "?"
+
+
+def _safe_position_value(item: dict) -> float:
+ """
+ Вычисляет стоимость позиции протокола, защищаясь от фантомных данных API.
+
+ Логика:
+ - Пересчитывает стоимость из asset_token_list (фильтруя скам-токены).
+ - Если asset_token_list пустой или все токены скам → возвращает 0.
+ - Использует min(api_value, recalc_value):
+ * Для lending: api_value (залог−долг) < recalc_value (только залог) → берём api_value.
+ * Для farming/common: recalc_value ≈ api_value → результат корректный.
+ * Для фантомной позиции: recalc_value = 0 → возвращаем 0.
+ """
+ api_value = max(0.0, item.get("stats", {}).get("net_usd_value", 0))
+
+ asset_tokens = item.get("asset_token_list", [])
+ if not asset_tokens:
+ return 0.0 # нет токенов — фантомная позиция
+
+ recalc = 0.0
+ for t in asset_tokens:
+ value = t.get("price", 0) * t.get("amount", 0)
+ if t.get("is_verified", True) and not t.get("is_scam", False):
+ recalc += value
+
+ recalc = max(0.0, recalc)
+ if recalc == 0.0:
+ return 0.0 # все токены в позиции — скам
+
+ return min(api_value, recalc)
+
+
+def _write_log(address: str, total_usd: float, tokens_usd: float,
+ protocols_usd: float, tokens: list, portfolio: list) -> None:
+ """Пишет лог в logs.txt в корневой директории проекта."""
+ import json
+ from pathlib import Path
+ from datetime import datetime
+
+ log_path = Path(__file__).parent.parent / "logs.txt"
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+
+ with open(log_path, "a", encoding="utf-8") as f:
+ f.write(f"\n{'=' * 60}\n")
+ f.write(f"[{timestamp}] {address}\n")
+ f.write(f" total_usd={total_usd:.2f} tokens_usd={tokens_usd:.2f}"
+ f" protocols_usd={protocols_usd:.2f}\n")
+ if total_usd > 1_000:
+ f.write(" [!] АНОМАЛЬНЫЙ БАЛАНС — сохраняю сырые данные\n")
+ f.write(" --- TOKENS ---\n")
+ f.write(json.dumps(tokens, ensure_ascii=False, indent=2))
+ f.write("\n --- PORTFOLIO ---\n")
+ f.write(json.dumps(portfolio, ensure_ascii=False, indent=2))
+ f.write("\n")
+
+
+def _agree(a: float, b: float) -> bool:
+ """Две суммы считаются согласованными в пределах относ./абс. допуска."""
+ return abs(a - b) <= max(CORROBORATION_ABS_TOL,
+ CORROBORATION_REL_TOL * max(abs(a), abs(b)))
+
+
+def _largest_agreeing_cluster(snaps: list[dict[str, Any]]) -> list[dict[str, Any]]:
+ """Наибольшая группа выборок, согласованных по total_usd.
+
+ При равенстве размеров выбирается группа с НАИМЕНЬШИМ значением — фантом
+ всегда завышает баланс, поэтому консервативный выбор защищает от инфляции.
+ """
+ best: list[dict[str, Any]] = []
+ for anchor in snaps:
+ cluster = [s for s in snaps if _agree(s["total_usd"], anchor["total_usd"])]
+ if (len(cluster) > len(best)
+ or (len(cluster) == len(best) and best
+ and _rep(cluster)["total_usd"] < _rep(best)["total_usd"])):
+ best = cluster
+ return best
+
+
+def _rep(cluster: list[dict[str, Any]]) -> dict[str, Any]:
+ """Представитель группы: выборка с минимальным total_usd (все согласованы)."""
+ return min(cluster, key=lambda s: s["total_usd"])
+
+
+def _fetch_snapshot(address: str, proxy: str) -> dict[str, Any]:
+ """Одна независимая выборка баланса кошелька (tokens + portfolio + NFT).
+
+ Бросает исключение при сетевой ошибке. Возвращает result-dict со status=OK.
+
+ ВНИМАНИЕ: под высокой конкуренцией DeBank иногда отдаёт ответ от ДРУГОГО
+ адреса (response contamination) — такая выборка внутренне консистентна и
+ в одиночку неотличима от настоящей. Отсев делает корроборация в
+ check_wallet(): фантом случаен и не повторяется, истинный баланс стабилен.
+ """
+ client = DeBankClient(proxy=proxy)
+
+ # Токены в кошельке — фильтруем скам и неверифицированные
+ tokens = client.get_total_balance_cache(address)
+ tokens = [
+ t for t in tokens
+ if t.get("is_verified", True) and not t.get("is_scam", False)
+ ]
+
+ portfolio = client.get_portfolio(address)
+
+ tokens_usd = sum(t.get("price", 0) * t.get("amount", 0) for t in tokens)
+
+ protocols_data = []
+ protocols_usd = 0.0
+ for proto in portfolio:
+ proto_value = sum(
+ _safe_position_value(item)
+ for item in proto.get("portfolio_item_list", [])
+ )
+ if round(proto_value, 2) < MIN_VALUE_DISPLAY:
+ continue
+ protocols_usd += proto_value
+
+ positions = []
+ for item in proto.get("portfolio_item_list", []):
+ net = _safe_position_value(item)
+ if round(net, 2) < MIN_VALUE_DISPLAY:
+ continue
+ detail = item.get("detail", {})
+ supply = [
+ f"{t.get('symbol', '?')} {t.get('amount', 0):.4f}"
+ for t in detail.get("supply_token_list", [])
+ ]
+ reward = [
+ f"{t.get('symbol', '?')} {t.get('amount', 0):.4f}"
+ for t in detail.get("reward_token_list", [])
+ ]
+ positions.append({
+ "type": item.get("name", ""),
+ "value": round(net, 2),
+ "supply": ", ".join(supply),
+ "rewards": ", ".join(reward),
+ })
+
+ protocols_data.append({
+ "logo": proto.get("logo_url") or "",
+ "name": proto.get("name", "?"),
+ "chain": proto.get("chain", "?"),
+ "value": round(proto_value, 2),
+ "positions": positions,
+ })
+
+ protocols_data.sort(key=lambda p: p["value"], reverse=True)
+
+ nft_usd = 0.0
+ nft_data: list[dict] = []
+ nft_chains: set[str] = set()
+ try:
+ nft_chains_list = client.get_nft_used_chains(address)
+ for chain in (nft_chains_list or [])[:10]:
+ collections = client.get_nft_collection_list(address, chain)
+ for col in collections:
+ amount = col.get("amount") or col.get("nft_count", 0)
+ if not amount:
+ continue
+ nft_chains.add(col.get("chain_id") or chain)
+ nft_data.append({
+ "name": col.get("name", "?"),
+ "chain": col.get("chain_id") or chain,
+ "amount": amount,
+ })
+ except Exception:
+ pass
+ nft_data.sort(key=lambda x: (x["chain"], x["name"]))
+
+ total_usd = tokens_usd + protocols_usd
+
+ # Лог сырых данных при аномалии (помогает увидеть, что именно отсеяла корроборация)
+ _write_log(address, total_usd, tokens_usd, protocols_usd, tokens, portfolio)
+
+ chains = sorted({t.get("chain", "") for t in tokens if t.get("chain")} | nft_chains)
+
+ tokens_data = [
+ {
+ "logo": t.get("logo_url") or "",
+ "symbol": t.get("symbol", "?"),
+ "chain": t.get("chain", "?"),
+ "amount": t.get("amount", 0),
+ "price": t.get("price", 0),
+ "value": round(t.get("price", 0) * t.get("amount", 0), 2),
+ }
+ for t in tokens
+ if round(t.get("price", 0) * t.get("amount", 0), 2) >= MIN_VALUE_DISPLAY
+ ]
+
+ top_tokens = sorted(tokens_data, key=lambda t: t["value"], reverse=True)[:3]
+ top_str = ", ".join(f"{t['symbol']}(${t['value']:.2f})" for t in top_tokens)
+
+ return {
+ "address": address,
+ "total_usd": total_usd,
+ "tokens_usd": tokens_usd,
+ "protocols_usd": protocols_usd,
+ "nft_usd": nft_usd,
+ "tokens": len(tokens_data),
+ "chains": ", ".join(chains),
+ "top_tokens": top_str,
+ "tokens_data": tokens_data,
+ "protocols_data": protocols_data,
+ "nft_data": nft_data,
+ "proxy": proxy or "—",
+ "status": "OK",
+ "error": "",
+ "corroborated": True,
+ }
+
+
+def check_wallet(address: str, proxy_manager: ProxyManager, wallet_idx: int = -1) -> dict[str, Any]:
+ """Проверяет баланс одного кошелька с защитой от «фантомных» балансов.
+
+ Сетевые ошибки → повтор с новым прокси. При CORROBORATION_ENABLED баланс
+ принимается только если подтверждён CORROBORATION_MIN_AGREE независимыми
+ выборками, сошедшимися по total_usd; иначе берётся консервативное значение
+ (наибольшая согласованная группа, при равенстве — меньшая сумма).
+ """
+ last_error = None
+ used_proxy = None
+ total_start = time.perf_counter()
+
+ snapshots: list[dict[str, Any]] = []
+ fetches = 0
+ attempts = 0
+ # Запас попыток на сетевые сбои поверх бюджета успешных выборок.
+ max_attempts = (max(RETRY_ATTEMPTS, CORROBORATION_MAX_FETCHES * 3)
+ if CORROBORATION_ENABLED else RETRY_ATTEMPTS)
+
+ while attempts < max_attempts:
+ attempts += 1
+ if CORROBORATION_ENABLED and fetches >= CORROBORATION_MAX_FETCHES:
+ break
+
+ attempt_start = time.perf_counter()
+ proxy = proxy_manager.get_proxy()
+ if not proxy:
+ if not snapshots:
+ if DEBUG:
+ _debug_log(wallet_idx, address, "NO_PROXY", attempts, 0, "—")
+ return _error_result(address, "Нет доступных прокси", used_proxy)
+ break
+ used_proxy = proxy
+
+ try:
+ snap = _fetch_snapshot(address, proxy)
+ except Exception as e:
+ last_error = e
+ err_str = str(e).lower()
+ if "timeout" in err_str or "timed out" in err_str:
+ proxy_manager.report_timeout(used_proxy)
+ if DEBUG:
+ _debug_log(wallet_idx, address, "FAIL", attempts,
+ time.perf_counter() - attempt_start,
+ _mask_proxy(used_proxy), str(e)[:80])
+ continue
+
+ fetches += 1
+
+ if not CORROBORATION_ENABLED:
+ if DEBUG:
+ _debug_log(wallet_idx, address, "OK", attempts,
+ time.perf_counter() - total_start, _mask_proxy(used_proxy))
+ return snap
+
+ # Корроборация: ищем группу согласованных по total_usd выборок.
+ snapshots.append(snap)
+ cluster = [s for s in snapshots if _agree(s["total_usd"], snap["total_usd"])]
+ if len(cluster) >= CORROBORATION_MIN_AGREE:
+ chosen = _rep(cluster)
+ chosen["corroborated"] = True
+ if DEBUG:
+ _debug_log(wallet_idx, address, "OK", attempts,
+ time.perf_counter() - total_start, _mask_proxy(used_proxy))
+ return chosen
+
+ # Бюджет исчерпан без подтверждения — берём консервативный результат.
+ if snapshots:
+ chosen = _rep(_largest_agreeing_cluster(snapshots))
+ chosen["corroborated"] = False
+ chosen["error"] = (chosen.get("error")
+ or "баланс не подтверждён (возможен фантом) — взято консервативное значение")
+ if DEBUG:
+ others = sorted(round(s["total_usd"], 2) for s in snapshots)
+ _debug_log(wallet_idx, address, "WARN", attempts,
+ time.perf_counter() - total_start, _mask_proxy(used_proxy),
+ f"не подтверждён, выборки={others}")
+ return chosen
+
+ if DEBUG:
+ elapsed = time.perf_counter() - total_start
+ _debug_log(wallet_idx, address, "ERROR", attempts, elapsed,
+ _mask_proxy(used_proxy), str(last_error)[:80])
+
+ return _error_result(
+ address,
+ str(last_error) if last_error else "Unknown error",
+ used_proxy,
+ )
+
+
+def _debug_log(idx: int, addr: str, status: str, attempt: int, sec: float, proxy: str, err: str = "") -> None:
+ """Отладочный лог в stderr."""
+ if not DEBUG:
+ return
+ import sys
+ short = f"{addr[:10]}...{addr[-6:]}" if len(addr) > 20 else addr
+ err_part = f" | {err}" if err else ""
+ line = f"[DEBUG] #{idx} {short} | {status} | попытка {attempt} | {sec:.2f}s | {proxy}{err_part}\n"
+ sys.stderr.write(line)
+ sys.stderr.flush()
+
+
+def _error_result(address: str, err_msg: str, proxy: str | None) -> dict[str, Any]:
+ return {
+ "address": address,
+ "total_usd": 0.0,
+ "tokens_usd": 0.0,
+ "protocols_usd": 0.0,
+ "nft_usd": 0.0,
+ "tokens": 0,
+ "chains": "",
+ "top_tokens": "",
+ "tokens_data": [],
+ "protocols_data": [],
+ "nft_data": [],
+ "proxy": proxy or "—",
+ "status": "ERROR",
+ "error": err_msg,
+ }
\ No newline at end of file
diff --git a/debank_checker/config.py b/debank_checker/config.py
new file mode 100644
index 0000000..9b2cff6
--- /dev/null
+++ b/debank_checker/config.py
@@ -0,0 +1,48 @@
+"""
+Конфигурация DeBank Balance Checker
+"""
+
+# Пути к файлам
+WALLETS_FILE = "wallets.txt"
+PROXIES_FILE = "proxy.txt"
+OUTPUT_DIR = "Results" # папка для Excel-результатов
+
+# API
+REQUEST_TIMEOUT = 3 # секунд (быстрый failover при мёртвых прокси, см. docs/DEBUG_REPORT.md)
+API_KEY_INIT = "3b92c003-ddc1-4c2d-b36e-781838f362c5"
+
+# Прокси и rate limit
+RATE_LIMIT_REQ_PER_MIN = 60 # запросов в минуту на один прокси
+RETRY_ATTEMPTS = 10 # попыток при ошибке (с новым прокси, без задержки между попытками)
+
+# Параллелизм
+MAX_WORKERS = 500 # максимум одновременных воркеров
+PROXY_MULTIPLIER = 5 # max_workers = min(MAX_WORKERS, len(wallets), len(proxies) * PROXY_MULTIPLIER)
+
+# Минимальная сумма для отображения (USD)
+MIN_VALUE_DISPLAY = 0.01
+
+# --- Защита от «фантомных» балансов -------------------------------------
+# Под высокой конкуренцией DeBank-API/edge иногда возвращает ОТВЕТ ОТ ДРУГОГО
+# адреса (response contamination: ~1 на 30 запросов при 40+ воркерах; при
+# последовательных запросах НЕ воспроизводится). Из-за этого на кошельке с $15
+# вдруг «появляются» сотни тысяч/миллионы. Данные при этом внутренне
+# консистентны (верифицированные токены, реальные пулы) — пересчётом одной
+# выборки фантом не отличить, нужна КОРРОБОРАЦИЯ независимыми запросами.
+#
+# Баланс принимается, только если подтверждён двумя независимыми выборками,
+# сошедшимися в пределах допуска. Фантом случаен и не повторяется → отбрасываем;
+# истинное значение стабильно → подтверждается.
+CORROBORATION_ENABLED = True # False — старое поведение (1 запрос)
+CORROBORATION_MIN_AGREE = 2 # сошедшихся выборок нужно для приёма
+CORROBORATION_MAX_FETCHES = 8 # бюджет успешных выборок на кошелёк
+CORROBORATION_REL_TOL = 0.02 # относительный допуск согласия (2%)
+CORROBORATION_ABS_TOL = 1.0 # абсолютный допуск согласия (USD)
+
+# NFT
+NFT_POLL_INTERVAL = 3 # сек между попытками при async job
+NFT_POLL_MAX_WAIT = 30 # макс время ожидания результата
+NFT_REQUEST_TIMEOUT = 3 # таймаут запроса (как REQUEST_TIMEOUT)
+
+# Отладка
+DEBUG = False # True — отладочное логирование (время, попытки, прокси)
diff --git a/debank_checker/export/__init__.py b/debank_checker/export/__init__.py
new file mode 100644
index 0000000..355970c
--- /dev/null
+++ b/debank_checker/export/__init__.py
@@ -0,0 +1,5 @@
+"""Экспорт: Excel."""
+
+from debank_checker.export.excel import export_to_excel
+
+__all__ = ["export_to_excel"]
diff --git a/debank_checker/export/common.py b/debank_checker/export/common.py
new file mode 100644
index 0000000..68a9994
--- /dev/null
+++ b/debank_checker/export/common.py
@@ -0,0 +1,110 @@
+"""
+Общая логика фильтрации и построения данных для экспорта
+"""
+
+from debank_checker.export.config import ExportConfig
+
+
+def filter_tokens(tokens_data: list[dict], token_filter: str | None) -> list[dict]:
+ """Фильтр по symbol:chain (например ETH:eth)."""
+ if not token_filter or ":" not in token_filter:
+ return tokens_data
+ parts = token_filter.split(":", 1)
+ symbol, chain = (parts[0].strip().upper(), parts[1].strip().lower()) if len(parts) == 2 else ("", "")
+ return [
+ t for t in tokens_data
+ if (not symbol or (t.get("symbol") or "").upper() == symbol)
+ and (not chain or (t.get("chain") or "").lower() == chain)
+ ]
+
+
+def filter_protocols(protocols_data: list[dict], protocol_filter: str | None) -> list[dict]:
+ """Фильтр по name:chain. :chain — все в сети."""
+ if not protocol_filter or ":" not in protocol_filter:
+ return protocols_data
+ parts = protocol_filter.split(":", 1)
+ name, chain = (parts[0].strip(), parts[1].strip().lower()) if len(parts) == 2 else ("", "")
+ return [
+ p for p in protocols_data
+ if (not name or (p.get("name") or "").strip() == name)
+ and (not chain or (p.get("chain") or "").lower() == chain)
+ ]
+
+
+def filter_nft(nft_data: list[dict], nft_filter: str | None) -> list[dict]:
+ """Фильтр по collection:chain."""
+ if not nft_filter or ":" not in nft_filter:
+ return nft_data
+ parts = nft_filter.split(":", 1)
+ collection, chain = (parts[0].strip(), parts[1].strip().lower()) if len(parts) == 2 else ("", "")
+ return [
+ n for n in nft_data
+ if (not collection or collection.lower() in (n.get("name") or "").lower())
+ and (not chain or (n.get("chain") or "").lower() == chain)
+ ]
+
+
+def build_export_data(results: list[dict], config: ExportConfig) -> dict:
+ """
+ Построить данные для экспорта по config.
+ Возвращает: { "total": {...}, "summary": [...], "tokens": [...], "protocols": [...], "nft": [...] }
+ """
+ ok = [r for r in results if r and r.get("status") == "OK"]
+ total_sum = sum(r.get("total_usd", 0) for r in ok)
+ data = {
+ "total": {"sum_usd": total_sum, "ok_count": len(ok), "total_count": len(results)},
+ "summary": [],
+ "tokens": [],
+ "protocols": [],
+ "nft": [],
+ }
+
+ if config.summary and not config.total_only:
+ for i, r in enumerate(results, 1):
+ data["summary"].append({
+ "n": i,
+ "address": r.get("address", ""),
+ "total_usd": r.get("total_usd") if r.get("status") == "OK" else None,
+ "chains": r.get("chains", ""),
+ "status": r.get("status", ""),
+ })
+
+ if config.tokens:
+ for r in results:
+ if r.get("status") != "OK":
+ continue
+ for t in filter_tokens(r.get("tokens_data", []), config.token_filter):
+ data["tokens"].append({
+ "address": r["address"],
+ "symbol": t.get("symbol", ""),
+ "chain": t.get("chain", ""),
+ "amount": t.get("amount", 0),
+ "price": t.get("price", 0),
+ "value": t.get("value", 0),
+ })
+
+ if config.protocols:
+ for r in results:
+ if r.get("status") != "OK":
+ continue
+ for p in filter_protocols(r.get("protocols_data", []), config.protocol_filter):
+ data["protocols"].append({
+ "address": r["address"],
+ "name": p.get("name", ""),
+ "chain": p.get("chain", ""),
+ "value": p.get("value", 0),
+ })
+
+ if config.nft:
+ for r in results:
+ if r.get("status") != "OK":
+ continue
+ for n in filter_nft(r.get("nft_data", []), config.nft_filter):
+ data["nft"].append({
+ "address": r["address"],
+ "collection": n.get("name", ""),
+ "chain": n.get("chain", ""),
+ "amount": n.get("amount", 0),
+ })
+
+ return data
diff --git a/debank_checker/export/config.py b/debank_checker/export/config.py
new file mode 100644
index 0000000..9bd1fec
--- /dev/null
+++ b/debank_checker/export/config.py
@@ -0,0 +1,65 @@
+"""
+Конфигурация экспорта — что включать в результат
+"""
+
+from dataclasses import dataclass
+
+
+@dataclass
+class ExportConfig:
+ """Настройки экспорта по выбору пользователя в меню."""
+
+ # 1 — только общий баланс
+ total_only: bool = False
+ # 2 — Summary по кошелькам
+ summary: bool = True
+ # 3 — конкретный токен (symbol:chain)
+ token_filter: str | None = None # "ETH:eth" или None
+ # 4 — все токены
+ tokens: bool = True
+ # 5 — все NFT
+ nft: bool = True
+ # 6 — конкретный NFT (collection:chain)
+ nft_filter: str | None = None # "Bored Ape:eth" или None
+ # 7 — DeFi-позиции (name:chain или :chain для всех в сети)
+ protocol_filter: str | None = None # "Uniswap:eth" или ":eth"
+ protocols: bool = True
+
+ @classmethod
+ def from_menu_choice(
+ cls,
+ choice: int,
+ token_filter: str | None = None,
+ nft_filter: str | None = None,
+ protocol_filter: str | None = None,
+ ) -> "ExportConfig":
+ """Создать конфиг по номеру пункта меню (1–11)."""
+ configs = {
+ 1: cls(summary=True, tokens=False, nft=False, protocols=False),
+ 2: cls(summary=False, token_filter=token_filter or None, tokens=True, nft=False, protocols=False),
+ 3: cls(summary=False, tokens=True, nft=False, protocols=False),
+ 4: cls(summary=False, token_filter=token_filter or None, tokens=True, nft=False, protocols=False),
+ 5: cls(summary=False, tokens=False, nft=True, protocols=False),
+ 6: cls(summary=False, tokens=False, nft_filter=nft_filter or None, nft=True, protocols=False),
+ 7: cls(summary=False, tokens=False, nft_filter=nft_filter or None, nft=True, protocols=False),
+ 8: cls(summary=False, tokens=False, nft=False, protocol_filter=None, protocols=True),
+ 9: cls(summary=False, tokens=False, nft=False, protocol_filter=protocol_filter, protocols=True),
+ 10: cls(summary=False, tokens=False, nft=False, protocol_filter=protocol_filter or None, protocols=True),
+ 11: cls(summary=False, tokens=True, nft=True, protocols=True),
+ }
+ return configs.get(choice, configs[11])
+
+ def get_filename_suffix(self) -> str:
+ """Суффикс для имени файла: Total, Summary, Tokens, NFT, DeFi или комбинация."""
+ if self.total_only:
+ return "Total"
+ if self.summary and not any([self.tokens, self.protocols, self.nft]):
+ return "Summary"
+ parts: list[str] = []
+ if self.tokens:
+ parts.append("Tokens")
+ if self.protocols:
+ parts.append("DeFi")
+ if self.nft:
+ parts.append("NFT")
+ return "_".join(parts) if parts else "Summary"
diff --git a/debank_checker/export/csv_exporter.py b/debank_checker/export/csv_exporter.py
new file mode 100644
index 0000000..cdc5cf0
--- /dev/null
+++ b/debank_checker/export/csv_exporter.py
@@ -0,0 +1,69 @@
+"""
+Экспорт результатов в CSV
+"""
+
+import csv
+import datetime
+from pathlib import Path
+
+from debank_checker.export.common import build_export_data
+from debank_checker.export.config import ExportConfig
+
+
+def export_to_csv(
+ results: list[dict],
+ output_dir: Path | str = ".",
+ config: ExportConfig | None = None,
+) -> Path:
+ """
+ Экспорт в CSV по ExportConfig.
+ Создаёт один или несколько CSV-файлов в зависимости от config.
+ """
+ config = config or ExportConfig(summary=True, tokens=True, nft=True, protocols=True)
+ output_dir = Path(output_dir)
+ ts = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
+ suffix = config.get_filename_suffix()
+ base = f"debank_{suffix}_{ts}"
+
+ data = build_export_data(results, config)
+ written: list[Path] = []
+
+ if config.total_only:
+ path = output_dir / f"{base}.csv"
+ with open(path, "w", encoding="utf-8", newline="") as f:
+ w = csv.writer(f)
+ w.writerow(["Параметр", "Значение"])
+ w.writerow(["Суммарный баланс", data["total"]["sum_usd"]])
+ w.writerow(["Успешно", f"{data['total']['ok_count']}/{data['total']['total_count']}"])
+ written.append(path)
+ else:
+ if data["summary"]:
+ path = output_dir / f"{base}_summary.csv"
+ with open(path, "w", encoding="utf-8", newline="") as f:
+ w = csv.DictWriter(f, fieldnames=["n", "address", "total_usd", "chains", "status"])
+ w.writeheader()
+ w.writerows(data["summary"])
+ written.append(path)
+ if data["tokens"]:
+ path = output_dir / f"{base}_tokens.csv"
+ with open(path, "w", encoding="utf-8", newline="") as f:
+ w = csv.DictWriter(f, fieldnames=["address", "symbol", "chain", "amount", "price", "value"])
+ w.writeheader()
+ w.writerows(data["tokens"])
+ written.append(path)
+ if data["protocols"]:
+ path = output_dir / f"{base}_protocols.csv"
+ with open(path, "w", encoding="utf-8", newline="") as f:
+ w = csv.DictWriter(f, fieldnames=["address", "name", "chain", "value"])
+ w.writeheader()
+ w.writerows(data["protocols"])
+ written.append(path)
+ if data["nft"]:
+ path = output_dir / f"{base}_nft.csv"
+ with open(path, "w", encoding="utf-8", newline="") as f:
+ w = csv.DictWriter(f, fieldnames=["address", "collection", "chain", "amount"])
+ w.writeheader()
+ w.writerows(data["nft"])
+ written.append(path)
+
+ return written[0] if written else output_dir / f"{base}.csv"
diff --git a/debank_checker/export/excel.py b/debank_checker/export/excel.py
new file mode 100644
index 0000000..a37494c
--- /dev/null
+++ b/debank_checker/export/excel.py
@@ -0,0 +1,193 @@
+"""
+Экспорт результатов в Excel
+"""
+
+import datetime
+from pathlib import Path
+
+from openpyxl import Workbook
+from openpyxl.styles import Alignment, Border, Font, PatternFill, Side
+from openpyxl.utils import get_column_letter
+
+from debank_checker.export.common import filter_nft, filter_protocols, filter_tokens
+from debank_checker.export.config import ExportConfig
+
+
+def export_to_excel(
+ results: list[dict],
+ output_dir: Path | str = ".",
+ config: ExportConfig | None = None,
+) -> Path:
+ """
+ Экспорт в Excel по ExportConfig.
+ Если config=None — экспорт всего (как раньше).
+ """
+ config = config or ExportConfig(summary=True, tokens=True, nft=True, protocols=True)
+ output_dir = Path(output_dir)
+ suffix = config.get_filename_suffix()
+ filename = f"debank_{suffix}_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
+ filepath = output_dir / filename
+
+ wb = Workbook()
+
+ if config.total_only:
+ _add_total_only_sheet(wb, results)
+ else:
+ default_sheet = wb.active
+ if config.summary:
+ _style_summary_sheet(wb, results)
+ elif not any([config.tokens, config.protocols, config.nft]):
+ _style_summary_sheet(wb, results)
+ if config.tokens:
+ _add_tokens_sheet(wb, results, config.token_filter)
+ if config.protocols:
+ _add_protocols_sheet(wb, results, config.protocol_filter)
+ if config.nft:
+ _add_nft_sheet(wb, results, config.nft_filter)
+ if not config.summary and any([config.tokens, config.protocols, config.nft]) and default_sheet in wb.worksheets:
+ wb.remove(default_sheet)
+
+ wb.save(filepath)
+ return filepath
+
+
+def _add_total_only_sheet(wb: Workbook, results: list[dict]) -> None:
+ """Лист только с общим балансом."""
+ ws = wb.active
+ ws.title = "Total"
+ total = sum(r["total_usd"] for r in results if r and r.get("status") == "OK")
+ ok = sum(1 for r in results if r and r.get("status") == "OK")
+ ws.cell(row=1, column=1, value="Суммарный баланс").font = Font(bold=True)
+ ws.cell(row=1, column=2, value=total).number_format = "#,##0.00"
+ ws.cell(row=2, column=1, value="Успешно")
+ ws.cell(row=2, column=2, value=f"{ok}/{len(results)}")
+ ws.column_dimensions["A"].width = 20
+ ws.column_dimensions["B"].width = 18
+
+
+def _style_summary_sheet(wb: Workbook, results: list[dict]) -> None:
+ ws = wb.active
+ ws.title = "Summary"
+
+ header_font = Font(name="Calibri", bold=True, color="FFFFFF", size=11)
+ header_fill = PatternFill("solid", fgColor="1A73E8")
+ ok_fill = PatternFill("solid", fgColor="E6F4EA")
+ err_fill = PatternFill("solid", fgColor="FCE8E6")
+ center = Alignment(horizontal="center", vertical="center")
+ left = Alignment(horizontal="left", vertical="center")
+ thin = Side(style="thin")
+ border = Border(left=thin, right=thin, top=thin, bottom=thin)
+
+ headers = ["#", "Адрес", "USD баланс", "Chains", "Статус"]
+ for ci, h in enumerate(headers, 1):
+ c = ws.cell(row=1, column=ci, value=h)
+ c.font = header_font
+ c.fill = header_fill
+ c.alignment = center
+ c.border = border
+ ws.column_dimensions[get_column_letter(ci)].width = max(15, len(h) + 2)
+
+ ws.column_dimensions["B"].width = 45
+ ws.column_dimensions["C"].width = 18
+
+ for ri, r in enumerate(results, 2):
+ row_fill = ok_fill if r["status"] == "OK" else err_fill
+ values = [
+ ri - 1,
+ r["address"],
+ r["total_usd"] if r["status"] == "OK" else None,
+ r.get("chains", ""),
+ r["status"],
+ ]
+ for ci, val in enumerate(values, 1):
+ c = ws.cell(row=ri, column=ci, value=val)
+ c.fill = row_fill
+ c.border = border
+ c.alignment = center if ci in (1, 3, 5) else left
+ if ci == 3 and isinstance(val, (int, float)):
+ c.number_format = "#,##0.00"
+
+ total_sum = sum(x["total_usd"] for x in results if x["status"] == "OK")
+ ok_count = sum(1 for x in results if x["status"] == "OK")
+ summary_row = len(results) + 2
+ ws.cell(row=summary_row, column=1, value="ИТОГО").font = Font(bold=True)
+ ws.cell(row=summary_row, column=2, value=f"{ok_count}/{len(results)} успешно")
+ sc = ws.cell(row=summary_row, column=3, value=total_sum)
+ sc.font = Font(bold=True)
+ sc.number_format = "#,##0.00"
+
+ ws.freeze_panes = "A2"
+
+
+def _add_tokens_sheet(wb: Workbook, results: list[dict], token_filter: str | None = None) -> None:
+ ws = wb.create_sheet("Tokens", 1)
+ headers = ["Адрес", "Symbol", "Chain", "Amount", "Price", "Value USD"]
+ for ci, h in enumerate(headers, 1):
+ ws.cell(row=1, column=ci, value=h).font = Font(bold=True)
+ ws.column_dimensions[get_column_letter(ci)].width = 15
+ ws.column_dimensions["A"].width = 45
+
+ row = 2
+ for r in results:
+ if r["status"] != "OK":
+ continue
+ tokens = filter_tokens(r.get("tokens_data", []), token_filter)
+ for t in tokens:
+ ws.cell(row=row, column=1, value=r["address"])
+ ws.cell(row=row, column=2, value=t.get("symbol", ""))
+ ws.cell(row=row, column=3, value=t.get("chain", ""))
+ ws.cell(row=row, column=4, value=t.get("amount", 0))
+ ws.cell(row=row, column=5, value=t.get("price", 0))
+ ws.cell(row=row, column=6, value=t.get("value", 0))
+ row += 1
+
+ if token_filter and row == 2:
+ ws.cell(row=2, column=1, value=f"Нет совпадений по фильтру {token_filter}. Проверьте symbol и chain.")
+
+
+def _add_protocols_sheet(wb: Workbook, results: list[dict], protocol_filter: str | None = None) -> None:
+ ws = wb.create_sheet("Protocols", 2)
+ headers = ["Адрес", "Протокол", "Chain", "Value USD"]
+ for ci, h in enumerate(headers, 1):
+ ws.cell(row=1, column=ci, value=h).font = Font(bold=True)
+ ws.column_dimensions[get_column_letter(ci)].width = 20
+ ws.column_dimensions["A"].width = 45
+
+ row = 2
+ for r in results:
+ if r["status"] != "OK":
+ continue
+ protocols = filter_protocols(r.get("protocols_data", []), protocol_filter)
+ for p in protocols:
+ ws.cell(row=row, column=1, value=r["address"])
+ ws.cell(row=row, column=2, value=p.get("name", ""))
+ ws.cell(row=row, column=3, value=p.get("chain", ""))
+ ws.cell(row=row, column=4, value=p.get("value", 0))
+ row += 1
+
+ if protocol_filter and row == 2:
+ ws.cell(row=2, column=1, value=f"Нет совпадений по фильтру {protocol_filter}. Проверьте protocol и chain.")
+
+
+def _add_nft_sheet(wb: Workbook, results: list[dict], nft_filter: str | None = None) -> None:
+ ws = wb.create_sheet("NFT", 3)
+ headers = ["Адрес", "Collection", "Chain", "Amount"]
+ for ci, h in enumerate(headers, 1):
+ ws.cell(row=1, column=ci, value=h).font = Font(bold=True)
+ ws.column_dimensions[get_column_letter(ci)].width = 20
+ ws.column_dimensions["A"].width = 45
+
+ row = 2
+ for r in results:
+ if r["status"] != "OK":
+ continue
+ nfts = filter_nft(r.get("nft_data", []), nft_filter)
+ for n in nfts:
+ ws.cell(row=row, column=1, value=r["address"])
+ ws.cell(row=row, column=2, value=n.get("name", ""))
+ ws.cell(row=row, column=3, value=n.get("chain", ""))
+ ws.cell(row=row, column=4, value=n.get("amount", 0))
+ row += 1
+
+ if nft_filter and row == 2:
+ ws.cell(row=2, column=1, value=f"Нет совпадений по фильтру {nft_filter}. Проверьте collection и chain.")
diff --git a/debank_checker/export/json_exporter.py b/debank_checker/export/json_exporter.py
new file mode 100644
index 0000000..717d23c
--- /dev/null
+++ b/debank_checker/export/json_exporter.py
@@ -0,0 +1,48 @@
+"""
+Экспорт результатов в JSON
+"""
+
+import datetime
+import json
+from pathlib import Path
+
+from debank_checker.export.common import build_export_data
+from debank_checker.export.config import ExportConfig
+
+
+def _json_serial(obj):
+ """Сериализация для JSON (float, etc)."""
+ if isinstance(obj, float):
+ return round(obj, 6) if obj == obj else None # NaN check
+ raise TypeError(f"Object of type {type(obj)} is not JSON serializable")
+
+
+def export_to_json(
+ results: list[dict],
+ output_dir: Path | str = ".",
+ config: ExportConfig | None = None,
+) -> Path:
+ """
+ Экспорт в JSON по ExportConfig.
+ Один файл со структурой { total, summary, tokens, protocols, nft }.
+ """
+ config = config or ExportConfig(summary=True, tokens=True, nft=True, protocols=True)
+ output_dir = Path(output_dir)
+ ts = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
+ suffix = config.get_filename_suffix()
+ filepath = output_dir / f"debank_{suffix}_{ts}.json"
+
+ data = build_export_data(results, config)
+ out = {
+ "exported_at": datetime.datetime.now().isoformat(),
+ "total": data["total"],
+ "summary": data["summary"],
+ "tokens": data["tokens"],
+ "protocols": data["protocols"],
+ "nft": data["nft"],
+ }
+
+ with open(filepath, "w", encoding="utf-8") as f:
+ json.dump(out, f, ensure_ascii=False, indent=2, default=_json_serial)
+
+ return filepath
diff --git a/debank_checker/proxy/__init__.py b/debank_checker/proxy/__init__.py
new file mode 100644
index 0000000..cff54de
--- /dev/null
+++ b/debank_checker/proxy/__init__.py
@@ -0,0 +1,5 @@
+"""Прокси: загрузка, ротация, rate limiting."""
+
+from debank_checker.proxy.manager import ProxyManager, load_proxies
+
+__all__ = ["ProxyManager", "load_proxies"]
diff --git a/debank_checker/proxy/manager.py b/debank_checker/proxy/manager.py
new file mode 100644
index 0000000..531820e
--- /dev/null
+++ b/debank_checker/proxy/manager.py
@@ -0,0 +1,116 @@
+"""
+Менеджер прокси: загрузка, ротация, rate limiting
+"""
+
+import threading
+import time
+from collections import deque
+from pathlib import Path
+
+from debank_checker.config import DEBUG, PROXIES_FILE, RATE_LIMIT_REQ_PER_MIN
+
+
+def load_proxies(path: str | Path = PROXIES_FILE) -> list[str]:
+ """
+ Читает прокси из файла.
+ Формат: ip:port:login:password или ip:port
+ Возвращает список "http://login:password@ip:port"
+ """
+ path = Path(path)
+ proxies = []
+ if not path.exists():
+ return proxies
+ with open(path, encoding="utf-8") as f:
+ for line in f:
+ line = line.strip()
+ if not line or line.startswith("#"):
+ continue
+ parts = line.split(":")
+ if len(parts) == 4:
+ ip, port, login, password = parts
+ proxies.append(f"http://{login}:{password}@{ip}:{port}")
+ elif len(parts) == 2:
+ proxies.append(f"http://{parts[0]}:{parts[1]}")
+ return proxies
+
+
+class ProxyManager:
+ """
+ Ротация прокси с учётом rate limit.
+ get_proxy() возвращает прокси с наименьшей нагрузкой.
+ report_timeout() временно исключает прокси из выдачи (см. docs/DEBUG_REPORT.md).
+ """
+
+ PROXY_COOLDOWN_AFTER_TIMEOUT = 60 # секунд, не выдавать прокси после таймаута
+
+ def __init__(
+ self,
+ proxies: list[str],
+ req_per_min: int = RATE_LIMIT_REQ_PER_MIN,
+ ):
+ if not proxies:
+ self._proxies = []
+ self._timestamps: dict[str, deque] = {}
+ self._timeout_until: dict[str, float] = {}
+ return
+ self._proxies = list(proxies)
+ self._req_per_min = req_per_min
+ self._lock = threading.Lock()
+ self._timestamps: dict[str, deque[float]] = {
+ p: deque(maxlen=req_per_min * 2) for p in self._proxies
+ }
+ self._timeout_until: dict[str, float] = {} # proxy -> time.time() когда снова доступен
+ self._idx = 0
+
+ def report_timeout(self, proxy: str | None) -> None:
+ """Исключить прокси из выдачи на PROXY_COOLDOWN_AFTER_TIMEOUT сек."""
+ if not proxy:
+ return
+ with self._lock:
+ self._timeout_until[proxy] = time.time() + self.PROXY_COOLDOWN_AFTER_TIMEOUT
+
+ def get_proxy(self) -> str | None:
+ """Возвращает прокси с наименьшей нагрузкой (round-robin с учётом rate limit)."""
+ if not self._proxies:
+ return None
+ t0 = time.perf_counter()
+ with self._lock:
+ now = time.time()
+ cutoff = now - 60
+ best = None
+ best_count = float("inf")
+ for _ in range(len(self._proxies)):
+ p = self._proxies[self._idx % len(self._proxies)]
+ self._idx += 1
+ if self._timeout_until.get(p, 0) > now:
+ continue
+ ts = self._timestamps[p]
+ while ts and ts[0] < cutoff:
+ ts.popleft()
+ if len(ts) < best_count and len(ts) < self._req_per_min:
+ best = p
+ best_count = len(ts)
+ break
+ forced = best is None
+ if best is None:
+ available = [p for p in self._proxies if self._timeout_until.get(p, 0) <= now]
+ best = available[0] if available else min(
+ self._proxies, key=lambda p: self._timeout_until.get(p, 0)
+ )
+ self._timestamps[best].append(now)
+ result = best
+ if DEBUG:
+ elapsed = time.perf_counter() - t0
+ load = len(self._timestamps[result])
+ if elapsed > 0.01 or forced or load >= self._req_per_min:
+ import sys
+ short = result.split("@")[-1] if "@" in result else result
+ flags = []
+ if forced:
+ flags.append("FORCED")
+ if load >= self._req_per_min:
+ flags.append(f"LOAD={load}")
+ flag_str = " | " + ", ".join(flags) if flags else ""
+ sys.stderr.write(f"[DEBUG] get_proxy | {elapsed:.3f}s | {short}{flag_str}\n")
+ sys.stderr.flush()
+ return result
diff --git a/debank_checker/ui/__init__.py b/debank_checker/ui/__init__.py
new file mode 100644
index 0000000..06fcadf
--- /dev/null
+++ b/debank_checker/ui/__init__.py
@@ -0,0 +1,6 @@
+"""UI: баннер, логирование."""
+
+from debank_checker.ui.banner import create_progress_bar, show
+from debank_checker.ui.logger import error, info, success, warning
+
+__all__ = ["create_progress_bar", "show", "error", "info", "success", "warning"]
diff --git a/debank_checker/ui/banner.py b/debank_checker/ui/banner.py
new file mode 100644
index 0000000..e35bbf5
--- /dev/null
+++ b/debank_checker/ui/banner.py
@@ -0,0 +1,85 @@
+"""
+ASCII-заставка в стиле Season7
+"""
+
+import sys
+
+# ANSI цвета
+RESET = "\033[0m"
+BRIGHT = "\033[1m"
+DIM = "\033[2m"
+CYAN = "\033[36m"
+YELLOW = "\033[33m"
+BLUE = "\033[34m"
+GREEN = "\033[32m"
+
+_BANNER_INDENT = " "
+_BANNER_LINES = [
+ "██████╗ ███████╗██████╗ █████╗ ███╗ ██╗██╗ ██╗",
+ "██╔══██╗██╔════╝██╔══██╗██╔══██╗████╗ ██║██║ ██╔╝",
+ "██║ ██║█████╗ ██████╔╝███████║██╔██╗ ██║█████╔╝",
+ "██║ ██║██╔══╝ ██╔══██╗██╔══██║██║╚██╗██║██╔═██╗",
+ "██████╔╝███████╗██████╔╝██║ ██║██║ ╚████║██║ ██╗",
+ "╚═════╝ ╚══════╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝",
+]
+_BANNER_WIDTH = max(len(l) for l in _BANNER_LINES)
+
+
+def _center_text_in_banner(s: str) -> str:
+ """Центрировать строку относительно ширины ASCII-баннера (не экрана)."""
+ s = s.rstrip()
+ pad = max(0, (_BANNER_WIDTH - len(s)) // 2)
+ return f"{_BANNER_INDENT}{' ' * pad}{s}"
+
+
+def show() -> None:
+ """Показать главную заставку."""
+ if sys.platform == "win32":
+ try:
+ import os
+ os.system("cls")
+ except Exception:
+ pass
+ else:
+ print("\033[2J\033[H", end="")
+
+ print(create_main_banner())
+ print(create_subtitle())
+ print(create_separator())
+ print()
+
+
+def create_main_banner() -> str:
+ """Главный баннер DeBank Checker."""
+ banner = "\n".join(f"{_BANNER_INDENT}{l}" for l in _BANNER_LINES)
+ return f"\n{CYAN}{BRIGHT}{banner}{RESET}"
+
+
+def create_subtitle() -> str:
+ """Подзаголовок."""
+ return "\n".join(
+ [
+ _center_text_in_banner(f"{YELLOW}{BRIGHT}BALANCE CHECKER v1.1.0{RESET}"),
+ _center_text_in_banner(f"{DIM}EVM · Tokens · DeFi · NFT{RESET}"),
+ _center_text_in_banner(f"{DIM}TG: https://t.me/privatekey_ai{RESET}"),
+ ]
+ )
+
+
+def create_separator() -> str:
+ """Разделитель."""
+ return f"{_BANNER_INDENT}{BLUE}{'=' * _BANNER_WIDTH}{RESET}"
+
+
+def create_progress_bar(current: int, total: int, width: int = 50) -> str:
+ """Прогресс-бар в стиле Season7."""
+ if total <= 0:
+ pct = 0
+ filled = 0
+ empty = width
+ else:
+ pct = round((current / total) * 100)
+ filled = round((current / total) * width)
+ empty = width - filled
+ bar = f"{GREEN}{'█' * filled}{DIM}{'░' * empty}{RESET}"
+ return f"[{bar}] {pct}% ({current}/{total})"
diff --git a/debank_checker/ui/logger.py b/debank_checker/ui/logger.py
new file mode 100644
index 0000000..15131ba
--- /dev/null
+++ b/debank_checker/ui/logger.py
@@ -0,0 +1,40 @@
+"""
+Логирование в формате: YYYY-MM-DD HH:MM:SS | LEVEL | Сообщение
+Цвета: INFO — белый, WARNING — оранжевый, SUCCESS — зелёный, ERROR — красный
+"""
+
+import sys
+from datetime import datetime
+
+# ANSI коды
+RESET = "\033[0m"
+WHITE = "\033[37m"
+BRIGHT = "\033[1m"
+ORANGE = "\033[38;5;208m" # 256-color orange
+GREEN = "\033[32m"
+RED = "\033[31m"
+
+
+def _timestamp() -> str:
+ return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+
+
+def _log(level: str, msg: str, color: str) -> None:
+ line = f"{_timestamp()} | {level:<7} | {msg}"
+ print(f"{color}{line}{RESET}", file=sys.stderr, flush=True)
+
+
+def info(msg: str) -> None:
+ _log("INFO", msg, WHITE + BRIGHT)
+
+
+def warning(msg: str) -> None:
+ _log("WARNING", msg, ORANGE + BRIGHT)
+
+
+def success(msg: str) -> None:
+ _log("SUCCESS", msg, GREEN + BRIGHT)
+
+
+def error(msg: str) -> None:
+ _log("ERROR", msg, RED + BRIGHT)
diff --git a/debank_checker/ui/menu.py b/debank_checker/ui/menu.py
new file mode 100644
index 0000000..3589f17
--- /dev/null
+++ b/debank_checker/ui/menu.py
@@ -0,0 +1,273 @@
+"""
+Консольное меню выбора экспорта.
+Вызывается после проверки кошельков — данные уже получены.
+Двухшаговый выбор: сначала сеть, затем токен/NFT/протокол в этой сети.
+"""
+
+import questionary
+
+from debank_checker.export.config import ExportConfig
+
+# Разделитель для фильтра (symbol:chain)
+_SEP = ":"
+_ALL_IN_CHAIN = "← Все в этой сети"
+
+
+def _get_chains_from_tokens(results: list[dict] | None) -> list[str]:
+ """Уникальные сети из токенов."""
+ chains: set[str] = set()
+ if not results:
+ return []
+ for r in results:
+ if r.get("status") != "OK":
+ continue
+ for t in r.get("tokens_data", []):
+ ch = (t.get("chain") or "").strip().lower()
+ if ch:
+ chains.add(ch)
+ return sorted(chains)
+
+
+def _get_chains_from_nft(results: list[dict] | None) -> list[str]:
+ """Уникальные сети из NFT."""
+ chains: set[str] = set()
+ if not results:
+ return []
+ for r in results:
+ if r.get("status") != "OK":
+ continue
+ for n in r.get("nft_data", []):
+ ch = (n.get("chain") or "").strip().lower()
+ if ch:
+ chains.add(ch)
+ return sorted(chains)
+
+
+def _get_chains_from_protocols(results: list[dict] | None) -> list[str]:
+ """Уникальные сети из DeFi-протоколов."""
+ chains: set[str] = set()
+ if not results:
+ return []
+ for r in results:
+ if r.get("status") != "OK":
+ continue
+ for p in r.get("protocols_data", []):
+ ch = (p.get("chain") or "").strip().lower()
+ if ch:
+ chains.add(ch)
+ return sorted(chains)
+
+
+def _build_token_options_for_chain(results: list[dict] | None, chain: str) -> list[str]:
+ """Токены в указанной сети: SYMBOL (из реальных данных)."""
+ seen: set[str] = set()
+ options: list[str] = []
+ if not results:
+ return options
+ chain_l = chain.lower()
+ for r in results:
+ if r.get("status") != "OK":
+ continue
+ for t in r.get("tokens_data", []):
+ if (t.get("chain") or "").lower() != chain_l:
+ continue
+ symbol = (t.get("symbol") or "").strip().upper()
+ if symbol and symbol not in seen:
+ seen.add(symbol)
+ options.append(symbol)
+ return sorted(options)
+
+
+def _build_nft_options_for_chain(results: list[dict] | None, chain: str) -> list[str]:
+ """NFT-коллекции в указанной сети (из реальных данных)."""
+ seen: set[str] = set()
+ options: list[str] = []
+ if not results:
+ return options
+ chain_l = chain.lower()
+ for r in results:
+ if r.get("status") != "OK":
+ continue
+ for n in r.get("nft_data", []):
+ if (n.get("chain") or "").lower() != chain_l:
+ continue
+ name = (n.get("name") or "").strip()
+ if name and name not in seen:
+ seen.add(name)
+ options.append(name)
+ return sorted(options)
+
+
+def _build_protocol_options_for_chain(results: list[dict] | None, chain: str) -> list[str]:
+ """DeFi-протоколы в указанной сети (из реальных данных)."""
+ seen: set[str] = set()
+ options: list[str] = []
+ if not results:
+ return options
+ chain_l = chain.lower()
+ for r in results:
+ if r.get("status") != "OK":
+ continue
+ for p in r.get("protocols_data", []):
+ if (p.get("chain") or "").lower() != chain_l:
+ continue
+ name = (p.get("name") or "").strip()
+ if name and name not in seen:
+ seen.add(name)
+ options.append(name)
+ return sorted(options)
+
+
+def _select(title: str, options: list[str]) -> str | None:
+ """Выбор из списка с помощью questionary."""
+ if not options:
+ return None
+ result = questionary.select(title, choices=options).ask()
+ return result
+
+
+FORMAT_OPTIONS = [
+ "CSV",
+ "Excel",
+ "JSON",
+]
+
+AGAIN_OPTIONS = [
+ "1. Продолжить",
+ "2. Выйти",
+]
+
+MAIN_OPTIONS = [
+ "1. Summary (адрес, баланс, chains, статус)",
+ "2. Конкретный токен (сеть → токен)",
+ "3. Все токены",
+ "4. Все токены в конкретной сети",
+ "5. Все NFT",
+ "6. Конкретный NFT (сеть → коллекция)",
+ "7. Все NFT в конкретной сети",
+ "8. Все DeFi-позиции",
+ "9. Конкретный DeFi (сеть → протокол)",
+ "10. Все DeFi в конкретной сети",
+ "11. Всё (Tokens + Protocols + NFT)",
+]
+
+
+def show_menu(results: list[dict] | None = None) -> ExportConfig:
+ """
+ Интерактивное меню: двухшаговый выбор.
+ Шаг 1: выбор сети. Шаг 2: выбор токена/NFT/протокола в этой сети.
+ """
+ choice_str = _select("Что экспортировать? (↑↓ — выбор, Enter — подтвердить)", MAIN_OPTIONS)
+ if not choice_str:
+ choice_str = MAIN_OPTIONS[0]
+ choice = int(choice_str.split(".")[0].strip())
+
+ token_filter = None
+ nft_filter = None
+ protocol_filter = None
+
+ if choice == 2:
+ chains = _get_chains_from_tokens(results)
+ if not chains:
+ print(" Нет токенов в данных. Экспорт всех токенов (п.3).")
+ choice = 3
+ else:
+ chain = _select("Шаг 1: Выберите сеть", chains)
+ if not chain:
+ choice = 3
+ else:
+ tokens = _build_token_options_for_chain(results, chain)
+ if not tokens:
+ print(" Нет токенов в этой сети. Экспорт всех токенов (п.3).")
+ choice = 3
+ else:
+ symbol = _select("Шаг 2: Выберите токен", tokens)
+ if symbol:
+ token_filter = f"{symbol}{_SEP}{chain}"
+
+ elif choice == 4:
+ chains = _get_chains_from_tokens(results)
+ if not chains:
+ print(" Нет токенов в данных. Экспорт всех токенов (п.3).")
+ choice = 3
+ else:
+ chain = _select("Выберите сеть", chains)
+ if chain:
+ token_filter = f"{_SEP}{chain}"
+
+ elif choice == 6:
+ chains = _get_chains_from_nft(results)
+ if not chains:
+ print(" Нет NFT в данных. Экспорт всех NFT (п.5).")
+ choice = 5
+ else:
+ chain = _select("Шаг 1: Выберите сеть", chains)
+ if not chain:
+ choice = 5
+ else:
+ nfts = _build_nft_options_for_chain(results, chain)
+ if not nfts:
+ print(" Нет NFT в этой сети. Экспорт всех NFT (п.5).")
+ choice = 5
+ else:
+ collection = _select("Шаг 2: Выберите NFT-коллекцию", nfts)
+ if collection:
+ nft_filter = f"{collection}{_SEP}{chain}"
+
+ elif choice == 7:
+ chains = _get_chains_from_nft(results)
+ if not chains:
+ print(" Нет NFT в данных. Экспорт всех NFT (п.5).")
+ choice = 5
+ else:
+ chain = _select("Выберите сеть", chains)
+ if chain:
+ nft_filter = f"{_SEP}{chain}"
+
+ elif choice == 9:
+ chains = _get_chains_from_protocols(results)
+ if not chains:
+ print(" Нет DeFi-позиций в данных. Экспорт всех DeFi (п.8).")
+ choice = 8
+ else:
+ chain = _select("Шаг 1: Выберите сеть", chains)
+ if not chain:
+ choice = 8
+ else:
+ protocols = _build_protocol_options_for_chain(results, chain)
+ if not protocols:
+ print(" Нет протоколов в этой сети. Экспорт всех DeFi (п.8).")
+ choice = 8
+ else:
+ options = [_ALL_IN_CHAIN] + protocols
+ selected = _select("Шаг 2: Выберите протокол или «Все в этой сети»", options)
+ if selected == _ALL_IN_CHAIN:
+ protocol_filter = f"{_SEP}{chain}"
+ elif selected:
+ protocol_filter = f"{selected}{_SEP}{chain}"
+
+ elif choice == 10:
+ chains = _get_chains_from_protocols(results)
+ if not chains:
+ print(" Нет DeFi-позиций в данных. Экспорт всех DeFi (п.8).")
+ choice = 8
+ else:
+ chain = _select("Выберите сеть", chains)
+ if chain:
+ protocol_filter = f"{_SEP}{chain}"
+
+ return ExportConfig.from_menu_choice(choice, token_filter, nft_filter, protocol_filter)
+
+
+def ask_format() -> str:
+ """Выбор формата экспорта: csv, excel, json."""
+ choice = _select("В какой формат экспортировать?", FORMAT_OPTIONS)
+ if not choice:
+ return "excel"
+ return choice.lower()
+
+
+def ask_continue() -> bool:
+ """Спросить: продолжить или выйти. True = продолжить."""
+ choice = _select("Продолжить?", AGAIN_OPTIONS)
+ return choice == AGAIN_OPTIONS[0] if choice else False
diff --git a/main.py b/main.py
index ee20995..f8f6843 100644
--- a/main.py
+++ b/main.py
@@ -1,4 +1,146 @@
-from app.main import main
+"""
+DeBank Balance Checker — точка входа
+"""
+
+import sys
+import threading
+import time
+from concurrent.futures import ThreadPoolExecutor, as_completed
+from pathlib import Path
+
+from debank_checker.checker import check_wallet
+from debank_checker.config import (
+ DEBUG,
+ MAX_WORKERS,
+ OUTPUT_DIR,
+ PROXIES_FILE,
+ PROXY_MULTIPLIER,
+ WALLETS_FILE,
+)
+from debank_checker.export.csv_exporter import export_to_csv
+from debank_checker.export.excel import export_to_excel
+from debank_checker.export.json_exporter import export_to_json
+from debank_checker.proxy.manager import load_proxies, ProxyManager
+from debank_checker.ui.banner import create_progress_bar, show
+from debank_checker.ui.logger import error, info, success
+from debank_checker.ui.menu import ask_continue, ask_format, show_menu
+
+def setup_encoding() -> None:
+ """UTF-8 и colorama для Windows."""
+ if sys.platform == "win32":
+ try:
+ import colorama
+ colorama.init()
+ except ImportError:
+ pass
+ try:
+ sys.stdout.reconfigure(encoding="utf-8", errors="replace")
+ sys.stderr.reconfigure(encoding="utf-8", errors="replace")
+ except Exception:
+ pass
+
+
+def load_wallets(path: str | Path = WALLETS_FILE) -> list[str]:
+ """Читает адреса из файла."""
+ path = Path(path)
+ wallets = []
+ if not path.exists():
+ return wallets
+ with open(path, encoding="utf-8") as f:
+ for line in f:
+ line = line.strip()
+ if line and not line.startswith("#"):
+ wallets.append(line)
+ return wallets
+
+
+def main() -> None:
+ setup_encoding()
+ show()
+
+ wallets = load_wallets()
+ proxies = load_proxies()
+
+ if not wallets:
+ error("Нет кошельков для проверки. Добавь адреса в wallets.txt")
+ sys.exit(1)
+
+ if not proxies:
+ error("Прокси обязательны. Добавь прокси в proxy.txt")
+ sys.exit(1)
+
+ info(f"Кошельков: {len(wallets)} | Прокси: {len(proxies)}")
+
+ max_workers = min(MAX_WORKERS, len(wallets), len(proxies) * PROXY_MULTIPLIER)
+ max_workers = max(1, max_workers)
+ info(f"Параллельных воркеров: {max_workers}")
+
+ proxy_manager = ProxyManager(proxies)
+ results: list[dict] = [None] * len(wallets)
+ completed = [0]
+ lock = threading.Lock()
+
+ def process(idx: int, address: str) -> None:
+ start = time.perf_counter()
+ row = check_wallet(address, proxy_manager, wallet_idx=idx)
+ results[idx] = row
+ if DEBUG:
+ elapsed = time.perf_counter() - start
+ sys.stderr.write(f"[DEBUG] #{idx} DONE | {elapsed:.2f}s total | status={row['status']}\n")
+ sys.stderr.flush()
+ with lock:
+ completed[0] += 1
+ done = completed[0]
+ total = len(wallets)
+ bar = create_progress_bar(done, total)
+ print(f"\r{bar}", end="", flush=True)
+
+ print("\r" + create_progress_bar(0, len(wallets)), end="", flush=True)
+
+ with ThreadPoolExecutor(max_workers=max_workers) as executor:
+ futures = {
+ executor.submit(process, i, w): i
+ for i, w in enumerate(wallets)
+ }
+ for future in as_completed(futures):
+ future.result()
+
+ print()
+
+ ok_count = sum(1 for r in results if r and r["status"] == "OK")
+ total_sum = sum(r["total_usd"] for r in results if r and r["status"] == "OK")
+
+ info(f"Итого: {ok_count}/{len(results)} успешно | Суммарный баланс: ${total_sum:,.2f}")
+
+ output_path = Path(OUTPUT_DIR)
+ output_path.mkdir(parents=True, exist_ok=True)
+
+ while True:
+ export_config = show_menu(results)
+ fmt = ask_format()
+
+ if fmt == "csv":
+ out_path = export_to_csv(results, output_path, config=export_config)
+ success(f"CSV сохранён: {out_path.resolve()}")
+ elif fmt == "json":
+ out_path = export_to_json(results, output_path, config=export_config)
+ success(f"JSON сохранён: {out_path.resolve()}")
+ else:
+ out_path = export_to_excel(results, output_path, config=export_config)
+ success(f"Excel сохранён: {out_path.resolve()}")
+
+ if not ask_continue():
+ break
+
+ info("Готово.")
+
if __name__ == "__main__":
- main()
+ try:
+ main()
+ except KeyboardInterrupt:
+ info("Прервано пользователем")
+ sys.exit(0)
+ except Exception as e:
+ error(f"Критическая ошибка: {e}")
+ sys.exit(1)
diff --git a/requirements.txt b/requirements.txt
index 131f199..6014d71 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,8 +1,5 @@
-PySide6>=6.6
-httpx[socks]>=0.27
-openpyxl>=3.1
-PyYAML>=6.0
-python-dotenv>=1.0
-web3>=6.0,<8
-solana>=0.34
-curl-cffi>=0.7
+curl_cffi>=0.5.0
+openpyxl>=3.1.0
+colorama>=0.4.6
+questionary>=2.0.0
+pytest>=7.0