Розробка некастодіального мобільного криптокошелька
Некастодіальний кошелек означає одне: приватний ключ користувача ніколи не залишає його пристрій. Немає серверної бази даних з ключами, немає можливості відновити доступ "через підтримку", немає центральної точки компрометації. Це фундаментальне архітектурне рішення, яке визначає весь стек розробки.
BIP39/32/44 — стандарти, які неможливо ігнорувати
Починайте з мнемонічної фрази. BIP39 визначає список з 2048 слів та алгоритм генерації 512-бітового seed з 12 або 24 слів + опціональної passphrase через PBKDF2-HMAC-SHA512 (2048 ітерацій). Seed → master key через BIP32 HMAC-SHA512. Ієрархічна деривація ключів за шляхом BIP44: m/44'/60'/0'/0/0 — перша адреса Ethereum, m/44'/0'/0'/0/0 — перша адреса Bitcoin.
Чому це важливо: користувач повинен мати можливість відновити всі свої адреси в будь-якому сумісному кошельку (MetaMask, Trust Wallet, Ledger) за однією мнемонікою. Відхилення від стандарту позбавляє користувача цієї можливості.
Генерація мнемоніки на Android:
// BitcoinJ або Web3j для BIP39
val entropy = ByteArray(16) // 128 бітів → 12 слів
SecureRandom().nextBytes(entropy)
val mnemonic = MnemonicCode.INSTANCE.toMnemonic(entropy)
// ["word1", "word2", ..., "word12"]
// seed з мнемоніки
val seed = MnemonicCode.toSeed(mnemonic, "") // без passphrase
val masterKey = HDKeyDerivation.createMasterPrivateKey(seed)
Контрольна сума мнемоніки (останнє слово або його частина) — обов'язкова валідація при імпорті. Користувачі регулярно роблять помилки.
iOS, Swift:
// WalletCore від Trust Wallet — відмінна бібліотека для iOS/Android
let wallet = HDWallet(strength: 128, passphrase: "")
let mnemonic = wallet.mnemonic // 12 слів
let ethAddress = wallet.getAddressForCoin(coin: .ethereum)
Trust Wallet Core (WalletCore) — open source, підтримує 60+ блокчейнів, реалізує всі BIP стандарти. Використовується в Trust Wallet, Argent та десятках інших кошельків. Для нового некастодіального кошелька — стандартний вибір основи.
Безпечне зберігання seed та приватних ключів
Ключ не можна зберігати в откритому вигляді ніде: не в файлах, не в SharedPreferences, не в базі даних. Схема:
- Користувач створює PIN або налаштовує біометрію
- Генеруйте випадковий ключ шифрування (AES-256), захищений Android Keystore / iOS Secure Enclave з прив'язкою до біометрії
- Зашифруйте seed цим ключем
- Зберігайте зашифрований blob у зашифрованій БД (SQLCipher) або EncryptedSharedPreferences
При біометричній аутентифікації:
val cryptoObject = BiometricPrompt.CryptoObject(cipher) // cipher прив'язаний до Keystore ключа
biometricPrompt.authenticate(promptInfo, cryptoObject)
// у onAuthenticationSucceeded:
val decryptedSeed = result.cryptoObject?.cipher?.doFinal(encryptedSeed)
Приватний ключ у розшифрованому вигляді живе в пам'яті тільки під час підписання транзакції. Потім — обнулюйте масив байтів, GC не гарантує звільнення, тому явний Arrays.fill(keyBytes, 0.toByte()).
Робота з блокчейном
Для мереж, сумісних з Ethereum (ETH, BSC, Polygon, Arbitrum, Optimism) — Web3j (Android) або web3.swift (iOS). Для Bitcoin — BitcoinJ. Для Solana — Solana Mobile Stack SDK. Для TON — ton-kotlin або TonConnect.
Підключення до мережі через RPC-провайдер: Infura, Alchemy, QuickNode. Для приватності — власна нода (дорого в утриманні) або кілька провайдерів з fallback.
Відправка ETH транзакції:
val credentials = Credentials.create(privateKeyHex)
val nonce = web3j.ethGetTransactionCount(
credentials.address,
DefaultBlockParameterName.PENDING
).send().transactionCount
val rawTransaction = RawTransaction.createEtherTransaction(
nonce,
gasPrice,
gasLimit,
toAddress,
amountInWei
)
val signedTransaction = TransactionEncoder.signMessage(rawTransaction, chainId, credentials)
val txHash = web3j.ethSendRawTransaction(
Numeric.toHexString(signedTransaction)
).send().transactionHash
Приватний ключ використовується тільки для TransactionEncoder.signMessage — підписання відбувається локально, у мережу йде тільки підписана транзакція без ключа.
EIP-1559 та розрахунок газу
З London hardfork (EIP-1559) транзакції мають maxFeePerGas та maxPriorityFeePerGas замість простого gasPrice. Правильний розрахунок: метод RPC eth_feeHistory для аналізу останніх блоків, алгоритм підбору maxPriorityFeePerGas (tip) на основі перцентилів. MetaMask використовує 50-й перцентиль приоритетних комісій з останніх 5 блоків як базовий совіт.
Показуйте користувачу три варіанти (slow/normal/fast) з оцінкою часу підтвердження — стандартний UX.
WalletConnect для dApps
Без WalletConnect кошелек ізольований від екосистеми DeFi. WalletConnect v2 (Sign API) — протокол для зв'язку між кошельком та dApp через relay сервер. Реалізація: WalletConnect Swift SDK (iOS), WalletConnect Kotlin SDK (Android).
Сесія встановлюється через QR-код або deep link:
- dApp генерує URI:
wc:...@2?relay-protocol=irn&symKey=... - Користувач сканує QR у кошельку
- E2E-зашифрована сесія встановлюється через relay
- dApp запитує
eth_sendTransaction→ користувач бачить деталі → підписує
Seed phrase backup flow
UX seed backup — критична частина. Користувачі втрачають гроші через втрату seed. Правильний потік:
- Показати мнемоніку — попросити підтвердження, що вона записана
- Верифікація: показати 3 випадкові слова з фрази, попросити ввести порядкові номери
- Нагадувати про бекап у онбордингу та періодично
Забороняйте скриншоти на екрані з seed через FLAG_SECURE / iOS UIScreen.capturedDidChangeNotification.
Мультичейн та токени
ERC-20 токени не потребують окремих ключів — та ж адреса Ethereum. Баланс через balanceOf(address) виклик контракту. Список токенів — через CoinGecko API або Trust Wallet Assets репозиторій (открита лист з іконками для 10000+ токенів).
NFT (ERC-721, ERC-1155) — ownerOf(tokenId) / balanceOf(address, id). Метадані через tokenURI → IPFS або HTTP.
Відповідність вимогам
Некастодіальний кошелек у більшості юрисдикцій не вимагає ліцензії — користувач сам управляє своїми ключами. Але якщо додати обмін валют (swap), fiat on-ramp — ситуація змінюється. Консультація з юристом щодо регулювання обов'язкова перед запуском з такими функціями.
Часова шкала для розробки базового некастодіального кошелька (Ethereum + ERC-20 токени + відправка/отримання + WalletConnect + seed backup) — 2–4 місяці в залежності від команди та підтримуваних мереж. Додавання кожного нового блокчейна з нативною інтеграцією — 2–4 тижні додатково. Вартість рассчітується після детальних функціональних вимог.







