Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OneFive Wallet — MVP

Некастодиальный USDT-кошелёк (TRC-20, TRON) как Telegram Mini App, с ботом через webhook, P2P-модулем на верифицированных обменниках, смарт-контрактом эскроу и крипточеками — всё в одном Render Web Service.

Финальная архитектура

GitHub
  ↓
Render (ОДИН Web Service)
  ↓
Express (server/server.js)
  ├── /api/*              REST API (wallet, p2p, checks, merchants, admin)
  ├── /telegram/webhook    Приём апдейтов Telegram-бота
  ├── /health              Health-check для Render
  └── /app/*               Статика Mini App (miniapp/dist), собранная при деплое
       ↓
   MongoDB (Atlas) + TRON (TronGrid) + Bot API (api.telegram.org)

Admin-панель — отдельный Static Site (см. admin/), намеренно не влита в основной сервис: она не нужна ежесекундно и её проще обновлять/защищать отдельно (см. rationale в конце файла).

Структура проекта

OneFive_App/
├── server/          Backend: Express + MongoDB + TronGrid + встроенный бот (webhook)
│   └── telegram/     bot.js (хендлеры команд) + webhook.js (роут + setWebHook)
├── bot/              ⚠️ DEV-ONLY: отдельный процесс с polling, для локальной разработки
├── miniapp/          React miniapp — сам кошелёк, P2P, чеки
├── admin/            React админ-панель (отдельный деплой)
└── contracts/        Смарт-контракт эскроу (Solidity/TVM) + деплой (TronBox)

Архитектура безопасности (кратко)

  • Некастодиальность: приватные ключи/сид-фразы генерируются и хранятся ТОЛЬКО на устройстве пользователя (AES-GCM, PIN-код, Telegram CloudStorage). Backend их не видит и не хранит — проверено аудитом (grep по всему репо на секреты, см. ниже).
  • Подпись транзакций — исключительно на клиенте, backend только рассылает подписанные транзакции (/api/wallet/broadcast, под rate limit).
  • Telegram auth — каждый запрос от miniapp проверяется по HMAC подписи initData (middleware/telegramAuth.js), initDataUnsafe нигде не используется как источник авторизации.
  • Webhook защищён секретным заголовком X-Telegram-Bot-Api-Secret-Token.
  • Bot ↔ Backend — отдельный секрет BOT_API_SECRET, не пересекается с ADMIN_SECRET или Telegram-авторизацией.
  • Крипточеки — атомарные переходы статусов в MongoDB (findOneAndUpdate с условием на текущий статус) защищают от гонки двух параллельных запросов; реальная защита от двойной траты — сам блокчейн (второй sweep с уже пустого адреса физически не пройдёт).
  • Rate limiting — общий лимит на /api/*, ужесточённый на /api/wallet/broadcast и /api/checks/:address/claim.

Что уже реализовано (MVP)

  • Онбординг: создание / импорт кошелька, PIN, автоблокировка (lock из профиля)
  • Backup seed flow (просмотр по PIN + проверка нескольких слов) — см. CreateWallet.jsx
  • Баланс USDT/TRX, история операций, отправка/приём (QR)
  • P2P: лента верифицированных обменников + реальная сделка через эскроу-контракт
  • Крипточеки: создание, привязка к @username, отмена, срок действия, атомарная защита от двойной активации, уведомления через Bot API
  • Смарт-контракт эскроу с автовозвратом по таймауту (Solidity, TronBox)
  • Telegram-бот через webhook в одном процессе с API
  • Единая сборка/деплой на один Render Web Service (/api, /telegram/webhook, /app)
  • Rate limiting на чувствительных операциях
  • Аудит на утечки секретов (см. раздел ниже)
  • Админка: дашборд, пользователи, обменники (курс/топ), транзакции

⚠️ Честно: что НЕ готово для реальных денег

  • Смарт-контракт эскроу НЕ задеплоен и НЕ протестирован — код написан, но не прогнан ни в Shasta testnet, ни тем более в mainnet. Перед реальными деньгами обязательно: тестнет → unit-тесты (access control, reentrancy, double release, cancellation, fee logic) → отдельный аудит.
  • Ссылка на крипточек не протестирована в реальном Telegram-клиенте — логика написана по документации (hash-путь внутри HashRouter, чтобы не задеть лимит start_param в 64 символа), но живое поведение стоит проверить на реальном боте до масштабирования.
  • Webhook проверен на реальном Render-деплое ✅ (см. постмортем ниже).
  • Полноценные unit/integration-тесты отсутствуют — только ручной код-ревью и синтаксическая проверка (node --check + esbuild), без реального npm install (нет сети в среде разработки Claude).

🩹 Постмортем реальных проблем деплоя (для истории)

При первом реальном деплое на Render всплыли 3 отдельные проблемы подряд — фиксирую, чтобы не наступать на те же грабли:

  1. vite: not found при сборке. vite лежит в devDependencies miniapp, а Render (и большинство PaaS) выставляет NODE_ENV=production, при котором npm install пропускает devDependencies. Фикс — корневой package.json теперь ставит зависимости miniapp с флагом --include=dev.
  2. /app отдавал NOT_FOUND даже после успешной сборки. В vite.config.js не было base: '/app/' — собранный index.html ссылался на JS/CSS от корня домена, а не от /app/. Заодно поправили Express-роут, чтобы матчил и /app без слэша на конце.
  3. Пустой экран в miniapp даже после успешной раздачи /app. TronWeb/hdkey написаны под Node.js и ожидают Buffer/process/ global, которых нет в браузере — без полифиллов JS падал ещё до первого рендера React, молча, без единой ошибки на экране. Фикс — vite-plugin-node-polyfills в vite.config.js + защитный window.addEventListener('error', ...) в main.jsx, который теперь печатает текст ошибки прямо на экране (критично для дебага на телефоне без доступа к консоли разработчика).

Запуск локально

Вариант A — с dev-ботом на polling (проще для разработки)

cd server && cp .env.example .env && npm install && npm run dev
cd bot && cp .env.example .env && npm install && npm run dev   # отдельный терминал
cd miniapp && cp .env.example .env && npm install && npm run dev
cd admin && cp .env.example .env && npm install && npm run dev

Вариант B — как в production (webhook, единый процесс)

Нужен публичный HTTPS-туннель (например, ngrok http 3000) для локального теста webhook:

cd server && cp .env.example .env
# впиши PUBLIC_URL=https://<твой-ngrok-адрес>.ngrok.io
npm install && npm run dev

Бот из bot/ в этом варианте НЕ запускать — иначе будет конфликт 409 (polling и webhook с одним BOT_TOKEN одновременно).

Смарт-контракт эскроу

cd contracts && cp .env.example .env
npm install
npm run compile
npm run migrate:shasta   # ОБЯЗАТЕЛЬНО тестнет перед mainnet

После деплоя впиши адрес в server/.env (ESCROW_CONTRACT_ADDRESS) и miniapp/.env (VITE_ESCROW_CONTRACT_ADDRESS).

Деплой на Render

Service Type: Web Service Branch: main Root Directory: OneFive_App (или корень репозитория, если структура выше — корень) Build Command: npm run build Start Command: npm start Health Check Path: /health

Render сам подставляет RENDER_EXTERNAL_URL — можно не задавать PUBLIC_URL вручную, server/telegram/webhook.js подхватит его автоматически.

Полный список ENV (backend, он же единственный сервис)

Переменная Обязательна Назначение
BOT_TOKEN да токен из BotFather
MINIAPP_URL да https://<render-app>.onrender.com/app
TELEGRAM_WEBHOOK_SECRET да защита /telegram/webhook
PUBLIC_URL нет* *не нужен на Render — есть RENDER_EXTERNAL_URL автоматически
MONGODB_URI да строка подключения MongoDB Atlas
TRON_FULL_NODE да по умолчанию https://api.trongrid.io
TRON_USDT_CONTRACT да адрес USDT-TRC20
TRONGRID_API_KEY нет увеличенные лимиты TronGrid
ESCROW_CONTRACT_ADDRESS нет** **пусто, пока контракт не задеплоен в testnet/mainnet
PLATFORM_PAYMENT_ADDRESS нет адрес платформы для оплаты подписки обменников
ADMIN_SECRET да доступ к /api/admin/*
BOT_API_SECRET да server-to-server канал бот → backend
CORS_ORIGIN да домен miniapp/админки
NODE_ENV да production
PORT нет Render подставляет сам

Frontend (miniapp/.env, admin/.env) — только переменные с префиксом VITE_*, все публичные (адрес контракта, URL API). Секреты туда никогда не попадают — это проверено аудитом (раздел ниже).

Аудит безопасности — что проверено

Прогнано по всему репозиторию перед этим релизом:

  • ✅ Нет захардкоженных приватных ключей / токенов / сид-фраз
  • MONGODB_URI используется только в server/config/db.js, нигде не передаётся на фронтенд, ошибки подключения санитизируются перед логом
  • BOT_TOKEN используется только в server/telegram/, server/services/telegramNotify.js и dev-фолбэке bot/bot.js — нигде во фронтенде
  • ✅ Единственные оставшиеся localhost/127.0.0.1 — в dev-фолбэках (bot/bot.js, admin/.env дефолт) и локальной сети TronBox — все переопределяются в production через ENV
  • ✅ Все критические операции (broadcast, claim чека, fund/release эскроу) требуют проверенной Telegram initData
  • ⚠️ Rate limiting — базовый (in-memory, per-IP). Для серьёзного трафика стоит вынести в Redis — сейчас достаточно для MVP, но это грубая защита, не production-grade для высоких нагрузок

Как это работает — по шагам

/start → бот (через webhook, единый процесс с API) отправляет приветствие и кнопку 💼 Открыть кошелёк → открывает MINIAPP_URL.

Mini App открывается на /app, читает Telegram.WebApp.initData, шлёт его в заголовке x-telegram-init-data на каждый запрос к /api/*.

Wallet: кошелёк создаётся/импортируется на клиенте, ключ шифруется PIN-кодом и живёт в Telegram CloudStorage — backend знает только публичный адрес.

Checks: одноразовый TRON-адрес генерируется на клиенте, ссылка на чек содержит зашифрованный ключ в hash-пути (#/claim/адрес/ключ), backend никогда не видит ключ — только публичные метаданные для UX/уведомлений.

P2P: пока — курсы верифицированных обменников через админку + эскроу-сделка (fund/release/dispute) через смарт-контракт. Testnet-only до полного прогона тестов контракта.

Git

git add .
git commit -m "OneFive MVP: webhook bot, single Render service, checks, rate limiting, security audit"
git push origin main

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages