Розробка веб-криптогаманця
Останній раз, коли ви вводили seed phrase у веб-форму? Це XSS-пастка. Веб-гаманець — найуразливіша ланка, але й найдоступніша. Ми вирішуємо проблему: як зберігати ключі в браузері без ризику компрометації, забезпечуючи при цьому зручність користувача. У нас 7 років досвіду в блокчейн-розробці, понад 50 реалізованих гаманців — від простих EOA до розумних контрактів з ERC-4337. Мінімальний бюджет на MVP — від $50 000, але вартість розраховується індивідуально.
Ключова дилема: безпека проти UX. Традиційні EOA гаманці втрачають кошти при крадіжці ключа. Smart Accounts (ERC-4337) додають social recovery та session keys, але потребують більше газу. На практиці для масового продукту вибір очевидний — Account Abstraction. Ми покажемо, як зібрати гаманець, який не скомпрометує жоден з аспектів.
Як розробити веб-криптогаманець: ключові архітектурні рішення
EOA vs Smart Account
EOA (Externally Owned Account) — класичний гаманець з одним приватним ключем. Втрата ключа = втрата доступу назавжди. Smart Account (ERC-4337) — програмована логіка підпису: social recovery, session keys, batched transactions. На практиці Smart Account знижує ризик втрати коштів у 5 разів завдяки відновленню через довірених осіб (social recovery). Однак EOA дешевший у газі на 10-15% — обирайте за пріоритетом: безпека чи вартість.
Як захистити приватні ключі в браузері?
Варіанти від найменш до найбільш безпечного:
- localStorage / sessionStorage — ніколи. Доступний будь-якому JavaScript.
- IndexedDB з шифруванням AES-GCM 256-bit через Web Crypto API. Ключ від пароля (PBKDF2, 600 000 ітерацій). Це стандарт для браузерних гаманців.
async function encryptPrivateKey(
privateKey: Uint8Array,
password: string
): Promise<{ encrypted: ArrayBuffer; salt: Uint8Array; iv: Uint8Array }> {
const salt = crypto.getRandomValues(new Uint8Array(32));
const iv = crypto.getRandomValues(new Uint8Array(12));
const keyMaterial = await crypto.subtle.importKey(
"raw",
new TextEncoder().encode(password),
"PBKDF2",
false,
["deriveKey"]
);
const encryptionKey = await crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt,
iterations: 600000,
hash: "SHA-256",
},
keyMaterial,
{ name: "AES-GCM", length: 256 },
false,
["encrypt"]
);
const encrypted = await crypto.subtle.encrypt(
{ name: "AES-GCM", iv },
encryptionKey,
privateKey
);
return { encrypted, salt, iv };
}
- WebAuthn + hardware key — найбільш безпечний. Приватний ключ ніколи не покидає TPM/Secure Enclave. Підпис всередині пристрою. Daimo та Coinbase Smart Wallet використовують цей підхід. Його безпека в 3 рази вища порівняно з IndexedDB.
- MPC — ключ ніколи не існує цілком. Розбитий на shares, підпис потребує threshold. Мінус: повільніше на 30-50%.
Key Derivation та HD гаманці
BIP-39 та BIP-44: seed phrase → master key → дочірні ключі. Шлях m/44'/60'/0'/0/0 — перший Ethereum акаунт. Бібліотеки: @scure/bip39 та @scure/bip32 — audited, tree-shakeable.
Приклад коду для derivation
import { mnemonicToSeed } from "@scure/bip39";
import { HDKey } from "@scure/bip32";
async function deriveAccount(mnemonic: string, index: number) {
const seed = await mnemonicToSeed(mnemonic);
const masterKey = HDKey.fromMasterSeed(seed);
const derivationPath = `m/44'/60'/0'/0/${index}`;
const childKey = masterKey.derive(derivationPath);
return {
privateKey: childKey.privateKey!,
address: computeAddress(childKey.publicKey!),
};
}
Архітектура веб-гаманця
Separation of concerns: UI vs Signing
Критичне правило: код, що має доступ до ключа, ізольований від UI через Web Worker. XSS в UI не компрометує ключ.
// Main thread — UI
async function signTransaction(txRequest: TransactionRequest): Promise<string> {
return new Promise((resolve, reject) => {
const worker = new Worker("/signing-worker.js");
worker.postMessage({ type: "SIGN_TX", payload: txRequest });
worker.onmessage = (e) => {
if (e.data.type === "SIGNED") resolve(e.data.signature);
if (e.data.type === "REJECTED") reject(new Error("User rejected"));
if (e.data.type === "ERROR") reject(new Error(e.data.error));
};
});
}
WalletConnect та dApp інтеграція
Використовуємо @walletconnect/web3wallet SDK v2.
import { Web3Wallet } from "@walletconnect/web3wallet";
import { Core } from "@walletconnect/core";
const core = new Core({ projectId: WALLETCONNECT_PROJECT_ID });
const web3wallet = await Web3Wallet.init({
core,
metadata: {
name: "My Wallet",
description: "Custom Web3 Wallet",
url: "https://mywallet.app",
icons: ["https://mywallet.app/icon.png"],
},
});
web3wallet.on("session_request", async (event) => {
const { id, topic, params } = event;
const { request } = params;
if (request.method === "eth_sendTransaction") {
const approved = await showTransactionConfirmation(request.params[0]);
if (approved) {
const txHash = await sendTransaction(request.params[0]);
await web3wallet.respondSessionRequest({
topic,
response: { id, result: txHash, jsonrpc: "2.0" },
});
} else {
await web3wallet.respondSessionRequest({
topic,
response: { id, error: { code: 4001, message: "User rejected" }, jsonrpc: "2.0" },
});
}
}
});
Що входить у роботу
| Deliverable | Опис |
|---|---|
| Архітектурна документація | Діаграми, опис модулів, threat model |
| Вихідний код під ключ | Репозиторій з повним кодом гаманця |
| Інтеграція із зовнішніми сервісами | WalletConnect, RPC, bundler, paymaster |
| Unit та integration тести | Покриття ключових сценаріїв |
| Security audit | Аудит коду та контрактів сторонньою компанією |
| Deployment та підтримка | Запуск у production, 3 місяці підтримки |
Етапи розробки веб-гаманця
- Архітектура та threat model (1-2 тижні)
- Key management та HD wallet (3-4 тижні)
- Transaction signing та RPC-шар (2-3 тижні)
- ERC-4337 integration (3-4 тижні)
- WalletConnect та dApp інтеграція (2-3 тижні)
- UI (React + TypeScript) (5-7 тижнів)
- Security hardening та аудит (2-3 тижні)
- Multi-chain підтримка (3-4 тижні)
- Тестування та баг-фікс (3-4 тижні)
Чому ізоляція підпису від UI критична?
Основні загрози: XSS, clipboard-атаки, phishing, supply chain. Мітигація:
- Строга CSP + Subresource Integrity
- Показувати перші та останні символи адреси, використовувати identicon
- PWA з verified domain, ENS верифікація
- Seed phrase ніколи не передається по мережі
- Private key у пам'яті обнулюється після використання
Що робить гаманець по-справжньому безпечним?
WebAuthn + апаратний ключ — золотий стандарт. Приватний ключ фізично недоступний браузеру. Другий шар — MPC, де підпис збирається з розділених частин. Третій — програма bug bounty на Immunefi. Ми використовуємо всі три рівні для production-рішень.
Терміни орієнтовно
| Компонент | Технологія | Термін |
|---|---|---|
| Key management | Web Crypto API + @scure | 3-4 тижні |
| HD wallet (BIP-39/44) | @scure/bip32 + bip39 | 1-2 тижні |
| Transaction signing | viem + ethers | 2-3 тижні |
| ERC-4337 integration | permissionless.js + Pimlico | 3-4 тижні |
| WalletConnect v2 | @walletconnect/web3wallet | 2-3 тижні |
| UI (React + TypeScript) | React + Tailwind | 5-7 тижнів |
| Security hardening | CSP + Web Worker isolation | 2-3 тижні |
| Multi-chain | Chain abstraction layer | 3-4 тижні |
| Testing + audit prep | Vitest + Playwright | 3-4 тижні |
MVP веб-гаманець (EOA, Ethereum, базовий UI): 8-10 тижнів. Production-ready з ERC-4337, мультичейн, WalletConnect, WebAuthn: 6-9 місяців. Зв'яжіться з нами, щоб обговорити ваш проєкт — ми оцінимо обсяг робіт та запропонуємо оптимальне рішення. Замовте розробку веб-гаманця та отримайте консультацію інженера.







