Розробка десктопного криптогаманця

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1306 послуг
Розробка десктопного криптогаманця
Складний
від 2 тижнів до 3 місяців
Часті запитання

Напрямки блокчейн-розробки

Етапи блокчейн-розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1306
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1218
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    920
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1147
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    610
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    885

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

Десктопний криптовалютний гаманець — це не просто зручна обгортка над web3 бібліотекою. Це програма з претензією на високу безпеку яка зберігає приватні ключі у середовищі потенційно заразженому malware. Завдання: забезпечити безпечне зберігання ключів та зручний UX одночасно — завдання де ці вимоги часто суперечать один одному.

Приклади: Rabby Wallet (Electron + TypeScript), Ledger Live (Electron, інтеграція hardware wallet), Frame (нативний desktop, focus на privacy), Electrum (Bitcoin-специфічний, один з найстаріших).

Вибір технологічного стека

Electron vs Tauri vs Native

Electron: Node.js + Chromium. Найбільша екосистема, будь-які npm-залежності доступні. Недоліки: великий bundle (100–200MB), більший attack surface від Chromium, історичні CSP проблеми.

Tauri: Rust backend + системний WebView (WebKit/WebView2/GTK). Малий bundle (5–15MB), більш безпечний (Rust memory safety, менший surface), TypeScript/React frontend через IPC. Рекомендований для нових проектів.

Qt / Swift / WPF: нативний стек. Максимальна продуктивність та безпека, але високі затрати розробки, окремий codebase для кожної платформи.

Для більшості нових десктопних гаманців — вибір між Electron та Tauri залежить від вимог до розміру та безпеки.

// Tauri: backend команда для підпису транзакції

#[command]
async fn sign_transaction(
    tx_hash: String,
    wallet_id: String,
    password: String
) -> Result<SignatureResult, String> {
    let keystore = state.keystore.lock().await;
    let wallet: LocalWallet = keystore
        .load_wallet(&wallet_id, &password)
        .map_err(|e| format!("Failed to load wallet: {}", e))?;
    
    let hash = H256::from_slice(&hex::decode(&tx_hash)?);
    let signature = wallet.sign_hash(hash).await?;
    
    Ok(SignatureResult {
        v: signature.v,
        r: format!("{:x}", signature.r),
        s: format!("{:x}", signature.s),
    })
}

// Ключовий принцип: приватний ключ ніколи не передається в JavaScript
// Усі крипто-операції — тільки в Rust backend

Безпечне зберігання ключів

Формат Keystore та шифрування

Стандартний підхід — ethereum keystore формат (EIP-55): ключ шифрується паролем користувача, результат зберігається в JSON файлі.

pub struct KeystoreManager {
    keystore_dir: PathBuf,
}

impl KeystoreManager {
    pub fn create_wallet(&self, password: &str) -> Result<WalletInfo, KeystoreError> {
        let mut rng = rand::thread_rng();
        let mut private_key = [0u8; 32];
        rng.fill_bytes(&mut private_key);
        
        let signing_key = SigningKey::from_bytes(&private_key)?;
        let wallet = LocalWallet::from(signing_key);
        let address = wallet.address();
        
        let filename = format!("wallet-{}.json", address);
        let keystore_path = self.keystore_dir.join(&filename);
        
        encrypt_key(&keystore_path, &mut rng, private_key, password, Some(&filename))?;
        
        private_key.zeroize();
        
        Ok(WalletInfo {
            id: filename,
            address: format!("{:?}", address),
        })
    }
}

Інтеграція OS-level Keychain

Додатковий рівень — зберігання мастер-пароля або ключа шифрування у системному keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service).

use keyring::Entry;

pub fn store_master_password(wallet_id: &str, password: &str) -> Result<(), KeyringError> {
    let entry = Entry::new("crypto-wallet", wallet_id)?;
    entry.set_password(password)?;
    Ok(())
}

Захищає від наївного читання файлів — пароль недоступний без системного keychain. Але не захищає від malware з privilege escalation.

Seed phrase: зберігання та відображення

BIP-39 мнемоніка — єдиний спосіб відновити гаманець. Алгоритм: мнемоніка → seed (PBKDF2) → HD wallet (BIP-32).

// Показуємо seed phrase ТІЛЬКИ в захищеному вікні
import * as bip39 from '@scure/bip39';
import { wordlist } from '@scure/bip39/wordlists/english';
import { HDKey } from '@scure/bip32';

function generateWallet() {
    return window.__TAURI__.invoke('generate_new_wallet');
}

// Seed відображається тільки в ізольованому компоненті
// з явним user action та таймером auto-hide
function SeedPhraseDisplay({ onConfirmed }) {
    const [revealed, setRevealed] = useState(false);
    const [timeLeft, setTimeLeft] = useState(60);
    
    useEffect(() => {
        if (revealed) {
            const timer = setInterval(() => {
                setTimeLeft(t => {
                    if (t <= 1) {
                        setRevealed(false);
                        return 60;
                    }
                    return t - 1;
                });
            }, 1000);
            return () => clearInterval(timer);
        }
    }, [revealed]);
    
    return (
        <div style={{ userSelect: 'none' }}>
            {revealed ? (
                <>
                    <p>Скрито за: {timeLeft}s</p>
                    <SeedWords />
                </>
            ) : (
                <button onClick={() => setRevealed(true)}>
                    Показати seed phrase
                </button>
            )}
        </div>
    );
}

HD Wallet та управління аккаунтами

BIP-44 визначає ієрархію: m/44'/60'/account'/change/index для Ethereum. Користувач бачить «аккаунти» — за ними стоїть дерево дочірніх ключів з однієї seed.

pub fn derive_accounts(
    mnemonic: &str,
    count: u32
) -> Result<Vec<DerivedAccount>, DerivationError> {
    let mnemonic = Mnemonic::from_phrase(mnemonic, Language::English)?;
    let seed = mnemonic.to_seed("");
    
    let root = XPriv::root_from_seed(&seed, None)?;
    let mut accounts = Vec::new();
    
    for index in 0..count {
        let path = format!("m/44'/60'/0'/0/{}", index);
        let child_key = root.derive_path(&path)?;
        let wallet = LocalWallet::from(SigningKey::from(child_key.as_ref()));
        
        accounts.push(DerivedAccount {
            index,
            address: format!("{:?}", wallet.address()),
            path,
        });
    }
    
    Ok(accounts)
}

Підключення до мереж та RPC провайдери

Десктопний гаманець підтримує кілька мереж (Ethereum mainnet, L2: Arbitrum, Optimism, Base, Polygon) з можливістю додавання кастомних RPC.

interface NetworkConfig {
    chainId: number;
    name: string;
    rpcUrls: string[];
    nativeCurrency: { symbol: string; decimals: number };
    blockExplorer?: string;
}

class MultiChainProvider {
    private providers: Map<number, ethers.JsonRpcProvider[]> = new Map();
    
    async getProvider(chainId: number): Promise<ethers.JsonRpcProvider> {
        const providers = this.providers.get(chainId);
        if (!providers?.length) throw new Error(`Unknown chain ${chainId}`);
        
        for (const provider of providers) {
            try {
                await provider.getBlockNumber();
                return provider;
            } catch {
                continue;
            }
        }
        
        throw new Error(`No available RPC for chain ${chainId}`);
    }
}

Privacy розумування: публічні RPC провайдери (Infura, Alchemy) логують IP-адреси та адреси гаманців. Privacy-орієнтовані гаманці використовують власні light client ноди або Tor.

Transaction Signing UI та захист від фішингу

Момент підпису транзакції — критична UX точка. Користувач повинен розуміти що підписується.

interface TransactionPreview {
    type: 'ETH_TRANSFER' | 'TOKEN_TRANSFER' | 'CONTRACT_INTERACTION' | 'APPROVE';
    to: string;
    toLabel?: string;
    toRisk: 'safe' | 'unknown' | 'suspicious';
    value?: string;
    tokenAmount?: string;
    estimatedGasUSD: string;
    totalCostUSD: string;
    decodedCalldata?: { methodName: string; params: Record<string, string> };
    warnings: string[];
}

async function buildTransactionPreview(
    tx: ethers.TransactionRequest
): Promise<TransactionPreview> {
    const warnings: string[] = [];
    
    if (tx.data && tx.data !== '0x') {
        const decoded = await decodeTransactionData(tx.data, tx.to);
        
        if (decoded?.methodName === 'approve') {
            const amount = decoded.params.amount;
            if (BigInt(amount) === MaxUint256) {
                warnings.push('⚠️ Unlimited approval');
            }
        }
    }
    
    const toRisk = await checkAddressRisk(tx.to);
    if (toRisk === 'suspicious') {
        warnings.push('🚨 Address flagged as suspicious');
    }
    
    return {
        type: determineTransactionType(tx),
        to: tx.to,
        estimatedGasUSD: await estimateGasInUSD(tx),
        totalCostUSD: await calculateTotalCostUSD(tx),
        warnings
    };
}

dApp Browser та WalletConnect

Сучасний десктопний гаманець взаємодіє з dApps через WalletConnect v2: стандартний протокол через QR-код або deep link. Найбільш універсальний — підтримується тисячами dApps.

import { Web3Wallet } from "@walletconnect/web3wallet";

const web3wallet = await Web3Wallet.init({
    core: new Core({ projectId: WC_PROJECT_ID }),
    metadata: { name: 'My Desktop Wallet', ... }
});

web3wallet.on('session_request', async ({ id, topic, params }) => {
    const { request } = params;
    
    if (request.method === 'eth_sendTransaction') {
        const preview = await buildTransactionPreview(request.params[0]);
        const approved = await showConfirmationDialog(preview);
        
        if (approved) {
            const signedTx = await signTransaction(request.params[0]);
            await web3wallet.respondSessionRequest({
                topic,
                response: { id, result: signedTx, jsonrpc: "2.0" }
            });
        }
    }
});

Інтеграція Hardware Wallets

Десктопний гаманець без підтримки Ledger та Trezor — нішевий продукт. Більшість серйозних користувачів зберігають значні суми на апаратних гаманцях.

import TransportNodeHid from '@ledgerhq/hw-transport-node-hid';
import Eth from '@ledgerhq/hw-app-eth';

async function signWithLedger(
    txHash: string,
    derivationPath: string = "44'/60'/0'/0/0"
): Promise<{ v: number; r: string; s: string }> {
    const transport = await TransportNodeHid.create(5000);
    const eth = new Eth(transport);
    
    const result = await eth.signTransaction(derivationPath, txHash, null);
    return { v: parseInt(result.v, 16), r: result.r, s: result.s };
}

Auto-update та безпека поставок

Десктопна програма оновлюється — кожне оновлення потенційно небезпечне якщо процес скомпрометований. Обов'язкові заходи:

Code signing: Apple Developer (macOS) та EV code signing (Windows). ОС попереджає при запуску неподписаної програми.

Reproducible builds: CI/CD публічна, будь-хто може відтворити та верифікувати hash.

Auto-update через Sparkle (macOS) / Squirrel (Windows): оновлення з перевіркою підпису. Tauri має вбудований updater.

{
  "tauri": {
    "updater": {
      "active": true,
      "endpoints": ["https://releases.mydesktopwallet.com/{{target}}/{{current_version}}"],
      "dialog": true,
      "pubkey": "PUBLICKEYHERE"
    }
  }
}

Security Testing

  • Верифікація що приватний ключ не потрапляє в JavaScript контекст
  • Memory dump тести (ключ не залишається після використання)
  • IPC permissions перевірка (Tauri capabilities)
  • Penetration testing XSS → key extraction (критичен для Electron)
  • RPC response spoofing тести (MITM на локальній мережі)

Стек розробки

Frontend: React 18 + TypeScript + Tailwind CSS, wagmi для web3 абстракцій.

Backend: Tauri + Rust для крипто та зберігання ключів, або Electron + Node.js з native addons для чутливих операцій.

Крипто-бібліотеки: ethers.js (JS), ethers-rs (Rust), @scure/bip39 та @scure/bip32 для HD wallet.

Тестування: Playwright для E2E, Vitest для unit.

MVP з однією мережею, базовим управлінням ключами, відправкою транзакцій — 3–4 місяці для команди 2–3 розробників. Production-ready з мультиланцюгом, WalletConnect, hardware wallet, code signing та security audit — 8–12 місяців.