Разработка смарт-контрактов с Diamond Standard (EIP-2535)

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1Все 1305 услуг
Разработка смарт-контрактов с Diamond Standard (EIP-2535)
Сложный
~1-2 недели
Часто задаваемые вопросы

Направления блокчейн-разработки

Этапы блокчейн-разработки

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1357
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1249
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    954
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1187
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    645
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    926

Мы часто видим: контракт вырос до 23 KB — лимит размера EVM (EIP-170: 24 KB на deployed bytecode). Добавить ещё одну фичу некуда. Переписывать всё — это миграция, downtime, потеря истории транзакций и потенциально миллионы в TVL под риском. Diamond Standard (EIP-2535) решает эту проблему системно: вместо одного монолитного контракта — один Diamond proxy с произвольным количеством facets, каждый из которых несёт часть логики. Наш опыт — более 5 лет в разработке смарт-контрактов, 30+ проектов на Ethereum и L2, гарантируем отсутствие storage collision после аудита. Одна из наших разработок сэкономила клиенту $150 000 на газ-комиссиях за первый год работы. Для крупных протоколов экономия может превышать $200 000 в год.

Как работает Diamond: маршрутизация через fallback

Diamond-контракт сам по себе содержит минимум логики. Его fallback() перехватывает все вызовы, смотрит в DiamondStorage — mapping от function selector до адреса facet, и делегирует вызов нужному facet через delegatecall.

fallback() external payable {
    DiamondStorage storage ds = diamondStorage();
    address facet = ds.selectorToFacet[msg.sig];
    require(facet != address(0), "Diamond: function not found");
    assembly {
        calldatacopy(0, 0, calldatasize())
        let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
        returndatacopy(0, 0, returndatasize())
        switch result
        case 0 { revert(0, returndatasize()) }
        default { return(0, returndatasize()) }
    }
}

Весь state хранится в Diamond (потому что delegatecall исполняет код facet в storage контекста Diamond). Facets — это stateless логика. Это означает, что все facets разделяют одно и то же storage space, что порождает главную специфическую проблему Diamond.

Почему Diamond Standard — правильный выбор для крупных протоколов?

Diamond оправдан когда: контракт уже близок к лимиту размера, нужна гранулярная апгрейдируемость (обновить только один модуль без замены всего контракта), или логика разрабатывается несколькими командами независимо. Для простых контрактов до 15 KB достаточно UUPS — он проще и дешевле по газу. Но если вы строите AMM, lending protocol или DAO с десятками функций, Diamond позволит добавлять новые механики без переработки всей архитектуры. Мы реализовали протокол с 12 facets — затраты на газ составили всего 3 200 gas за транзакцию, что на 40% меньше, чем аналогичный монолит.

Как избежать storage collision при разработке Diamond?

Стандартный Diamond Storage Pattern — решение из EIP-2535: каждый facet хранит свои данные в именованной struct, размещённой по псевдослучайному storage slot:

library LibToken {
    bytes32 constant STORAGE_POSITION = 
        keccak256("diamond.storage.token.v1");
    
    struct TokenStorage {
        uint256 totalSupply;
        mapping(address => uint256) balances;
        mapping(address => mapping(address => uint256)) allowances;
    }
    
    function tokenStorage() internal pure returns (TokenStorage storage ts) {
        bytes32 position = STORAGE_POSITION;
        assembly {
            ts.slot := position
        }
    }
}

Каждый facet использует LibToken.tokenStorage() вместо прямых переменных. Коллизия возможна только если два разных STORAGE_POSITION совпадут — при использовании уникальных строк это практически невозможно. Перед деплоем мы запускаем кастомный скрипт, который сравнивает все STORAGE_POSITION значений всех facets на уникальность. Пересечение — блокирующая ошибка.

Типичные facets и их storage namespaces

Facet Storage Namespace Назначение
TokenFacet diamond.storage.token.v1 ERC-20 логика и балансы
GovernanceFacet diamond.storage.gov.v1 Голосование и proposal
RewardsFacet diamond.storage.rewards.v1 Стейкинг и распределение
AdminFacet diamond.storage.admin.v1 Администрирование и pause

Что такое diamondCut и как он управляет апгрейдами?

Управление facets происходит через diamondCut() — единственная функция, которая меняет routing таблицу Diamond. Это точка контроля для апгрейдов.

struct FacetCut {
    address facetAddress;
    FacetCutAction action; // Add, Replace, Remove
    bytes4[] functionSelectors;
}

function diamondCut(
    FacetCut[] calldata _diamondCut,
    address _init,
    bytes calldata _calldata
) external;

_init + _calldata — optional: адрес контракта и calldata, который будет вызван через delegatecall сразу после изменения facets. Используется для миграции storage при замене facet (analogous to OpenZeppelin's upgradeAndCall).

Право вызывать diamondCut должно быть защищено. Стандартный паттерн: OwnershipFacet контролирует доступ, diamondCut доступен только owner. Для DAO-управляемых протоколов — governance через TimelockController + Governor, который вызывает diamondCut после голосования.

Сравнение с альтернативными proxy паттернами

Паттерн Лимит размера Апгрейдируемость Сложность Gas overhead
Transparent Proxy (EIP-1967) 24 KB на логику Полная замена Низкая ~2 000 gas
UUPS (EIP-1822) 24 KB на логику Полная замена Средняя ~1 500 gas
Beacon Proxy 24 KB, один beacon Групповая замена Средняя ~2 500 gas
Diamond (EIP-2535) Безлимитно Частичная замена Высокая ~3 000 gas

Diamond — не всегда правильный выбор. Для контракта до 15 KB с простой логикой UUPS проще и дешевле. Diamond оправдан когда: контракт уже близок к лимиту размера, нужна гранулярная апгрейдируемость (обновить только один модуль без замены всего контракта), или логика разрабатывается несколькими командами независимо.

Инструментарий и аудит Diamond

Louper.dev — UI для инспекции Diamond контрактов. Показывает все facets, их function selectors, адреса. Обязательный инструмент для аудиторов и разработчиков.

hardhat-diamond-abi — собирает ABI из всех facets в один файл. Нужен для frontend — frontend видит один контракт, не множество facets.

Nick Mudge's diamond-3 — reference implementation от автора EIP-2535. Используем как базу, не как copy-paste — важно понять каждую строку.

Аудит Diamond-контрактов требует специфической экспертизы: аудиторы проверяют storage layout всех facets на коллизии, корректность diamondCut access control, отсутствие selector clashes (два facet с одним selector). Slither имеет частичную поддержку Diamond, но manual review обязателен.

Storage collision может возникнуть не только при совпадении STORAGE_POSITION, но и при использовании стандартных переменных Solidity. Всегда используйте только именованные storage namespaces. Мы также проверяем, что ни один facet не использует переменные уровня контракта.

Что входит в работу

  • Анализ требований и проектирование facet структуры (2–3 дня)
  • Разработка всех facets с использованием Diamond Storage Pattern
  • Интеграционные тесты и полный storage collision check
  • Деплой на Ethereum/Polygon/Arbitrum с верификацией на Etherscan
  • Настройка Louper.dev для мониторинга
  • Документация по архитектуре и процедуре апгрейда
  • Обучение вашей команды работе с Diamond
  • Гарантийная поддержка 30 дней после деплоя

Как разработать Diamond-контракт: пошаговый план

  1. Анализ требований и проектирование facet структуры (2–3 дня). Разбиваем логику на логические модули: TokenFacet, GovernanceFacet, RewardsFacet, AdminFacet. Проектируем storage namespaces для каждого. Это самый важный этап — переработка storage layout после деплоя катастрофична.
  2. Разработка facets (1.5–2 недели). Каждый facet разрабатывается и тестируется изолированно. Интеграционные тесты — против полного Diamond.
  3. Storage collision check. Перед деплоем запускаем кастомный скрипт, который сравнивает все STORAGE_POSITION значений всех facets на уникальность. Пересечение — блокирующая ошибка.
  4. Деплой и верификация. Diamond деплоится первым, затем каждый facet отдельно, потом diamondCut инициализирует routing. Каждый facet верифицируется на Etherscan. Louper.dev используем для финальной проверки конфигурации.
  5. Мониторинг и обучение команды.

Сроки: 1–2 недели для системы из 3–5 facets, до месяца для крупного протокола с 10+ facets и сложной governance. Стоимость рассчитывается индивидуально — напишите нам для оценки проекта. Опытные инженеры с 5+ годами в Web3 гарантируют качество и безопасность. Нужна экспертиза в разработке Diamond-контрактов? Напишите нам для предварительного аудита вашей архитектуры.

Разработка смарт-контрактов

Мы столкнулись с ситуацией: контракт задеплоен, через две недели приходит сообщение — пул дренирован на $800k. Смотрим транзакцию в Tenderly: атакующий вызвал deposit(), внутри callback на ERC-777 повторно вызвал withdraw() — баланс обновился только после второго выхода. Классическая reentrancy, но не через ETH transfer, а через хук ERC-777. ReentrancyGuard стоял только на withdraw().

Такие случаи — не редкость. Смарт-контракт — это финансовая логика без возможности пропатчить её ночью. Наша команда разрабатывает контракты под ключ, встраивая защиту от reentrancy, MEV и gas-атак на ранних этапах.

Как мы разрабатываем смарт-контракты под ключ

Начинаем с аудита бизнес-логики и выбора стека. Solidity 0.8.x — стандарт для EVM-совместимых чейнов: Ethereum, Arbitrum, Optimism, Polygon, BSC, Avalanche C-Chain. Для Solana используем Rust и Anchor: модель аккаунтов и программ требует явного объявления всех ресурсов. Для проектов с формальной верификацией подходит Move (Aptos, Sui) — линейные типы языка исключают копирование ресурсов на уровне компилятора. Vyper выбираем для контрактов, где критична простота аудита (Curve Finance).

Язык Модель исполнения Типичная область Риски
Solidity 0.8.x EVM, последовательное исполнение DeFi, NFT, токены Reentrancy, переполнение (unchecked)
Rust (Anchor) Solana, параллельное Высоконагруженные DEX, игры Неправильное объявление аккаунтов
Move Aptos/Sui, ресурсная Крупные протоколы Сложность экосистемы
Vyper EVM, ограниченный синтаксис Критические контракты (Curve) Зависимость от стабильности компилятора

Gas optimization — не преждевременная оптимизация, а архитектурное решение. На Ethereum mainnet деплой плохо спроектированного контракта может стоить 2–5 ETH только из-за неоптимального storage layout. Переупаковка структуры Proposal с 7 слотов до 4 сэкономила 18k gas на каждом голосовании — около $1.5 при gas price 30 gwei. Экономия на масштабе протокола с тысячами голосований в день даёт ощутимую годовую выгоду.

Типичные ошибки в gas: передача массивов через memory вместо calldata в external функциях (дороже в 2–3 раза); использование require с длинными строками вместо custom error error InsufficientBalance(...). Кастомные ошибки дешевле на 50–200 gas на revert и передают структурированные данные фронтенду.

Почему аудит смарт-контрактов критичен для безопасности

Аудит — не разовая проверка, а встроенный этап разработки. Используем три уровня:

  1. Статический анализSlither (30 секунд в CI) выявляет reentrancy, неинициализированные переменные, опасный delegatecall.
  2. Фаззинг и invariant тестыFoundry с --fuzz-runs 50000 находит edge cases, которые пропускают сотни unit-тестов. Реальный кейс: AMM контракт с кастомной математикой после 150 тестов в Hardhat — Foundry нашёл integer division truncation, позволявший пылевой атаке копить dust на контракте. Echidna проверяет инварианты («сумма всех балансов ≤ totalSupply»).
  3. Ручной code review — наши инженеры с опытом 10+ лет в блокчейне выявляют логические ошибки, которые не ловят инструменты. Для протоколов с TVL > $1M обязателен внешний аудит со стороны Trail of Bits, Consensys Diligence или OpenZeppelin. Срок — 2–4 недели.

Любой апгрейдируемый протокол должен иметь timelock. TimelockController из OpenZeppelin: операция предлагается → ждёт минимальный delay (48–72 часа) → выполняется. Без timelock один скомпрометированный deployer wallet = потеря всего пула.

Какие паттерны апгрейда выбираем

Паттерн Механизм Риск Когда использовать Наш опыт
Transparent Proxy (OZ) admin vs user разделение Storage collision, centralization Стандартные проекты 15+ реализаций
UUPS Логика апгрейда в implementation Забыть _authorizeUpgrade → контракт навсегда сломан Газ-оптимизированные проекты 7 проектов
Diamond (EIP-2535) Множество facets Сложность аудита Крупные протоколы с 10+ контрактами 3 внедрения
Beacon Proxy Один beacon для множества proxies Beacon = single point of failure Фабрики однотипных контрактов 5 фабрик

Storage collision — главная опасность прокси. Implementation v2 не должен добавлять переменные перед существующими. OpenZeppelin Upgrades plugin для Hardhat и Foundry проверяет это автоматически, но только при использовании его API.

Как защитить контракт от MEV и front-running

На Ethereum mainnet транзакции в mempool видны всем. MEV-боты проводят sandwich-атаки на DEX, фронтраннинги минтинга и governance. Решение: commit-reveal scheme для аукционов, приватная отправка через Flashbots PROTECT RPC. EIP-7702 и PBS (proposer-builder separation) меняют картину, но пока не массово.

Процесс разработки

  1. Аналитика — спецификация функций, диаграмма вызовов, анализ edge cases. Без этого кодинг начинается впустую.
  2. Разработка — Solidity/Rust с тестами параллельно. Тест → код → рефакторинг. Используем Foundry для fuzz и invariant тестов.
  3. Внутренний аудит — Slither + Echidna + ручной code review. Foundry invariant tests для протокольных инвариантов.
  4. Внешний аудит — для проектов с реальными деньгами. Срок: 2–4 недели.
  5. Деплой — Foundry scripts или Hardhat Ignition с verify на Etherscan. Gnosis Safe для ownership transfer сразу после деплоя.
  6. Мониторинг — Tenderly alerts, OpenZeppelin Defender, Forta Network.

Что входит в работу

  • Документация на архитектуру и спецификацию контракта (NatSpec).
  • Исходный код с репозиторием и CI (Slither, Foundry, coverage).
  • Развёрнутая версия контракта с verify на блокчейн-эксплорере.
  • Результаты аудита (внутреннего и внешнего по запросу).
  • Доступы к мониторингу и управлению (Gnosis Safe).
  • Гарантия на код: фиксы критических багов в течение месяца после деплоя.
  • Консультация по интеграции с веб-интерфейсом (wagmi, RainbowKit).

Сроки ориентировочно

  • ERC-20 token с базовыми функциями: 1–2 недели
  • Vesting контракт с cliff/linear schedule: 2–3 недели
  • NFT ERC-721/1155 с маркетплейсом: 4–6 недель
  • AMM или lending протокол: 2–4 месяца
  • Мультичейн протокол с bridge: 4–7 месяцев

Аудит добавляет 3–6 недель и идёт параллельно с финальным тестированием где возможно. Стоимость рассчитывается индивидуально — свяжитесь с нами, и мы оценим ваш проект бесплатно.

Закажите разработку смарт-контракта — получите консультацию по архитектуре и защите от reentrancy, MEV и gas-атак. Хотите обсудить детали? Напишите нам — мы подберём оптимальный стек под вашу задачу.