Web3 и blockchain приложения

Vue.js — прогрессивный фреймворк для построения пользовательских интерфейсов, который отлично подходит для создания децентрализованных приложений (dApps) благодаря своей реактивной архитектуре и компонентной структуре. В контексте Web3 Vue.js используется для взаимодействия с блокчейнами через смарт-контракты, управление состоянием пользователя и визуализацию данных с блокчейна.


Установка и настройка проекта

Для начала создается стандартный Vue-проект через Vite или Vue CLI:

npm create vite@latest my-dapp --template vue
cd my-dapp
npm install

Далее подключаются библиотеки для работы с Web3, такие как ethers.js или web3.js:

npm install ethers

ethers.js обеспечивает удобный API для взаимодействия с Ethereum-совместимыми блокчейнами, управления кошельками и подписания транзакций.


Настройка провайдера Web3

Создается сервис для подключения к блокчейну. Используется объект provider и signer для чтения данных и отправки транзакций:

import { ethers } from "ethers";

let provider;
let signer;

export function connectWallet() {
  if (window.ethereum) {
    provider = new ethers.BrowserProvider(window.ethereum);
    return provider.send("eth_requestAccounts", []).then(() => {
      signer = provider.getSigner();
      return signer;
    });
  } else {
    throw new Error("MetaMask не найден");
  }
}

Ключевые моменты:

  • window.ethereum — объект, предоставляемый MetaMask.
  • provider.send("eth_requestAccounts") запрашивает разрешение на доступ к кошельку.
  • signer используется для подписания транзакций.

Взаимодействие со смарт-контрактами

Смарт-контракты на Ethereum обычно пишутся на Solidity. В Vue.js для работы с ними создается объект контракта:

import contractABI from './MyContract.json';

const contractAddress = "0x1234567890abcdef";

export function getContract(signerOrProvider) {
  return new ethers.Contract(contractAddress, contractABI, signerOrProvider);
}

Примеры взаимодействия:

  • Чтение данных:
async function getValue() {
  const contract = getContract(provider);
  const value = await contract.somePublicVariable();
  return value;
}
  • Отправка транзакций:
async function setValue(newValue) {
  const contract = getContract(signer);
  const tx = await contract.setValue(newValue);
  await tx.wait();
}

Управление состоянием в Vue.js

Для dApp важно отслеживать состояние кошелька и транзакций. Используются реактивные переменные Vue или Pinia/Vuex. Пример с ref и reactive:

import { ref, reactive } from 'vue';

export const wallet = reactive({
  address: null,
  balance: null
});

export async function updateWallet() {
  try {
    const signer = await connectWallet();
    wallet.address = await signer.getAddress();
    wallet.balance = ethers.formatEther(await signer.getBalance());
  } catch (error) {
    console.error(error);
  }
}

Реактивность позволяет автоматически обновлять интерфейс при изменении данных блокчейна.


Подключение событий смарт-контракта

Смарт-контракты могут отправлять события (events), на которые dApp может подписываться:

const contract = getContract(provider);

contract.on("ValueChanged", (newValue, event) => {
  console.log("Новое значение:", newValue);
});

Использование событий позволяет создавать динамический интерфейс без постоянного опроса блокчейна.


Работа с токенами и NFT

Для работы с ERC-20 и ERC-721 токенами создаются соответствующие контракты:

const erc20Abi = [...]; // ABI токена
const tokenContract = new ethers.Contract(tokenAddress, erc20Abi, signer);

// Баланс токена
async function getTokenBalance() {
  return await tokenContract.balanceOf(wallet.address);
}

// Отправка токена
async function sendToken(to, amount) {
  const tx = await tokenContract.transfer(to, amount);
  await tx.wait();
}

Для NFT используется стандарт ERC-721:

const nftContract = new ethers.Contract(nftAddress, erc721Abi, signer);

// Получение метаданных NFT
async function getNFTMetadata(tokenId) {
  const uri = await nftContract.tokenURI(tokenId);
  const response = await fetch(uri);
  return await response.json();
}

Оптимизация производительности dApp

  1. Локальный кэш данных: хранение данных блокчейна в состоянии Vue позволяет уменьшить количество запросов.
  2. Использование computed и watch: для автоматического обновления UI при изменении состояния.
  3. Динамическая загрузка компонентов: тяжелые модули, например визуализаторы NFT, подключаются только при необходимости.

Безопасность и ограничения

  • Никогда не хранить приватные ключи в коде.
  • Проверять контракты перед взаимодействием.
  • Ограничивать количество запросов к RPC для предотвращения перегрузки сети.
  • Обрабатывать ошибки транзакций и отклонений пользователем.

Интеграция с Vue Router и интерфейсом

dApp обычно имеет маршрутизацию по страницам: кошелек, токены, история транзакций. Используются динамические маршруты и lazy-loading компонентов:

import { createRouter, createWebHistory } from 'vue-router';

const routes = [
  { path: '/', component: () => import('./views/Home.vue') },
  { path: '/tokens', component: () => import('./views/Tokens.vue') },
];

export const router = createRouter({
  history: createWebHistory(),
  routes
});

В компонентах реализуются привязки состояния через setup и Composition API, обеспечивая плавное обновление данных при изменении блокчейна.


Интерактивные графики и данные

Для визуализации данных блокчейна, например балансов или истории транзакций, можно подключать библиотеки Chart.js или ECharts. Реактивные данные Vue.js обновляют графики автоматически при изменении состояния кошелька или смарт-контрактов.

import { ref, watch } from 'vue';
import { Chart } from 'chart.js';

const chartData = ref([]);

watch(chartData, (newData) => {
  // обновление графика
});

Эта структура позволяет создавать высоко интерактивные Web3 интерфейсы с современным UX.