Web3 Frontend — с чего начать?
- воскресенье, 27 июля 2025 г. в 00:00:02
Создание фронтенда для Web3-приложений - это не только дизайн, кнопки и React. Это мост между пользователем и блокчейном. И ты, как фронтенд-разработчик - тот, кто этот мост строит.
В этой статье ты узнаешь:
Что такое Web3 Frontend и чем он отличается от Web2
Какие инструменты тебе реально нужны
Как начать с нуля
Как использовать wagmi
- главный инструмент Web3-интерфейсов
Web3 Frontend — это интерфейс для децентрализованного приложения (dApp), который работает вместо сервера, напрямую общаясь с блокчейном и кошельком пользователя.
Если ты еще не знаешь что такое децентрализация, то обязательно прочитай об этом отдельно. Это целая концепция вокруг которой все web3 и построено.
Ты не отправляешь запросы на backend, как в Web2. Ты взаимодействуешь с сетью (Ethereum, Polygon, Base и т.п.) через смарт-контракты и подключённый кошелёк.
Библиотека | Назначение |
---|---|
| Основной инструмент для Web3-интерфейса |
| RPC-клиент для вызова контрактов (вместо ethers.js) |
| Подключение кошельков с UI |
| Старый, но популярный Web3-клиент |
Чтобы комфортно работать с wagmi
и любыми Web3-инструментами, нужно понимать, как устроен фундамент. Ниже представлены все ключевые термины, которые ты будешь встречать в dApp’ах снова и снова.
Это строка, которая представляет пользователя или контракт в сети. Она всегда начинается с 0x
, содержит 40 символов.
Пример:
0x1234567890abcdef1234567890abcdef12345678
Есть два вида:
EOA
(Externally Owned Account) — обычный кошелёк (например, MetaMask)
Contract Account
— адрес, по которому развёрнут смарт-контракт
Чтобы отображать адрес красиво, используют ENS (например: vitalik.eth
)
ERC-20 — взаимозаменяемые (USDC, DAI):
поддерживают balanceOf
, transfer
, approve
, decimals
Используй useBalance({ token })
в wagmi
для получения баланса
ERC-721 — NFT (уникальные ID):
функции ownerOf
, tokenURI
, transferFrom
Через tokenURI
получаешь метаданные с image
, name
decimals — количество знаков после запятой:
ETH = 18, USDC = 6
Используй parseUnits
/ formatUnits
из viem
для конвертации
approve + allowance — разрешение контракту тратить токены
Обязательно для свапов, стейкинга и NFT-маркетплейсов
Показывает, к какой сети подключён пользователь. Каждый блокчейн имеет уникальный chainId
.
Примеры:
Ethereum Mainnet → 1
Goerli Testnet → 5
Polygon → 137
Arbitrum → 42161
Optimism → 10
Ты используешь chainId
, чтобы:
определить активную сеть
переключать сеть (через switchNetwork
)
отображать правильные токены/цены
Это объект, через который ты читаешь данные из сети: балансы, блоки, события. Он не может подписывать транзакции.
→ В wagmi
и viem
провайдер создаётся через publicProvider()
или RPC-провайдеры вроде Alchemy, Infura и т. д.
→ Примеры возможностей:
Получить текущий блок
Прочитать состояние контракта
Подписаться на события
Это расширение provider
с доступом к приватному ключу (который держит MetaMask).
С помощью signer
ты можешь:
отправить транзакцию (sendTransaction
)
подписать сообщение (signMessage
)
вызывать contract.write()
(например, mint()
)
→ В wagmi
тебе не нужно напрямую работать с signer
, он используется внутри хуков типа useContractWrite
.
Смарт-контракт — это программа на блокчейне.
ABI
(Application Binary Interface) — это инструкция для твоего фронтенда: какие функции у контракта, какие параметры, что возвращается.
Пример ABI-функции:
{
"name": "mint",
"type": "function",
"stateMutability": "payable",
"inputs": [],
"outputs": []
}
Есть два типа вызовов:
read
→ бесплатный, безопасный, не требует подписи (например, totalSupply()
, balanceOf()
)
write
→ платный (gas), требует подписи (например, mint()
, transfer()
)
→ gas
→ топливо, которое тратится на выполнение кода
→ gasPrice
→ цена за одну единицу газа (в Gwei)
→ fee
= gas
× gasPrice
(тебе нужно заплатить в ETH или другой валюте)
→ nonce
→ счётчик количества транзакций от адреса (чтобы они шли по порядку)
Все write-функции тратят gas
, даже если они не срабатывают (например, revert’ятся)
→ network
= chain
= блокчейн-среда, в которой работает dApp
→ L1
→ основной уровень (Ethereum Mainnet)
→ L2
→ надстройка над L1 для ускорения и удешевления транзакций
Ты должен всегда:
проверять, в какой сети находится пользователь
уметь предлагать переключение сети (например, с mainnet на L2)
работать с несколькими chainId
через wagmi
-конфигурацию
На блокчейне балансы измеряются в целых числах, без запятой
- ETH имеет 18 знаков после запятой
- USDC — 6
В wagmi
ты используешь useBalance({ address })
— и получаешь уже отформатированное значение
Термин | Пояснение |
---|---|
| Адрес пользователя или контракта ( |
| ID блокчейна |
| Канал к блокчейну (чтение) |
| Подписант транзакций (MetaMask и т.д.) |
| Программа на блокчейне |
| Описание функций контракта |
| Стоимость исполнения |
| Чтение без газа |
| Транзакции с подписью и оплатой |
| Счётчик транзакций |
| Подпись строки через кошелёк |
| Авторизация без пароля через Ethereum |
| цифровой актив |
Библиотека wagmi
— это набор React-хуков, которые позволяют:
Подключать кошелёк
читать/записывать в смарт-контракт
Получать баланс, ENS, chain info
Подписывать сообщения и транзакции
npm install wagmi viem @rainbow-me/rainbowkit
// main.tsx
import { WagmiConfig, createConfig, configureChains } from 'wagmi'
import { publicProvider } from 'wagmi/providers/public'
import { mainnet, polygon, optimism } from 'wagmi/chains'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
const { publicClient, webSocketPublicClient } = configureChains(
[mainnet, polygon, optimism],
[publicProvider()]
)
const config = createConfig({
autoConnect: true,
publicClient,
webSocketPublicClient,
})
const queryClient = new QueryClient()
export function Web3Provider({ children }) {
return (
<WagmiConfig config={config}>
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
</WagmiConfig>
)
}
// ConnectWallet.tsx
import { useAccount, useConnect, useDisconnect } from 'wagmi'
import { InjectedConnector } from 'wagmi/connectors/injected'
export function ConnectWallet() {
const { connect } = useConnect({
connector: new InjectedConnector(),
})
const { disconnect } = useDisconnect()
const { isConnected, address } = useAccount()
return isConnected ? (
<div>
<p>Вы подключены: {address}</p>
<button onClick={() => disconnect()}>Отключиться</button>
</div>
) : (
<button onClick={() => connect()}>Подключить MetaMask</button>
)
}
// Balance.tsx
import { useBalance, useAccount } from 'wagmi'
export function Balance() {
const { address } = useAccount()
const { data, isLoading } = useBalance({ address })
if (isLoading) return <p>Загрузка...</p>
return <p>Баланс: {data?.formatted} {data?.symbol}</p>
}
// MintNFT.tsx
import { usePrepareContractWrite, useContractWrite } from 'wagmi'
import { parseEther } from 'viem'
const contractAddress = '0x123...' // твой контракт
const abi = [
{
name: 'mint',
type: 'function',
stateMutability: 'payable',
inputs: [],
outputs: [],
},
]
export function MintNFT() {
const { config } = usePrepareContractWrite({
address: contractAddress,
abi,
functionName: 'mint',
value: parseEther('0.01'),
})
const { write, isLoading, isSuccess } = useContractWrite(config)
return (
<button disabled={!write || isLoading} onClick={() => write?.()}>
{isLoading ? 'Минтим...' : 'Минт NFT'}
{isSuccess && <p>Успех!</p>}
</button>
)
}
Web3 Frontend - это не сложно, если начать с правильных инструментов.
Твоя цель - не перепридумать backend, а создать безопасный, быстрый и дружелюбный интерфейс поверх блокчейна. И в этом тебе максимально помогает wagmi
.
В следующих частях мы остановимся более подробно на живых примерах dapp приложений и разберем как это все работает под капотом.