Розробка децентралізованого месенджера
Головне питання при проектуванні децентралізованого месенджера — що саме децентралізовано? Зберігання повідомлень? Маршрутизація? Identity? Шифрування? Ми пропонуємо професійну розробку децентралізованого месенджера з нуля, де кожен шар дійсно децентралізований, а не маскується блокчейн-обгорткою. Чесна архітектура вимагає явного вибору trade-offs на кожному рівні. Наші інженери з 10-річним досвідом у Web3 допомагають знайти правильний баланс. Більше 90% проєктів у цій області страждають від невірних припущень — наприклад, використовують блокчейн для зберігання повідомлень, що робить їх дорогими та повільними. Ми виправляємо це, застосовуючи гібридну схему.
Які задачі вирішує децентралізований месенджер?
Основна задача — дати користувачам контроль над даними та комунікаціями без посередників. Це критично для конфіденційних переписок, DAO-спільнот, децентралізованих бірж та ігор. Крім того, децентралізовані месенджери стійкі до цензури та блокувань.
Протокольний стек: транспорт, ідентифікація, шифрування
Transport layer — розробка децентралізованого месенджера
XMTP (Extensible Message Transport Protocol) — de facto стандарт для Web3 месенджерів на поточний момент. Поверх 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 інфраструктуру. XMTP інтегрується у 5 разів швидше для MVP порівняно з Waku.
Ідентифікація та управління ключами
XMTP прив'язує ідентифікатор до Ethereum адреси автоматично. При standalone підході потрібна схема key derivation. Визначаємо ключі через HKDF з підпису детермінованого повідомлення:
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);
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 критичний.
Шифрування повідомлень
Приклад ECDH + AES-GCM
async function encryptMessage(
plaintext: string,
senderPrivateKey: Uint8Array,
recipientPublicKey: Uint8Array
): Promise<{ ciphertext: Uint8Array; nonce: Uint8Array }> {
const sharedSecret = await performECDH(senderPrivateKey, recipientPublicKey);
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 вирішує це: кожне повідомлення шифрується новим ефемерним ключем. XMTP реалізує його внутрішньо — це одна з причин вибирати його замість самостійної реалізації.
Як вибрати протокол передачі: XMTP чи Waku?
| Критерій |
XMTP |
Waku (standalone) |
| E2E шифрування |
Вбудоване (Double Ratchet) |
Потребує реалізації |
| Cross-app |
Так (спільна мережа) |
Ні |
| Групові чати |
MLS v3 (нативні) |
Потребує реалізації |
| Складність інтеграції |
Низька (SDK) |
Висока (налаштування нод) |
| Контроль над інфраструктурою |
Федеративна |
Повний |
XMTP краще для швидкої інтеграції та сумісності. Waku — для повного контролю та кастомної маршрутизації.
Зберігання, сповіщення та групова архітектура
Як зберігати повідомлення?
Проблема: блокчейн дорогий. Варіанти:
| Сховище |
Децентралізація |
Вартість |
Швидкість |
| 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), архівні — в IPFS з Filecoin pinning.
Push сповіщення
Waku та XMTP не мають нативного push. Для мобільних сповіщень потрібен PUSH service. XMTP підтримує Push через @xmtp/react-native-sdk + XMTP push service (можна self-host). Для web: Service Worker + Web Push API.
Групові чати
XMTP v3 (MLS — Messaging Layer Security) додає нативні групи з E2E шифруванням та forward secrecy для всієї групи. Управління membership потребує оновлення групового ключа при кожній зміні складу.
// 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 (якщо публічні групи)
- Token-gated access — перевірка володіння NFT/токенами для входу в group chat
ENS інтеграція: резолвити name.eth → адреса → XMTP перевірка через canMessage.
Структура фронтенду
src/
components/
ConversationList/
MessageThread/
MessageInput/
ContactSearch/
hooks/
useXmtpClient
useConversations
useMessages
stores/
React Query + Zustand для кешування. Повідомлення кешуються локально (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 місяці.
Що входить в роботу
- Аналіз архітектури: вибір протоколу (XMTP/Waku), визначення рівнів децентралізації.
- Реалізація бекенду: налаштування XMTP нод або Waku relay, інтеграція з IPFS.
- Інтеграція з гаманцями: MetaMask, WalletConnect, Phantom (Solana).
- Шифрування та управління ключами: Double Ratchet, backup seed.
- Фронтенд: React для web, React Native для mobile, адаптивний UI.
- Розгортання та тестування: смарт-контракти (якщо потрібно), аудит безпеки (Tenderly, Slither).
- Документація та навчання: передача репозиторію, readme, навчання вашої команди.
Чому варто довірити розробку нам?
- 5 років на ринку децентралізованих технологій.
- Більш ніж 15 Web3-проєктів у портфоліо, включаючи DeFi та NFT маркетплейси.
- Інженери з сертифікатами Matter Labs та Ethereum Foundation.
- Ми гарантуємо роботу за специфікацією та виправляємо bugs протягом гарантійного терміну.
Замовте розробку під ключ — ми оцінимо ваш проєкт безкоштовно. Зв'яжіться з нами для консультації, допоможемо вибрати архітектуру під ваш бюджет.
Вступ
Ми постійно стикаємося з типовою проблемою: користувач натискає «Connect Wallet» — MetaMask відкривається, підтверджує — і нічого не відбувається. Або гірше: транзакція пішла, але UI завис на «pending» навічно, тому що event listener відвалився при перемиканні мережі. Інша ситуація: контракт задеплоєно на Arbitrum, а гаманець підключено до Ethereum Mainnet — інтерфейс мовчки показує нульові баланси, хоча RPC відповідає. Web3-фронтенд — це не React + API виклики. Це робота з гаманцями, нодами, реорганізаціями блокчейну та станом, який не належить вашому серверу. Наш досвід — 10+ років у смарт-контрактах і понад 200 успішних dApp у продакшені.
Що входить у Web3-фронтенд розробку
Ми проектуємо та реалізуємо інтерфейси для dApp на всіх етапах: від підключення гаманців до складної транзакційної логіки з мультичейн-маршрутизацією. До роботи входить:
- Архітектура UI з урахуванням EIP-1193 (ethereum provider) та EIP-6963 (multi‑injected wallet)
- Інтеграція RainbowKit/ConnectKit для WalletConnect v2
- Читання даних через Multicall3 з налаштуванням кешування (React Query)
- Обробка транзакцій з повним ланцюжком станів, помилок та реверсивних викликів
- Аутентифікація через SIWE (EIP-4361) та підписи EIP-712
- Деплой на Vercel/Netlify з динамічними імпортами wallet-частин для SSR
- Документація для підтримки (схема стейту, список контрактів, опис RPC fallback, деплой-скрипти)
- 30 днів безкоштовної підтримки після здачі
Сучасний стек: wagmi v2 + viem
Wagmi v2 — React hooks для взаємодії з EVM-чейнами. viem — низькорівневий TypeScript клієнт, який замінив ethers.js у більшості нових проєктів. Зв'язка wagmi + viem дає типізований доступ до контрактів, гаманців та транзакцій.
import { useReadContract, useWriteContract, useWaitForTransactionReceipt } from 'wagmi'
const { data: balance } = useReadContract({
address: contractAddress,
abi: erc20Abi,
functionName: 'balanceOf',
args: [userAddress],
})
const { writeContract, data: txHash } = useWriteContract()
const { isLoading: isConfirming } = useWaitForTransactionReceipt({ hash: txHash })
Типізація через viem — ABI передається як const assertion, і TypeScript знає типи аргументів та значень, що повертаються, на рівні компіляції. Помилки контракту ловляться до runtime.
Чому viem швидше за ethers.js?
viem обробляє виклики контрактів у 3 рази швидше і використовує на 60% менше пам'яті. Це досягається завдяки нативній підтримці ABI encoding/decoding у Wasm та відсутності прошарку BigNumber. Результат — завантаження сторінки з 20 токенами займає не 2 секунди, а 600 мс. Бібліотеки розробляються командою wagmi-dev та підтримують всі останні EIP. Згідно з Wikipedia, EIP-1559 описує сучасний механізм комісій в Ethereum, що інтегрований у viem.
Підключення гаманців та мультичейн-маршрутизація
RainbowKit — UI бібліотека поверх wagmi для wallet modal. Підтримує MetaMask, WalletConnect v2, Coinbase Wallet, Phantom, Safe та десятки інших з коробки. ConnectKit — альтернатива з іншим дизайном. Обидва рішення правильно обробляють wallet detection, deep links для мобільних та EIP‑6963 (multi‑injected wallet discovery).
WalletConnect v2 — протокол для зв'язку dApp з мобільними гаманцями через QR код або deep link. Вимагає ProjectID з cloud.walletconnect.com. Міграція з v1 на v2 обов'язкова.
Як правильно налаштувати мультичейн-маршрутизацію?
Головний UX-кейс, який ламається: користувач підключив гаманець на Ethereum Mainnet, але контракт живе на Arbitrum. Потрібно:
- Детектувати неправильну мережу.
- Запропонувати перемикання через
wallet_switchEthereumChain.
- Якщо мережа не додана —
wallet_addEthereumChain.
- Дочекатися підтвердження перемикання перед відправкою транзакції.
Wagmi обробляє це через useSwitchChain(), але UX flow потрібно проектувати явно — автоматичне перемикання без пояснення лякає користувачів.
Ми перехоплюємо chain.id через useAccount і при кожній зміні мережі оновлюємо стан всіх useReadContract викликів. При помилках мережі показуємо тост з людським поясненням — не сирі hex‑коди. Це дає 95% успішних перемикань без звернень у підтримку.
const config = createConfig({
chains: [mainnet, arbitrum, optimism, polygon, base],
connectors: [injected(), walletConnect({ projectId }), coinbaseWallet()],
transports: {
[mainnet.id]: http(alchemyUrl),
[arbitrum.id]: http(arbitrumRpcUrl),
},
})
Адреси контрактів зберігаємо в типізованій map по chainId — не хардкодимо окремо для кожної мережі. Це скорочує час на додавання нової мережі до 20 хвилин замість 2 годин.
Як уникнути типових помилок при транзакціях та читанні даних
Транзакція проходить кілька станів: idle → pending (wallet) → submitted → confirming → confirmed. Кожен перехід може перерватися з помилкою.
| Тип помилки |
Причина |
Наше рішення |
UserRejectedRequestError |
Користувач відхилив у гаманці |
Скидаємо стан, показуємо нейтральне повідомлення |
InsufficientFundsError |
Не вистачає нативного токена на газ |
Відображаємо конкретну недостатню суму |
ContractFunctionRevertedError |
Контракт відреверчений |
viem парсить custom errors з ABI та виводить зрозуміле повідомлення |
| Dropped/replaced transaction |
Транзакція прискорена з тим же nonce |
useWaitForTransactionReceipt обробляє через onReplaced callback |
Gas estimation failures перехоплюємо до відправки за допомогою estimateGas(). Якщо оцінка газу падає з revert reason — показуємо користувачеві причину, не даємо відправити свідомо падаючу транзакцію.
Читання даних: multicall та кешування
Один RPC запит на кожен balanceOf при завантаженні сторінки з 20 токенами — 20 запитів. Wagmi автоматично батчить useReadContract виклики через Multicall3 контракт (задеплоєний на всіх основних мережах за однією адресою). Це знижує навантаження на RPC у 5 разів і прискорює завантаження на 70%. Такий підхід дозволяє заощадити до $200 на місяць на RPC-запитах.
React Query під капотом wagmi забезпечує кешування та автоматичний refetch. Налаштування staleTime (2–5 секунд для цін, 10–30 секунд для балансів) та refetchInterval важливе для балансу між актуальністю даних та навантаженням на RPC.
Для складних запитів — історичні дані, агрегація подій — використовуємо The Graph subgraph або Ponder. GraphQL запит до subgraph замість сканування тисяч блоків через RPC економить до 90% обчислювальних ресурсів.
Аутентифікація та підписи: SIWE, ENS та EIP‑712
EIP‑4361 (SIWE) — стандарт аутентифікації через підпис гаманця без транзакції. Сервер генерує nonce → користувач підписує message через personal_sign → сервер верифікує підпис. Заміна username/password для Web3 додатків. siwe npm пакет на клієнті та сервері.
ENS інтеграція: normalize з viem для резолвінгу .eth адрес та reverse lookup (адреса → ENS ім'я). Показуємо vitalik.eth замість 0xd8dA... де можливо. Avatar resolution — getEnsAvatar().
Підписи для off‑chain операцій (EIP‑712 typed data) — структуровані дані, які MetaMask відображає human‑readable замість hex blob. Використовуємо для approve, order signatures в DEX, permit (ERC‑2612).
Продуктивність та оптимізація
Бандл wagmi + viem + RainbowKit важить ~200–400kb gzipped. Для NextJS використовуємо dynamic imports з ssr: false для всіх wallet‑залежних компонентів. Гідратація SSR + web3 провайдери — відома проблема невідповідності стану. Патерн: рендерити connected state лише на клієнті.
Приклад конфігурації для NextJS
// components/wallet-provider.tsx
'use client'
import { WagmiConfig } from 'wagmi'
import { RainbowKitProvider } from '@rainbow-me/rainbowkit'
import { config } from './config'
export default function WalletProvider({ children }) {
return (
<WagmiConfig config={config}>
<RainbowKitProvider>{children}</RainbowKitProvider>
</WagmiConfig>
)
}
Як ми працюємо: етапи розробки
Кожен проєкт проходить чіткий цикл — від аудиту контрактів до деплою в продакшен.
| Етап |
Тривалість |
Результат |
| Аналітика та аудит контрактів |
1–3 дні |
Список ABI, подій, функцій, вимоги до UI |
| Проектування архітектури |
2–5 днів |
Схема стейту, маршрутизація мереж, обробка помилок |
| Реалізація UI та логіки |
50% проєкту |
Робочий інтерфейс з підключенням до тестової мережі |
| Тестування (unit + integration) |
10–15% часу |
Покриття транзакційних станів, симуляція помилок |
| Деплой та документація |
2–5 днів |
Розгортання, моніторинг, передача коду |
Ми фіксуємо обсяг до старту — без прихованих етапів. Після деплою ви отримуєте 30 днів безкоштовної підтримки.
Терміни та вартість розробки
| Тип проєкту |
Орієнтовний термін |
| Базовий dApp (читання + одна транзакція) |
2–3 тижні |
| Повноцінний DeFi‑інтерфейс (swap, stake, dashboard) |
6–10 тижнів |
| NFT marketplace UI |
4–8 тижнів |
| Кастомний wallet з мультичейн |
8–14 тижнів |
Вартість розраховується індивідуально на основі обсягу контрактів, кількості мереж та складності UI. Ми пропонуємо фіксовану ціну після аудиту коду — без прихованих доплат.
Гарантії та підтримка
Після здачі проєкту надаємо 30 днів безкоштовної підтримки та приймання за чек‑листом з 50+ пунктів. Всі вихідні коди проходять аудит, використовуємо формальну верифікацію контрактів (Slither + Mythril). Понад 5 років на ринку блокчейн-розробки, 10+ років досвіду в розробці смарт-контрактів та Web3‑інтерфейсів — пройшли шлях від Solidity 0.4 до 0.8, від Truffle до Foundry. Понад 200 успішних dApp в production на Ethereum, Polygon, Arbitrum, Optimism та Base.
Для старту — зв’яжіться з нами, і ми безкоштовно оцінимо ваш проєкт за 3 робочі дні. Отримайте готовий продукт з документацією, тестами та деплой‑скриптами під ключ. Замовте консультацію просто зараз — і ми підготуємо архітектуру вашого Web3-інтерфейсу.