it Новости Программирование для Web3: как создают децентрализованные программы?
Программирование для Web3: как создают децентрализованные программы?

Программирование для Web3: как создают децентрализованные программы?

1 389
14 сентября 2025 в 12:28

Разбираемся, из чего состоит стек Web3, как писать смарт-контракты, подключать кошельки, хранить данные децентрализованно и выпускать токены. Полный гайд для разработчика.

Web3 — это не просто новые инструменты, а изменение подхода к созданию приложений. В децентрализованных приложениях (dApp) логика и данные больше не принадлежат одному серверу: ядро переносится в смарт-контракты, а идентичность пользователя — в его кошелёк. Такой сдвиг требует иного мышления о архитектуре, безопасности, UX и DevOps.


Что такое Web3 и чем dApp отличается от обычного приложения?

В классическом вебе у нас есть клиент (браузер/мобильное приложение) и сервер с БД. В Web3 серверная «правда» живёт в блокчейне: код смарт-контрактов исполняется валидаторами, данные транзакций неизменяемы, а доступ к функциям определяется криптографическими ключами. dApp — это связка смарт-контрактов, фронтенда, кошелька и, часто, децентрализованного хранилища.


В результате меняются приоритеты: безопасность контракта важнее скорости релиза, неизменяемость важнее «горячих фиксов», а пользователь сам владеет своими активами — без «сброса пароля через e-mail».


Базовые компоненты стека Web3

Блокчейн-рантайм

EVM-совместимые сети (Ethereum, Polygon, BNB Smart Chain, Avalanche, Base и др.) позволяют писать контракты на Solidity/Vyper. Есть и не-EVM платформы (Solana, Aptos, Sui), где контракты пишут на Rust или Move.


Смарт-контракты

Это неизменяемые программы в блокчейне. Они управляют активами, определяют правила протокола (DEX, лендинг, DAO) и выступают публичным API: любой может вызвать их методы, оплатив газ.


Кошельки

Ключи пользователя — это и его логин, и подпись запросов. Кошельки (MetaMask, Rabby, Phantom и др.) выступают как провайдеры: они подключают фронтенд к сети, показывают пользователю транзакции и подписывают их.


Децентрализованное хранение

Крупные данные и статику часто хранят в IPFS/Arweave/Filecoin. Хэш (CID) закрепляется в контракте, чтобы любой мог проверить подлинность содержимого.


Индексаторы и субграфы

Для удобных запросов используют The Graph или собственные индексаторы: они «распаковывают» события блокчейна в удобные API, чтобы фронтенд не делал сотни прямых вызовов.


Жизненный цикл dApp: от идеи до мейннета

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


Проектирование смарт-контрактов: интерфейсы, события, доступ

Интерфейсы

Придерживайтесь стандартов (ERC-20/721/1155/4626/777/1271/4337 и др.). Это обеспечивает совместимость с кошельками, биржами и аналитикой.


События

Всё важное логируйте через события — их легко индексировать и показывать на фронтенде. События — это «канал связи» вашего контракта с остальным миром.


Доступ и роли

Минимизируйте права. Используйте паттерны Ownable/AccessControl, timelock-контракты для «прозрачных» апгрейдов и экстренный паузер.


Минимальный пример ERC-20 на Solidity (демо)

pragma solidity ^0.8.20;

contract SimpleToken {
	string public name = "DemoToken";
	string public symbol = "DEMO";
	uint8 public decimals = 18;
	uint256 public totalSupply;

	mapping(address => uint256) public balanceOf;
	mapping(address => mapping(address => uint256)) public allowance;

	event Transfer(address indexed from, address indexed to, uint256 value);
	event Approval(address indexed owner, address indexed spender, uint256 value);

	constructor(uint256 initialSupply) {
		totalSupply = initialSupply * 10**decimals;
		balanceOf[msg.sender] = totalSupply;
		emit Transfer(address(0), msg.sender, totalSupply);
	}

	function transfer(address to, uint256 value) external returns (bool) {
		require(balanceOf[msg.sender] >= value, "INSUFFICIENT");
		unchecked { balanceOf[msg.sender] -= value; }
		balanceOf[to] += value;
		emit Transfer(msg.sender, to, value);
		return true;
	}

	function approve(address spender, uint256 value) external returns (bool) {
		allowance[msg.sender][spender] = value;
		emit Approval(msg.sender, spender, value);
		return true;
	}

	function transferFrom(address from, address to, uint256 value) external returns (bool) {
		uint256 allowed = allowance[from][msg.sender];
		require(balanceOf[from] >= value && allowed >= value, "INSUFFICIENT");
		unchecked {
			balanceOf[from] -= value;
			allowance[from][msg.sender] = allowed - value;
		}
		balanceOf[to] += value;
		emit Transfer(from, to, value);
		return true;
	}
}

На практике лучше использовать проверенные реализации (например, OpenZeppelin), чтобы снизить риски и ускорить разработку.


Инструменты: Hardhat/Foundry, тестовые сети и деплой

Hardhat

Удобен для плагинов, JS/TS-скриптов и локальной сети. Foundry — быстрый набор на Rust (forge/anvil/cast) с фокусом на тестах и fuzzing. Оба инструмента хорошо дополняют друг друга.

// hardhat.config.ts (простейший пример)
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";

const config: HardhatUserConfig = {
	solidity: "0.8.20",
	networks: {
		sepolia: {
			url: process.env.RPC_URL,
			accounts: [process.env.PRIVATE_KEY as string]
		}
	}
};
export default config;

Другой пример:

// Скрипт деплоя (scripts/deploy.ts)
import { ethers } from "hardhat";

async function main() {
	const Token = await ethers.getContractFactory("SimpleToken");
	const token = await Token.deploy(1_000_000);
	await token.waitForDeployment();
	console.log("Token at:", await token.getAddress());
}

main().catch((e) => { console.error(e); process.exit(1); });

Фронтенд: подключение кошелька и вызовы контракта

На фронтенде можно работать с контрак том через ethers.js/viem/wagmi. Пользователь взаимодействует через кошелёк: вы читаете состояние контракта вызовами «view», а для транзакций создаёте запрос на подпись.

// Чтение баланса через ethers.js
import { ethers } from "ethers";
import abi from "./SimpleTokenABI.json";

async function readBalance(address) {
	const provider = new ethers.BrowserProvider(window.ethereum);
	const contract = new ethers.Contract("0xTOKEN", abi, provider);
	const bal = await contract.balanceOf(address);
	console.log("Balance:", ethers.formatUnits(bal, 18));
}

Другой пример:

// Отправка транзакции
import { ethers } from "ethers";
import abi from "./SimpleTokenABI.json";

async function transfer(to, amount) {
	const provider = new ethers.BrowserProvider(window.ethereum);
	const signer = await provider.getSigner();
	const contract = new ethers.Contract("0xTOKEN", abi, signer);
	const tx = await contract.transfer(to, ethers.parseUnits(amount, 18));
	const receipt = await tx.wait();
	console.log("Tx mined:", receipt.transactionHash);
}

Хранение данных: IPFS/Arweave и связь с контрактом

Большие файлы в блокчейн класть нельзя — это дорого и бессмысленно. Храните их в IPFS/Arweave, а в контракт заносите только их хэш (CID). Так любой сможет проверить, что контент не подменён.

// Псевдокод загрузки файла в IPFS через API-провайдера
import { create } from "ipfs-http-client";

const ipfs = create({ url: "https://ipfs.infura.io:5001/api/v0" });
const res = await ipfs.add(fileBuffer);
console.log("CID:", res.cid.toString());
// Далее CID можно сохранить в смарт-контракт

Стандарты токенов и NFT: ERC-20/721/1155

ERC-20 — взаимозаменяемые токены (балансы как числа). ERC-721 — уникальные невзаимозаменяемые токены (NFT). ERC-1155 — мульти-токен стандарт, объединяющий фичи 20 и 721. Использование стандартов обеспечивает работу с кошельками, маркетплейсами и DeFi-протоколами «из коробки».


Безопасность: угрозы и практики защиты

Типовые векторы атак

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


Практики

Аудит сторонними командами, формальные проверки критичных инвариантов, fuzzing-тесты, лимиты на операции, timelock перед апгрейдами, bug bounty. Никогда не деплойте непроверенный код в мейннет.


Тестирование: unit, integration, fuzzing и property-based

Тестируйте не только позитивные сценарии, но и невалидные входы, экстремальные значения, повторные вызовы и экономические инварианты (например, «из воздуха не появляется прибыль»). Используйте coverage-отчёты и дифф-тесты при рефакторинге.

// Пример простого теста Hardhat + Mocha/Chai
import { expect } from "chai";
import { ethers } from "hardhat";

describe("SimpleToken", function () {
	it("mints to deployer", async function () {
		const [owner] = await ethers.getSigners();
		const Token = await ethers.getContractFactory("SimpleToken");
		const token = await Token.deploy(1000);
		const bal = await token.balanceOf(owner.address);
		expect(bal).to.equal(1000n * 10n ** 18n);
	});
});

Экономика протокола: комиссии, стимулы, токеномика

Любой DeFi- или игровой протокол — это экономика. Определите, откуда берётся доход, кто платит комиссию, как стимулируются поставщики ликвидности, как распределяются токены и как предотвращаются злонамеренные стратегии (например, сэндвич-атаки).


Масштабирование: L2-роллапы, сиквенсеры и мосты

Для снижения комиссий используют L2-решения (Optimistic/ZK-роллапы). Они обрабатывают транзакции вне L1 и периодически публикуют доказательства. При работе с несколькими сетями учитывайте задержки мостов, возможные «ребятчи» и риски централизованных сиквенсеров.


Аккаунт-абстракция (ERC-4337) и UX без боли

Аккаунт-абстракция позволяет создавать смарт-аккаунты с кастомной логикой подписи, социальным восстановлением и оплатой газа спонсором. Это сильно упрощает онбординг и делает UX ближе к привычным веб-приложениям.


Оракулы и внешние данные

Контракты сами не видят интернет. Для цен, погодных и прочих данных применяют оракулы (Chainlink и др.). Обеспечьте устойчивость к сбоям, проверяйте свежесть и консистентность фидов.


Логирование и аналитика: события, индексаторы, дашборды

В смарт-контрактах события — источник правды. Стройте на их основе субграфы, отправляйте метрики в аналитические системы, делайте публичные дашборды. Это упрощает поддержку и повышает доверие к протоколу.


Практический чек-лист перед релизом

1. Покрытие тестами критичных путей ≥ 90%.

2. Fuzzing и property-based тесты на инварианты.

3. Аудит кода и исправление отчёта.

4. Timelock + ролевой контроль + паузер.

5. План апгрейдов (прокси) и миграций.

6. Документация ABI/адресов/событий.

7. Онбординг: понятные модалки, лимиты, предупреждения.

8. Мониторинг событий, алерты и резервные RPC.


Пример минимального dApp-потока

1) Пользователь подключает кошелёк. 2) Фронтенд читает состояние контракта. 3) Пользователь инициирует действие (например, «перевести токены»). 4) Кошелёк показывает транзакцию, пользователь подписывает. 5) После майнинга фронтенд слушает событие и обновляет интерфейс. Ни логинов, ни паролей — только подписи и адреса.

// Подключение кошелька и получение адреса
async function connect() {
	if (!window.ethereum) throw new Error("No wallet");
	const [acc] = await window.ethereum.request({ method: "eth_requestAccounts" });
	return acc;
}

Организация репозитория и DevOps для Web3

Разделяйте пакеты: контракты (Solidity), фронтенд (React/Vue/Svelte), скрипты деплоя, субграфы. Сборку и тесты запускайте в CI. Храните артефакты (ABI, адреса, схемы) в версии, сопоставленной с релизом. Для мейннета используйте многоступенчатое согласование и timelock.


Куда развиваться дальше

Освойте один EVM-стек (Solidity + Hardhat/Foundry + ethers/viem), затем попробуйте не-EVM (Solana/Aptos). Разберитесь в L2, ERC-4337 и индексаторах. Потренируйтесь на клон-проектах: простая биржа, NFT-минтер, вольт ERC-4626, DAO-голосование.

Больше интересных новостей

Комментарии
Добавить комментарий

Пока комментариев нет