Web318 марта 2026 16 мин

Solidity за 1 день: пишем первый смарт-контракт

Remix IDE, структура контракта, типы данных, ERC-20 токен, деплой в тестнет — полное руководство для начинающих.

Что такое смарт-контракты

Смарт-контракт — это программа, которая живёт на блокчейне и выполняется автоматически при определённых условиях. Никакой посредник не может её изменить, остановить или подделать.

Примеры смарт-контрактов:

  • ERC-20 токен: цифровая валюта (USDT, LINK, UNI — это всё смарт-контракты)
  • DEX (Uniswap): обмен токенов без посредников
  • Lending (Aave): кредиты без банков
  • NFT (ERC-721): уникальные цифровые объекты

Solidity — основной язык для смарт-контрактов на Ethereum, BSC, Polygon, Arbitrum, Base и других EVM-совместимых блокчейнах.

Подготовка

Что нужно

  1. Браузер — Chrome или Firefox
  2. MetaMask — расширение для работы с блокчейном (metamask.io)
  3. Remix IDE — онлайн-среда для Solidity (remix.ethereum.org)
  4. Тестовый ETH — бесплатные токены для тестовой сети

Настройка MetaMask

  1. Установите расширение MetaMask
  2. Создайте кошелёк (сохраните seed-фразу!)
  3. Добавьте тестовую сеть Sepolia:
    • Network Name: Sepolia
    • RPC URL: https://rpc.sepolia.org
    • Chain ID: 11155111
    • Currency: SepoliaETH
  4. Получите тестовый ETH: sepoliafaucet.com или faucet.sepolia.dev

Remix IDE

Откройте remix.ethereum.org — это ваша IDE для Solidity. Всё в браузере, ничего устанавливать не нужно.

Основы Solidity

Структура контракта

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract MyFirstContract {
    // Состояние (хранится на блокчейне)
    string public name;
    uint256 public count;
    address public owner;

    // Конструктор (вызывается один раз при деплое)
    constructor(string memory _name) {
        name = _name;
        owner = msg.sender;  // Тот, кто задеплоил
    }

    // Функция (изменяет состояние — стоит газ)
    function increment() public {
        count += 1;
    }

    // View-функция (только чтение — бесплатно)
    function getCount() public view returns (uint256) {
        return count;
    }
}

Типы данных

// Целые числа
uint256 public amount = 100;      // Беззнаковое (0 и выше)
int256 public temperature = -10;  // Со знаком

// Адреса
address public wallet = 0x1234...;
address payable public receiver;  // Может получать ETH

// Строки и байты
string public name = "Hello";
bytes32 public hash;

// Булевы
bool public isActive = true;

// Маппинги (словари)
mapping(address => uint256) public balances;
mapping(address => mapping(address => uint256)) public allowances;

// Массивы
uint256[] public numbers;
address[] public users;

// Структуры
struct User {
    string name;
    uint256 balance;
    bool isActive;
}
mapping(address => User) public users;

// Перечисления
enum Status { Pending, Active, Completed, Cancelled }
Status public currentStatus;

Модификаторы доступа

contract AccessControl {
    address public owner;

    constructor() {
        owner = msg.sender;
    }

    // Модификатор — проверка перед выполнением функции
    modifier onlyOwner() {
        require(msg.sender == owner, "Not the owner");
        _;  // Здесь выполняется тело функции
    }

    // Только владелец может вызвать
    function withdraw() public onlyOwner {
        payable(owner).transfer(address(this).balance);
    }

    // Видимость функций:
    // public    — вызывает кто угодно
    // external  — только извне (не из контракта)
    // internal  — только из контракта и наследников
    // private   — только из этого контракта
}

События (Events)

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

    function transfer(address to, uint256 amount) public {
        // ... логика перевода ...
        emit Transfer(msg.sender, to, amount);  // Записываем в лог
    }
}

Events записываются в лог блокчейна. Фронтенд может их слушать в реальном времени.

Пишем ERC-20 токен

ERC-20 — это стандарт токена. Все "монеты" на Ethereum (USDT, LINK, UNI) — это ERC-20. Давайте создадим свой.

Полный код ERC-20

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract MyToken {
    string public name;
    string public symbol;
    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(
        string memory _name,
        string memory _symbol,
        uint256 _initialSupply
    ) {
        name = _name;
        symbol = _symbol;
        totalSupply = _initialSupply * 10 ** decimals;
        balanceOf[msg.sender] = totalSupply;
        emit Transfer(address(0), msg.sender, totalSupply);
    }

    function transfer(address to, uint256 value) public returns (bool) {
        require(to != address(0), "Transfer to zero address");
        require(balanceOf[msg.sender] >= value, "Insufficient balance");

        balanceOf[msg.sender] -= value;
        balanceOf[to] += value;

        emit Transfer(msg.sender, to, value);
        return true;
    }

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

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) public returns (bool) {
        require(to != address(0), "Transfer to zero address");
        require(balanceOf[from] >= value, "Insufficient balance");
        require(allowance[from][msg.sender] >= value, "Insufficient allowance");

        balanceOf[from] -= value;
        balanceOf[to] += value;
        allowance[from][msg.sender] -= value;

        emit Transfer(from, to, value);
        return true;
    }
}

Разбор кода

balanceOf — сколько токенов у каждого адреса. Это маппинг: адрес → число.

allowance — разрешения. "Адрес X разрешил адресу Y тратить Z токенов от его имени". Это нужно для DEX (Uniswap) и других протоколов.

transfer — прямой перевод. Я отправляю токены тебе.

approve + transferFrom — делегированный перевод. Я разрешаю смарт-контракту Uniswap взять мои токены и обменять.

decimals = 18 — стандарт. 1 токен = 1 × 10^18 минимальных единиц (как 1 ETH = 10^18 wei).

Деплой в Remix

Шаг 1: Создание файла

  1. В Remix: File Explorer → New File → MyToken.sol
  2. Вставьте код ERC-20

Шаг 2: Компиляция

  1. Вкладка "Solidity Compiler" (слева)
  2. Compiler: 0.8.24
  3. Нажмите "Compile MyToken.sol"
  4. Зелёная галочка = успех

Шаг 3: Деплой в тестнет

  1. Вкладка "Deploy & Run Transactions"
  2. Environment: "Injected Provider - MetaMask"
  3. MetaMask подключится (убедитесь, что выбрана сеть Sepolia)
  4. Параметры конструктора:
    • _name: "My Token"
    • _symbol: "MTK"
    • _initialSupply: 1000000
  5. Нажмите "Deploy"
  6. MetaMask попросит подтвердить транзакцию → Confirm

Через 15-30 секунд контракт задеплоен! Адрес контракта появится в Remix.

Шаг 4: Тестирование

В Remix внизу появится интерфейс контракта:

  1. name() → "My Token"
  2. symbol() → "MTK"
  3. totalSupply() → 1000000000000000000000000 (1M × 10^18)
  4. balanceOf(ваш адрес) → вся эмиссия
  5. transfer(другой адрес, 1000000000000000000) → переведёт 1 токен

Безопасность

Типичные уязвимости

1. Reentrancy (повторный вход)

// ОПАСНО
function withdraw() public {
    uint256 amount = balances[msg.sender];
    (bool success, ) = msg.sender.call{value: amount}("");
    require(success);
    balances[msg.sender] = 0;  // Обнуление ПОСЛЕ отправки!
}

// БЕЗОПАСНО (Checks-Effects-Interactions)
function withdraw() public {
    uint256 amount = balances[msg.sender];
    balances[msg.sender] = 0;  // Обнуление ДО отправки
    (bool success, ) = msg.sender.call{value: amount}("");
    require(success);
}

2. Integer overflow/underflow

В Solidity 0.8+ это решено — арифметика проверяется автоматически. Но в старых контрактах (0.7 и ниже) — нужна библиотека SafeMath.

3. Неправильный контроль доступа

// ОПАСНО — кто угодно может вызвать
function mint(uint256 amount) public {
    totalSupply += amount;
    balanceOf[msg.sender] += amount;
}

// БЕЗОПАСНО — только владелец
function mint(uint256 amount) public onlyOwner {
    totalSupply += amount;
    balanceOf[msg.sender] += amount;
}

Чек-лист безопасности

  • [ ] Используете Solidity 0.8+
  • [ ] Checks-Effects-Interactions паттерн
  • [ ] Все функции с правильным контролем доступа
  • [ ] Нет tx.origin для авторизации (только msg.sender)
  • [ ] Обработка возвращаемых значений external calls
  • [ ] Нет возможности self-destruct без контроля
  • [ ] Тесты покрывают edge-кейсы

Использование OpenZeppelin

Не пишите всё с нуля. OpenZeppelin — проверенная библиотека контрактов:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract MyToken is ERC20, Ownable {
    constructor() ERC20("My Token", "MTK") Ownable(msg.sender) {
        _mint(msg.sender, 1000000 * 10 ** decimals());
    }

    function mint(address to, uint256 amount) public onlyOwner {
        _mint(to, amount);
    }
}

10 строк вместо 80 — и безопаснее, потому что код OpenZeppelin проверен аудиторами.

Что дальше

  1. Hardhat — профессиональная среда разработки (тесты, деплой-скрипты, отладка)
  2. Foundry — ещё быстрее, тесты на Solidity
  3. Ethers.js / Viem — взаимодействие с контрактами из JavaScript
  4. The Graph — индексация данных блокчейна
  5. OpenZeppelin Defender — мониторинг и управление контрактами

Ресурсы

  • solidity-by-example.org — примеры на каждую тему
  • docs.soliditylang.org — официальная документация
  • ethernaut.openzeppelin.com — CTF для изучения безопасности
  • speedrunethereum.com — практические челленджи

Хочешь изучить это глубже? Смотри наш курс — за неделю ты будешь писать и деплоить смарт-контракты профессионального уровня.

Понравилась статья?

Переходи от чтения к практике. 7-дневный челлендж — бесплатно.

Блог NEURO BRATVA — статьи про AI, вайбкодинг и заработок на ИИ