Разработка мультичейн-кошелька

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка мультичейн-кошелька
Сложная
от 2 недель до 3 месяцев
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1258
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1170
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    873
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1092
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    563
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    830

Разработка мультичейн-кошелька

Мультичейн-кошелёк — это не просто «подключить несколько сетей». Это комплексная система, которая должна корректно обрабатывать принципиально разные блокчейн-архитектуры: EVM-совместимые цепи (Ethereum, Arbitrum, Polygon, BSC), EVM-несовместимые (Solana, Sui, Aptos), Bitcoin с UTXO-моделью, Cosmos экосистему с IBC. Каждая имеет свою криптографию, формат транзакций, fee-механизм и модель аккаунтов.

Ключевой выбор: деривация ключей

HD Wallet и BIP-44 стандарт

Все современные мультичейн кошельки строятся на BIP-32/BIP-39/BIP-44 стандартах. Одна seed-фраза (12-24 слова) → один мастер ключ → дерево дочерних ключей для каждой сети.

BIP-44 путь деривации: m / purpose' / coin_type' / account' / change / index

import { HDNodeWallet, Mnemonic } from 'ethers';
import { derivePath } from 'ed25519-hd-key';
import * as bip39 from 'bip39';

// Генерация seed phrase
const mnemonic = Mnemonic.fromEntropy(crypto.getRandomValues(new Uint8Array(16)));
const seed = await bip39.mnemonicToSeed(mnemonic.phrase);

// EVM цепи (Ethereum, Arbitrum, Polygon) — secp256k1, coin_type = 60
const evmWallet = HDNodeWallet.fromSeed(seed).derivePath("m/44'/60'/0'/0/0");
console.log('EVM address:', evmWallet.address);  // 0x...

// Solana — ed25519, coin_type = 501 (по BIP-44)
// ethers.js не поддерживает ed25519, нужна отдельная библиотека
const solanaPath = "m/44'/501'/0'/0'";
const { key: solanaPrivKey } = derivePath(solanaPath, seed.toString('hex'));
// ... создание Solana Keypair

Разные кривые для разных цепей

Цепь Кривая BIP-44 coin_type
Ethereum и EVM secp256k1 60
Bitcoin secp256k1 0
Solana Ed25519 501
Cosmos/ATOM secp256k1 118
Sui Ed25519 784
Near Ed25519 397

Это означает: нельзя использовать одну библиотеку для всех цепей. EVM — ethers.js/viem, Solana — @solana/web3.js, Cosmos — cosmjs, Bitcoin — bitcoinjs-lib. Архитектура должна это учитывать.

Архитектура кошелька

Chain abstraction layer

// Абстрактный интерфейс для любой цепи
interface ChainAdapter {
    chainId: string;
    chainName: string;

    getAddress(publicKey: Uint8Array): string;
    getBalance(address: string): Promise<bigint>;
    buildTransaction(params: TxParams): Promise<UnsignedTx>;
    signTransaction(tx: UnsignedTx, privateKey: Uint8Array): Promise<SignedTx>;
    broadcastTransaction(tx: SignedTx): Promise<string>;  // возвращает txHash
    getTransactionStatus(txHash: string): Promise<TxStatus>;
    estimateFee(tx: UnsignedTx): Promise<FeeEstimate>;
}

// Реализация для EVM
class EVMAdapter implements ChainAdapter {
    private client: PublicClient;  // viem

    constructor(rpcUrl: string, public chainId: string, public chainName: string) {
        this.client = createPublicClient({ transport: http(rpcUrl) });
    }

    async getBalance(address: string): Promise<bigint> {
        return this.client.getBalance({ address: address as `0x${string}` });
    }

    async buildTransaction(params: TxParams): Promise<UnsignedTx> {
        const nonce = await this.client.getTransactionCount({ address: params.from as `0x${string}` });
        const feeData = await this.client.estimateFeesPerGas();
        return {
            to: params.to,
            value: params.value ?? 0n,
            data: params.data ?? '0x',
            nonce,
            maxFeePerGas: feeData.maxFeePerGas,
            maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
            chainId: BigInt(this.chainId),
        };
    }
    // ...
}

Multi-chain state management

Кошелёк одновременно работает с 10+ сетями. Балансы, транзакции, pending операции — для каждой сети независимо. Плохая реализация: последовательные запросы — медленно. Хорошая: параллельные запросы с per-chain state.

// Параллельная загрузка балансов из всех цепей
async function loadAllBalances(
    adapters: ChainAdapter[],
    addresses: Map<string, string>  // chainId -> address
): Promise<Map<string, bigint>> {
    const results = await Promise.allSettled(
        adapters.map(adapter => {
            const address = addresses.get(adapter.chainId);
            if (!address) return Promise.resolve([adapter.chainId, 0n] as [string, bigint]);
            return adapter.getBalance(address)
                .then(balance => [adapter.chainId, balance] as [string, bigint]);
        })
    );

    const balances = new Map<string, bigint>();
    for (const result of results) {
        if (result.status === 'fulfilled') {
            const [chainId, balance] = result.value;
            balances.set(chainId, balance);
        }
        // fulfilled или rejected — продолжаем, не блокируем из-за одной сети
    }
    return balances;
}

Безопасность: хранение приватных ключей

Мобильный кошелёк

iOS: Secure Enclave для генерации и хранения ключей. Приватный ключ физически не покидает чип. Подпись транзакций происходит внутри Secure Enclave, результат — только подписанная транзакция.

Ограничение: Secure Enclave поддерживает только P-256 (secp256r1), не secp256k1 (Ethereum). Решение: хранить seed зашифрованным в iOS Keychain с биометрией, расшифровывать для подписи только в защищённой памяти.

Android: StrongBox (если поддерживается железом) или Android Keystore. Аналогичные ограничения — HSM на Android тоже не поддерживает secp256k1 напрямую.

// iOS: хранение seed в Secure Enclave-protected Keychain
func storeSeed(_ seed: Data) throws {
    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrAccount as String: "wallet_seed",
        kSecValueData as String: seed,
        kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
        kSecAttrAccessControl as String: SecAccessControlCreateWithFlags(
            nil,
            kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
            [.biometryAny, .privateKeyUsage],
            nil
        )!
    ]
    let status = SecItemAdd(query as CFDictionary, nil)
    guard status == errSecSuccess else { throw KeychainError.unhandledError(status) }
}

Web/Extension кошелёк

Самая уязвимая среда. Chrome Extension работает в isolated world, но JavaScript — не нативный безопасный контекст. Главные риски: malicious extensions получают доступ к той же странице, XSS в dApp может попытаться получить доступ к extension API.

Разделение на background + content script + popup:

  • Приватные ключи хранятся только в background service worker
  • Content script инжектируется в страницы (предоставляет window.ethereum), не имеет доступа к ключам
  • Все операции с ключами — сообщения в background через chrome.runtime.sendMessage
// Background service worker: единственное место с ключами
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (request.type === 'SIGN_TRANSACTION') {
        // Показываем confirmation popup
        chrome.windows.create({ url: 'confirm.html', type: 'popup' }, async (window) => {
            // Ждём подтверждения пользователя
            const confirmed = await waitForUserConfirmation(window!.id!, request.tx);
            if (confirmed) {
                const signed = await signWithStoredKey(request.tx, request.chainId);
                sendResponse({ signed });
            } else {
                sendResponse({ error: 'User rejected' });
            }
        });
        return true; // async response
    }
});

Шифрование при хранении: seed шифруется паролем пользователя через scrypt/argon2 + AES-256-GCM. В памяти хранится только когда кошелёк разблокирован, автоматически очищается через N минут неактивности.

Fee estimation в мультичейн контексте

Каждая цепь имеет свою fee модель:

EVM с EIP-1559: baseFee + priorityFee. BaseFee задаётся протоколом, priorityFee — tip для validator. Нужно мониторить газ цену в реальном времени и рекомендовать slow/average/fast.

async function getEVMFeeOptions(client: PublicClient): Promise<FeeOptions> {
    const [block, feeHistory] = await Promise.all([
        client.getBlock(),
        client.getFeeHistory({ blockCount: 5, rewardPercentiles: [25, 50, 75] })
    ]);

    const baseFee = block.baseFeePerGas ?? 0n;
    const rewardHistory = feeHistory.reward?.flat() ?? [];
    const medianReward = rewardHistory[Math.floor(rewardHistory.length / 2)] ?? 0n;

    return {
        slow: { maxFeePerGas: baseFee * 110n / 100n, maxPriorityFeePerGas: medianReward / 2n },
        average: { maxFeePerGas: baseFee * 120n / 100n, maxPriorityFeePerGas: medianReward },
        fast: { maxFeePerGas: baseFee * 150n / 100n, maxPriorityFeePerGas: medianReward * 2n },
    };
}

Solana: fee = lamports per signature × количество подписей. Относительно стабильно. Нужно учитывать priority fees (compute units) при высокой нагрузке.

Bitcoin: fee = сатоши per virtual byte. Зависит от размера UTXO набора (больше inputs → больше байт → дороже). Нужен UTXO selection алгоритм (coin selection).

Token management и NFT поддержка

Обнаружение токенов

Пользователи не должны вручную добавлять каждый токен. Автоматическое обнаружение:

EVM: Etherscan/Covalent token balances API или сканирование Transfer событий на адрес пользователя. TokenList стандарт (Uniswap Token Lists) для whitelisted токенов.

Solana: getParsedTokenAccountsByOwner — возвращает все SPL токены владельца за один RPC вызов.

NFT поддержка

ERC-721 и ERC-1155 на EVM: Alchemy NFT API или Moralis для агрегации метаданных. IPFS metadata loading с fallback (много NFT имеют битые IPFS ссылки).

// Alchemy NFT API для получения NFT пользователя
async function getUserNFTs(address: string, chainId: number) {
    const alchemy = new Alchemy({
        apiKey: process.env.ALCHEMY_KEY,
        network: chainIdToNetwork(chainId),
    });

    const nfts = await alchemy.nft.getNftsForOwner(address);
    return nfts.ownedNfts.map(nft => ({
        contractAddress: nft.contract.address,
        tokenId: nft.tokenId,
        name: nft.name,
        imageUrl: nft.image.cachedUrl, // Alchemy кэширует IPFS
        collection: nft.contract.name,
    }));
}

WalletConnect и dApp интеграция

WalletConnect v2 — стандартный протокол для связи кошелька с dApp. Sign API для подписи, Auth API для аутентификации.

import { Web3Wallet } from '@walletconnect/web3wallet';
import { Core } from '@walletconnect/core';

const web3wallet = await Web3Wallet.init({
    core: new Core({ projectId: process.env.WALLETCONNECT_PROJECT_ID }),
    metadata: {
        name: 'My Wallet',
        description: 'Multichain Wallet',
        url: 'https://mywallet.io',
        icons: ['https://mywallet.io/icon.png'],
    },
});

// Обработка запроса на подпись транзакции от dApp
web3wallet.on('session_request', async (event) => {
    const { topic, params } = event;
    const { request } = params;

    if (request.method === 'eth_sendTransaction') {
        // Показываем пользователю детали транзакции
        const confirmed = await showTransactionConfirmation(request.params[0]);
        if (confirmed) {
            const signedTx = await signEVMTransaction(request.params[0]);
            await web3wallet.respondSessionRequest({
                topic,
                response: { id: event.id, jsonrpc: '2.0', result: signedTx }
            });
        }
    }
});

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

Компонент Технологии Срок
Core HD wallet bip39 + ethers.js + @solana/web3.js 2-3 недели
EVM multi-chain viem, 10+ сетей 2-3 недели
Solana интеграция @solana/web3.js + Metaplex 2 недели
Mobile (RN) React Native + Expo SecureStore 4-6 недель
Extension (Chrome) MV3 + chrome.storage 3-4 недели
WalletConnect v2 @walletconnect/web3wallet 1-2 недели
NFT + token discovery Alchemy/Moralis API 2-3 недели
UI/UX (полный) React Native / React 6-10 недель

Минимальный production-ready мультичейн кошелёк (EVM + Solana, mobile-first) — 4-5 месяцев. Добавление Bitcoin (UTXO модель) — ещё 4-6 недель отдельно из-за принципиально другой архитектуры. Расширение на Cosmos — 3-4 недели через cosmjs.

Безопасность требует внешнего аудита перед публичным релизом — кошелёк хранит ключи пользователей напрямую, это максимальный риск.