Проектирование архитектуры dApp
dApp архитектура — это не просто "React фронтенд + смарт-контракт". Это продуманная система где frontend, indexer, wallet integration, и контракты работают как единое целое с хорошим UX. Типичная ошибка: разрабатывать frontend отдельно от контрактной архитектуры — потом оказывается что UI не может эффективно читать нужные данные.
Ключевые компоненты dApp
Smart Contract Layer
Контракты проектируются с учётом frontendability:
- Богатые Events для индексирования (все важные действия логируются)
- View функции для чтения без газа
- Multicall совместимость
State Management
// Современный dApp стек: wagmi v2 + viem + TanStack Query
import { useReadContract, useWriteContract, useWaitForTransactionReceipt } from "wagmi";
import { formatUnits } from "viem";
function PoolStats() {
const { data: tvl } = useReadContract({
address: POOL_ADDRESS,
abi: POOL_ABI,
functionName: "totalAssets",
query: { refetchInterval: 30_000 }, // обновляем каждые 30 секунд
});
const { data: userBalance } = useReadContract({
address: POOL_ADDRESS,
abi: POOL_ABI,
functionName: "balanceOf",
args: [address],
});
return (
<div>
<p>TVL: {tvl ? formatUnits(tvl, 18) : "Loading..."} ETH</p>
<p>Your balance: {userBalance ? formatUnits(userBalance, 18) : "0"}</p>
</div>
);
}
Batch RPC calls (Multicall3)
Избегаем N отдельных RPC запросов через batching:
import { multicall } from "viem/actions";
// Вместо 10 отдельных запросов — один
const results = await multicall(client, {
contracts: [
{ address: TOKEN_A, abi: ERC20_ABI, functionName: "balanceOf", args: [user] },
{ address: TOKEN_B, abi: ERC20_ABI, functionName: "balanceOf", args: [user] },
{ address: POOL, abi: POOL_ABI, functionName: "totalAssets" },
// ...ещё 7 запросов
],
});
Transaction flow UX
function DepositButton({ amount }: { amount: bigint }) {
const { data: hash, writeContract, isPending } = useWriteContract();
const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({ hash });
// Состояния: idle → pending (wallet) → confirming (chain) → success/error
const status = isPending ? "WAITING_WALLET"
: isConfirming ? "CONFIRMING"
: isSuccess ? "SUCCESS"
: "IDLE";
return (
<button
onClick={() => writeContract({ address: POOL, abi, functionName: "deposit", args: [amount] })}
disabled={status !== "IDLE"}
>
{status === "WAITING_WALLET" && "Confirm in wallet..."}
{status === "CONFIRMING" && "Confirming..."}
{status === "SUCCESS" && "Deposited!"}
{status === "IDLE" && "Deposit"}
</button>
);
}
Data fetching архитектура
Realtime (< 1 sec latency): WebSocket к RPC или Alchemy SDK
Recent history (последние 1000 events): The Graph (subgraph)
Historical analytics: Self-hosted PostgreSQL indexer
Prices: CoinGecko API + Chainlink on-chain
Wallet connection
// RainbowKit конфигурация
import { getDefaultConfig, RainbowKitProvider } from "@rainbow-me/rainbowkit";
import { arbitrum, mainnet, base } from "wagmi/chains";
const config = getDefaultConfig({
appName: "MyDApp",
projectId: WALLETCONNECT_PROJECT_ID,
chains: [mainnet, arbitrum, base],
wallets: [
{ groupName: "Popular", wallets: [metaMaskWallet, coinbaseWallet, walletConnectWallet] },
],
});
Проектирование dApp архитектуры с учётом всех слоёв: 1-2 недели. Включает wireframes контрактного взаимодействия, data flow диаграммы, frontend стек выбор и UX flow документацию.







