Разработка децентрализованного мессенджера

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка децентрализованного мессенджера
Сложная
от 2 недель до 3 месяцев
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1221
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1163
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    855
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1056
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    828

Разработка децентрализованного мессенджера

Главный вопрос при проектировании децентрализованного мессенджера — что именно децентрализовано? Хранение сообщений? Маршрутизация? Identity? Шифрование? Большинство «децентрализованных» мессенджеров централизованы в одном или нескольких из этих слоёв, просто маскируя это блокчейн-обёрткой. Честная архитектура требует явного выбора trade-offs на каждом уровне.

Протокольный стек: выбор компонентов

Transport layer

XMTP (Extensible Message Transport Protocol) — de facto стандарт для Web3 мессенджеров на 2024-2025. Поверх Waku (libp2p-based messaging network). Сообщения хранятся на XMTP нодах (федерированная сеть), идентификация — Ethereum адрес, шифрование — Double Ratchet (как в Signal).

import { Client } from '@xmtp/xmtp-js';
import { Wallet } from 'ethers';

// Создание XMTP идентификатора (подпись кошельком)
const xmtpClient = await Client.create(signer, { env: 'production' });

// Проверка: зарегистрирован ли адрес в XMTP
const isOnNetwork = await Client.canMessage(recipientAddress);

// Создание или открытие conversation
const conversation = await xmtpClient.conversations.newConversation(recipientAddress);

// Отправка сообщения
await conversation.send('Hello from Web3');

// Получение истории
const messages = await conversation.messages({ limit: 50 });

// Streaming новых сообщений
for await (const message of await conversation.streamMessages()) {
  console.log(`${message.senderAddress}: ${message.content}`);
}

Преимущество XMTP: готовая E2E шифрование, cross-app (сообщения работают между разными dApp на базе XMTP: Coinbase Wallet, Converse, Lens), не нужно строить p2p инфраструктуру.

Waku (standalone) — если нужна полностью кастомная реализация без зависимости от XMTP. Light node в браузере через @waku/sdk:

import { createLightNode, waitForRemotePeer } from '@waku/sdk';

const node = await createLightNode({ defaultBootstrap: true });
await waitForRemotePeer(node);

const topic = '/my-messenger/1/chat/proto';
const encoder = createEncoder({ contentTopic: topic });
const decoder = createDecoder(topic);

// Подписка
await node.filter.subscribe([decoder], (message) => {
  // Обработка входящего сообщения
});

// Публикация
await node.lightPush.send(encoder, { payload: encryptedBytes });

Waku без XMTP даёт больше контроля, но требует самостоятельно реализовать шифрование, identity, доставку приватных сообщений.

Identity и key management

XMTP привязывает идентификатор к Ethereum адресу автоматически. При standalone подходе нужна схема key derivation.

Deterministic key derivation: мастер-ключ шифрования деривируем из подписи детерминированного сообщения. Пользователь подписывает один раз, ключи воспроизводимы на любом устройстве:

async function deriveMessagingKeys(signer: ethers.Signer): Promise<{
  identityKey: Uint8Array;
  preKey: Uint8Array;
}> {
  const message = 'MyMessenger Identity Key v1\n\nThis key is used for encrypted messaging.\nSign to generate your keys.';
  const signature = await signer.signMessage(message);
  
  // HKDF из подписи
  const keyMaterial = await crypto.subtle.importKey('raw', hexToBytes(signature), 'HKDF', false, ['deriveKey', 'deriveBits']);
  
  const identityKeyBits = await crypto.subtle.deriveBits(
    { name: 'HKDF', hash: 'SHA-256', salt: new Uint8Array(32), info: new TextEncoder().encode('identity-key') },
    keyMaterial, 256
  );
  
  const preKeyBits = await crypto.subtle.deriveBits(
    { name: 'HKDF', hash: 'SHA-256', salt: new Uint8Array(32), info: new TextEncoder().encode('pre-key') },
    keyMaterial, 256
  );
  
  return { identityKey: new Uint8Array(identityKeyBits), preKey: new Uint8Array(preKeyBits) };
}

Важно: если пользователь меняет кошелёк — он теряет ключи. Backup механизм критичен.

Шифрование сообщений

Для приватных чатов — X25519 ECDH для key agreement + AES-GCM для шифрования контента:

async function encryptMessage(
  plaintext: string,
  senderPrivateKey: Uint8Array,
  recipientPublicKey: Uint8Array
): Promise<{ ciphertext: Uint8Array; nonce: Uint8Array }> {
  // Shared secret через ECDH
  const sharedSecret = await performECDH(senderPrivateKey, recipientPublicKey);
  
  // Деривируем ключ шифрования из shared secret
  const encryptionKey = await crypto.subtle.importKey(
    'raw', sharedSecret, { name: 'AES-GCM' }, false, ['encrypt']
  );
  
  const nonce = crypto.getRandomValues(new Uint8Array(12));
  const ciphertext = await crypto.subtle.encrypt(
    { name: 'AES-GCM', iv: nonce },
    encryptionKey,
    new TextEncoder().encode(plaintext)
  );
  
  return { ciphertext: new Uint8Array(ciphertext), nonce };
}

Для группового чата — симметричный ключ группы, зашифрованный публичными ключами каждого участника (sealed sender модель).

Forward secrecy через Double Ratchet

Статичный ECDH ключ — слабость: компрометация ключа раскрывает всю историю переписки. Double Ratchet (алгоритм Signal Protocol) решает это: каждое сообщение шифруется новым эфемерным ключом, деривированным из ratchet состояния. Реализация с нуля — сложно; используйте @signalapp/libsignal-client (официальный WASM порт).

XMTP реализует Double Ratchet внутренне — это одна из причин выбирать его вместо самостоятельной реализации.

Хранение сообщений

Проблема: блокчейн дорог для хранения сообщений. Даже 100 байт текста на Ethereum = несколько долларов. Варианты:

Хранилище Децентрализация Стоимость Скорость
XMTP nodes Федерированная Бесплатно ~200ms
IPFS + Filecoin Высокая ~$0.01/GB/месяц 1-5 сек
Ceramic/ComposeDB Высокая Бесплатно (light) ~500ms
Arweave Максимальная ~$0.005/MB разово 2-30 сек
Собственный сервер Нет Дёшево <50ms

Для реального UX — гибридная схема: сообщения в XMTP/Waku (fast, p2p), архивные сообщения старше N дней — в IPFS с Filecoin pinning.

Push уведомления

Waku и XMTP не имеют нативного push. Для мобильных уведомлений нужен PUSH service. XMTP поддерживает Push notifications через @xmtp/react-native-sdk + XMTP push service, который можно self-host.

Для web: Service Worker + Web Push API. Паттерн: SW подписывается на XMTP streaming, при новом сообщении — показывает push notification через showNotification.

Групповые чаты

XMTP v3 (MLS — Messaging Layer Security) добавляет нативные группы с E2E шифрованием и forward secrecy для всей группы. Это значительно сложнее, чем диалоги один-на-один: управление membership (add/remove участника требует обновления группового ключа), согласование состояния между клиентами.

// XMTP v3 Group API
const group = await xmtpClient.conversations.newGroup([member1, member2, member3]);
await group.send('Hello group');

// Добавить участника
await group.addMembers([newMemberAddress]);

// Группа пересоздаёт ключи автоматически при изменении состава

On-chain компонент: что стоит хранить в блокчейне

Большинство данных мессенджера НЕ должны идти в блокчейн. Разумно хранить on-chain только:

  • Публичные ключи (identity registration) — один раз при первом использовании
  • Group registry — список групп, участниками которых является адрес (если публичные группы)
  • Токен-gated access — проверка владения NFT/токенами для входа в group chat

ENS интеграция: резолвить name.eth → адрес → XMTP проверка через canMessage. Отображать ENS имена вместо адресов в UI.

Структура фронтенда

src/
  components/
    ConversationList/     # Список чатов
    MessageThread/        # Отображение сообщений
    MessageInput/         # Ввод с attachment support
    ContactSearch/        # Поиск по ENS/адресу
  hooks/
    useXmtpClient         # Инициализация XMTP
    useConversations      # Список conversations с streaming
    useMessages           # Сообщения конкретного чата
  stores/                 # Zustand / Recoil state

React Query + Zustand — для кэширования данных с XMTP нод. Сообщения кэшируются локально (IndexedDB), streaming добавляет новые без перезагрузки.

Ориентиры по срокам

XMTP-based мессенджер (1-на-1 чаты, ENS резолвинг, базовый UI) — 2-3 недели. Групповые чаты (MLS v3), push уведомления, token-gated rooms — ещё 2-3 недели. Полноценный продукт с file sharing, read receipts, mobile-адаптацией — 2-3 месяца.