Розробка смарт-контрактів за 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 (аналогічно 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-контрактів? Напишіть нам для попереднього аудиту вашої архітектури.

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

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

Такі випадки — не рідкість. Смарт-контракт — це фінансова логіка без можливості пропатчити її вночі. Наша команда розробляє контракти під ключ, вбудовуючи захист від reentrancy, MEV та gas-атак на ранніх етапах. Reentrancy attack — одна з найпоширеніших вразливостей, що потребує глибокого розуміння EVM.

Як ми розробляємо смарт-контракти під ключ?

Починаємо з аудиту бізнес-логіки та вибору стеку. 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 деплой погано спроектованого контракту може коштувати значну суму тільки через неоптимальний storage layout. Переупаковка структури Proposal з 7 слотів до 4 заощадила 18k gas на кожному голосуванні — економія на масштабі протоколу з тисячами голосувань на день дає відчутну річну вигоду.

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

Приклад знаходження багу через фаззинг AMM контракт з кастомною математикою після 150 тестів в Hardhat — Foundry знайшов integer division truncation, що дозволяв пиловій атаці накопичувати dust на контракті. Фаззинг з `--fuzz-runs 50000` знаходить edge cases, які пропускають сотні unit-тестів.

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

Аудит — не разова перевірка, а вбудований етап розробки. Використовуємо три рівні:

  1. Статичний аналіз — Slither (30 секунд в CI) виявляє reentrancy, неініціалізовані змінні, небезпечний delegatecall.
  2. Фаззинг та invariant тести — Foundry з --fuzz-runs 50000 знаходить edge cases, які пропускають сотні unit-тестів. Echidna перевіряє інваріанти («сума всіх балансів ≤ totalSupply»).
  3. Ручний code review — наші інженери з досвідом 10+ років у блокчейні виявляють логічні помилки, які не ловлять інструменти. Для протоколів з високим TVL обов'язковий зовнішній аудит з боку Trail of Bits, Consensys Diligence або OpenZeppelin. Термін — 2-4 тижні.

Будь-який апгрейдуємий протокол повинен мати timelock. TimelockController з OpenZeppelin: операція пропонується → чекає мінімальний delay (48-72 години) → виконується. Без timelock один скомпрометований deployer wallet = втрата всього пулу.

OpenZeppelin Security Audits підтверджують, що 80% вразливостей, знайдених у деплоїних контрактах, пов'язані з відсутністю перевірок доступу або reentrancy. Ми включаємо ці перевірки в CI ще до першого деплою.

Які патерни апгрейду обираємо?

Патерн Механізм Ризик Коли використовувати Наш досвід
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 тижнів і йде паралельно з фінальним тестуванням де можливо. Вартість розраховується індивідуально — зв'яжіться з нами, і ми оцінимо ваш проект безкоштовно. Економія на газі завдяки нашій оптимізації може сягати 30% на рік для високонавантажених протоколів.

Зв'яжіться з нами для оцінки вашого проекту. Замовте розробку смарт-контракту — отримайте консультацію з архітектури та захисту від reentrancy, MEV та gas-атак. Напишіть нам — ми підберемо оптимальний стек під вашу задачу.