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

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Реалізація підключення криптогаманця до веб-застосунку
Середня
~3-5 робочих днів
Часті питання

Наші компетенції:

Етапи розробки

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

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

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

Підключення гаманця — перша точка входу в будь-яке Web3 застосування. Користувач клацає "Connect Wallet", браузер відкриває MetaMask або WalletConnect QR, застосування отримує адресу та підпис. Звучить просто, але під капотом — три різні протоколи, дюжина постачальників гаманців та ряд проблем із станом, які потрібно вирішити правильно з самого початку.

Що відбувається під час підключення

  1. Браузер перевіряє наявність window.ethereum (вбудовані гаманці: MetaMask, Rabby, Brave Wallet)
  2. Застосування викликає eth_requestAccounts — з'являється спливаюче вікно підтвердження
  3. Гаманець повертає масив адрес, перша — активна
  4. Застосування підписує SIWE (Sign-In with Ethereum) повідомлення для автентифікації на бекенді
  5. Сесія створюється на сервері за підписом

WalletConnect (мобільні гаманці) працює по-іншому: через сервер ретрансляції, WebSocket та QR-код. Coinbase Wallet підтримує обидва методи.

Мінімальна реалізація через ethers.js

// lib/wallet.ts
import { BrowserProvider, JsonRpcSigner } from 'ethers';

export interface WalletState {
  address: string | null;
  chainId: number | null;
  provider: BrowserProvider | null;
  signer: JsonRpcSigner | null;
}

export async function connectWallet(): Promise<WalletState> {
  if (!window.ethereum) {
    throw new Error('No injected wallet found. Install MetaMask.');
  }

  const provider = new BrowserProvider(window.ethereum);
  const accounts = await provider.send('eth_requestAccounts', []);
  const network = await provider.getNetwork();
  const signer = await provider.getSigner();

  return {
    address: accounts[0],
    chainId: Number(network.chainId),
    provider,
    signer,
  };
}

export async function switchChain(chainId: number): Promise<void> {
  await window.ethereum.request({
    method: 'wallet_switchEthereumChain',
    params: [{ chainId: `0x${chainId.toString(16)}` }],
  });
}

Обробка подій гаманця

Гаманець змінює рахунок або мережу без сповіщення програми — потрібно підписатися на события:

// hooks/useWalletEvents.ts
import { useEffect } from 'react';
import { useWalletStore } from '@/store/wallet';

export function useWalletEvents() {
  const { disconnect, setAddress, setChainId } = useWalletStore();

  useEffect(() => {
    if (!window.ethereum) return;

    const handleAccountsChanged = (accounts: string[]) => {
      if (accounts.length === 0) {
        disconnect();
      } else {
        setAddress(accounts[0]);
      }
    };

    const handleChainChanged = (chainIdHex: string) => {
      setChainId(parseInt(chainIdHex, 16));
      // Не перезавантажуємо сторінку — оновлюємо стан
    };

    window.ethereum.on('accountsChanged', handleAccountsChanged);
    window.ethereum.on('chainChanged', handleChainChanged);
    window.ethereum.on('disconnect', disconnect);

    return () => {
      window.ethereum.removeListener('accountsChanged', handleAccountsChanged);
      window.ethereum.removeListener('chainChanged', handleChainChanged);
      window.ethereum.removeListener('disconnect', disconnect);
    };
  }, [disconnect, setAddress, setChainId]);
}

SIWE-автентифікація

Адреса гаманця сама по собі не є ідентифікатором користувача. Його можна підробити в HTTP-запиті. Для сеансу бекенду потрібна підпис:

// lib/siwe.ts
import { SiweMessage } from 'siwe';

export async function signInWithEthereum(
  address: string,
  chainId: number,
  signer: JsonRpcSigner,
): Promise<{ message: string; signature: string }> {
  const nonce = await fetch('/api/auth/nonce').then(r => r.text());

  const message = new SiweMessage({
    domain: window.location.host,
    address,
    statement: 'Sign in to MyApp',
    uri: window.location.origin,
    version: '1',
    chainId,
    nonce,
  });

  const messageStr = message.prepareMessage();
  const signature = await signer.signMessage(messageStr);

  return { message: messageStr, signature };
}

Бекенд верифікує підпис через пакет siwe (Node.js) або будь-яку реалізацію ecrecover. Nonce у Redis з TTL 5 хвилин — захист від атак повторення.

Кілька гаманців через універсальний постачальник

Для підтримки MetaMask, WalletConnect, Coinbase Wallet без користувацької логіки для кожного — використовуйте @web3-onboard або стек wagmi + viem. Мінімальний приклад з @web3-onboard:

import Onboard from '@web3-onboard/core';
import injectedModule from '@web3-onboard/injected-wallets';
import walletConnectModule from '@web3-onboard/walletconnect';

const injected = injectedModule();
const walletConnect = walletConnectModule({
  projectId: process.env.NEXT_PUBLIC_WC_PROJECT_ID!,
  requiredChains: [1, 137],
});

export const onboard = Onboard({
  wallets: [injected, walletConnect],
  chains: [
    { id: '0x1', token: 'ETH', label: 'Ethereum Mainnet', rpcUrl: process.env.ETH_RPC_URL! },
    { id: '0x89', token: 'MATIC', label: 'Polygon', rpcUrl: process.env.POLYGON_RPC_URL! },
  ],
  appMetadata: {
    name: 'MyApp',
    icon: '/logo.svg',
    description: 'DeFi platform',
  },
});

Стійкість підключення

Після перезавантаження сторінки стан гаманця потрібно відновити без повторного спливаючого вікна:

// Перевірка під час ініціалізації
async function restoreConnection(): Promise<void> {
  if (!window.ethereum) return;

  // eth_accounts (не eth_requestAccounts) — не викликає спливаюче вікно
  const accounts: string[] = await window.ethereum.request({
    method: 'eth_accounts',
  });

  if (accounts.length > 0) {
    // Гаманець уже авторизований — відновімо стан
    const provider = new BrowserProvider(window.ethereum);
    const network = await provider.getNetwork();
    walletStore.set({ address: accounts[0], chainId: Number(network.chainId) });
  }
}

Часова шкала: базове підключення MetaMask + WalletConnect з SIWE-автентифікацією — 2–3 дні. Включаючи обробку подій, стійкість та підтримку 3–4 гаманців через @web3-onboard3–5 днів.