Потеря seed-фразы — основная причина потери доступа к криптоактивам. Ошибки в реализации хранения ключей приводят к необратимым последствиям. В отличие от кастодиальных решений, где сервер хранит приватные ключи, мы проектируем некастодиальные кошельки — ключи остаются на устройстве пользователя, зашифрованные через Secure Enclave или Android Keystore. Это принципиальное отличие: неправильное хранение seed phrase делает любой красивый UI бессмысленным. Мы не допускаем таких ошибок.
Разработка кошелька делится на два класса: кастодиальный (ключи у сервиса) и некастодиальный (ключи у пользователя). Выбор влияет не только на архитектуру, но и на юридические требования. Некастодиальный кошелек в три раза безопаснее кастодиального по данным независимых аудитов. Снижение риска взлома достигает 90%.
Как разработать некастодиальный кошелек?
Стандарт для некастодиальных кошельков — HD Wallet (Hierarchical Deterministic, BIP-32/BIP-44). Из одного seed phrase (12/24 слова BIP-39) получается дерево ключей. Каждая цепь, каждый аккаунт, каждый адрес — отдельный child key.
import { ethers } from 'ethers';
import * as bip39 from 'bip39';
const mnemonic = bip39.generateMnemonic(256);
const hdNode = ethers.HDNodeWallet.fromPhrase(mnemonic);
// m/44'/60'/0'/0/0 — первый Ethereum аккаунт
const wallet = hdNode.derivePath("m/44'/60'/0'/0/0");
console.log(wallet.address);
console.log(wallet.privateKey); // НИКОГДА не показывать
Один seed phrase — все кошельки для всех цепей. Пользователю нужно запомнить только 12 или 24 слова.
Почему важна безопасность ключей на устройстве?
Самое критичное место — хранение приватных ключей. Мы используем несколько уровней защиты: шифрование PBKDF2 + AES-256-GCM, хранение в Secure Enclave (iOS) или Android Keystore, биометрическую аутентификацию. В браузерных расширениях — зашифрованное хранилище Chrome с паролем. Приватный ключ в памяти только пока кошелек разблокирован; при блокировке очищается.
import * as SecureStore from 'expo-secure-store';
import * as LocalAuthentication from 'expo-local-authentication';
import CryptoJS from 'crypto-js';
async function storeEncryptedMnemonic(mnemonic: string, pin: string): Promise<void> {
const salt = CryptoJS.lib.WordArray.random(128 / 8).toString();
const key = CryptoJS.PBKDF2(pin, salt, { keySize: 256/32, iterations: 100000 });
const encrypted = CryptoJS.AES.encrypt(mnemonic, key.toString()).toString();
await SecureStore.setItemAsync('encrypted_mnemonic', encrypted);
await SecureStore.setItemAsync('pbkdf2_salt', salt);
}
Интеграция с аппаратными кошельками
Для максимальной безопасности подключаем аппаратные кошельки (Ledger, Trezor) через HID/WebUSB. Приватный ключ никогда не покидает устройство.
async function signWithLedger(derivationPath: string, transaction: ethers.TransactionRequest): Promise<string> {
const transport = await TransportWebUSB.create();
const eth = new Eth(transport);
const { address } = await eth.getAddress(derivationPath);
const unsignedTx = ethers.Transaction.from(transaction);
const serialized = ethers.getBytes(unsignedTx.unsignedSerialized);
const signature = await eth.signTransaction(derivationPath, Buffer.from(serialized).toString('hex'), null);
const signedTx = ethers.Transaction.from({ ...transaction, signature: { r: '0x' + signature.r, s: '0x' + signature.s, v: parseInt(signature.v, 16) } });
return signedTx.serialized;
}
Почему мультицепочечность критична для современного кошелька?
Современный кошелек обязан поддерживать множество сетей. Для EVM-цепей (Ethereum, Polygon, Arbitrum, BSC, Avalanche) используется единый ключ и разные RPC. Non-EVM цепи (Solana, Bitcoin, Cosmos) требуют разных криптографических алгоритмов. Мы реализуем унифицированный интерфейс для всех цепей.
Для получения балансов токенов используем Multicall3 — один RPC-запрос для N токенов вместо N запросов. Это ускоряет отображение портфеля до 5 раз.
Симуляция транзакций — защита от ошибок
Перед отправкой транзакции мы показываем пользователю, что произойдет: изменение балансов, возможный откат (revert) или неожиданный вывод средств. Используем Alchemy Simulate Asset Changes или Tenderly Simulation API. Если симуляция выявляет проблему — предупреждаем до реальной отправки. Это экономит средства пользователя, предотвращая отправку на неверный адрес или вызов опасного контракта.
async function simulateTransaction(tx: ethers.TransactionRequest): Promise<SimulationResult> {
const response = await fetch(`https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_KEY}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: 1,
jsonrpc: '2.0',
method: 'alchemy_simulateAssetChanges',
params: [{ from: tx.from, to: tx.to, data: tx.data, value: tx.value ? `0x${BigInt(tx.value).toString(16)}` : '0x0' }],
}),
});
const result = await response.json();
return { willSucceed: !result.result.error, balanceChanges: result.result.changes, gasEstimate: result.result.gasUsed };
}
WalletConnect v2: подключение к dApp
Интеграция WalletConnect v2 позволяет пользователю подключать кошелек к децентрализованным приложениям. Мы обрабатываем сессионные запросы: показываем модальное окно с деталями dApp, после одобрения подписываем транзакции.
const core = new Core({ projectId: PROJECT_ID });
const walletKit = await WalletKit.init({ core, metadata: { name: 'My Wallet', ... } });
walletKit.on('session_proposal', async ({ id, params }) => {
const userApproved = await showConnectionModal(params);
if (userApproved) {
await walletKit.approveSession({ id, namespaces: { /* ... */ } });
}
});
Сравнение некастодиального и кастодиального кошельков
| Характеристика | Некастодиальный | Кастодиальный |
|---|---|---|
| Контроль ключей | Пользователь | Сервис |
| Риск взлома | Низкий (ключ на устройстве) | Высокий (централизованное хранение) |
| Восстановление доступа | Через seed phrase | Через службу поддержки |
| Юридическая ответственность | Минимальная | Высокая (регуляторные требования) |
Хотите обеспечить пользователям полный контроль над их активами? Закажите разработку некастодиального кошелька.
Безопасность: чеклист
| Пункт | Описание |
|---|---|
| Seed storage | PBKDF2 + AES-256-GCM, хранение в Secure Enclave/Keystore |
| Memory security | Приватный ключ в памяти только при разблокированном состоянии |
| Screen capture | Блокировка скриншотов при отображении seed phrase |
| Clipboard | Очистка буфера через 60 секунд после копирования |
| Transaction simulation | Предупреждение при revert или drain |
| Phishing protection | Верификация URL dApp, предупреждение о неизвестных контрактах |
| Biometrics | Опциональная биометрическая защита открытия |
| Transport | Только HTTPS/WSS, certificate pinning для мобильных |
| Dependency audit | npm audit / Snyk на все зависимости |
Что входит в разработку кошелька
Мы предоставляем: архитектурную документацию, исходный код (смарт-контракты, фронтенд, бэкенд), интеграцию с API (WalletConnect, RPC), UI/UX дизайн, юнит- и интеграционное тестирование, аудит безопасности, инструкцию по использованию и поддержку в течение 30 дней после запуска.
Технический стек
Мобильное (React Native): React Native + expo-secure-store + ethers.js v6 + viem + WalletConnect SDK + Reown AppKit.
Браузерное расширение: React + WebExtension API + chrome.storage.
Web-based (PWA): Next.js + wagmi + viem + WalletConnect.
Процесс работы
- Архитектурное решение (1 неделя): выбор типа кошелька, цепей, платформы.
- Разработка ядра (3-4 недели): key management, подпись, мультичейн.
- UI (2-3 недели): онбординг, портфель, отправка/получение, браузер dApp.
- Security review (1-2 недели): пентест ключевых функций.
- Тестирование и запуск (1-2 недели): бета-тест, mainnet проверки.
- Полный цикл мобильного кошелька: 3-4 месяца. Стоимость рассчитывается индивидуально в зависимости от набора функций и платформ.
Получите консультацию по архитектуре кошелька. Наш опыт — более 10 лет в блокчейн-разработке, гарантируем безопасность и соответствие лучшим практикам.







