Розробка контрактів ескроу

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1306 послуг
Розробка контрактів ескроу
Середній
~2-3 дні
Часті запитання

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

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

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1308
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1221
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    921
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1149
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    612
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    886

Розробка контрактів еськроу

Еськроу-контракт виглядає просто: покласти гроші, виконати умову, забрати гроші. На практиці це один з найбільш аудируємих типів контрактів, тому що будь-яка помилка в логіці умов або правах виводу веде до прямої втрати коштів. Не до неправильного відображення балансу — до втрати ETH або токенів.

Дві головні точки відмови

Недостатньо жорсткі умови розблокування

Найпоширеніша помилка у еськроу-контрактах — неповна перевірка умов перед release(). Приклад: NFT маркетплейс з escrow для P2P-угод. Покупець депонує ETH, продавець має передати NFT. Контракт перевіряє ownerOf(tokenId) == address(this) перед release — то йсть що NFT знаходиться на контракті. Але не перевіряє, що це саме той NFT, який був заявлений у момент deposit().

Атака: продавець депонує дешевий NFT з тієї ж колекції (або взагалі інший контракт з збігаючим tokenId), контракт бачить NFT на своїй адресі та відправляє ETH. Втрата для покупця — різниця між заявленим та реальним NFT.

Правильна реалізація зберігає у маппінгу не просто флаг депозиту, а повний снімок угоди: адреса NFT-контракту, tokenId, очікуваний продавець, сума, дедлайн.

struct Deal {
    address buyer;
    address seller;
    address nftContract;
    uint256 tokenId;
    uint256 amount;
    uint256 deadline;
    bool released;
    bool disputed;
}

Проблема арбітражу та dispute-механізму

Простий двусторонній еськроу (покупець та продавець погоджуються на release) має очевидну проблему: якщо сторони не згідні, кошти заморожені назавжди. Або потрібен третій арбітр, або таймаут з логікою повернення.

Арбітр — окрема точка централізації та риску. Якщо арбітр — EOA, це single point of failure (втрата ключа). Якщо арбітр — контракт, потрібна governance. Якщо арбітр — multisig (Gnosis Safe), це прийнятний компроміс для більшості випадків.

Важна деталь: арбітр не повинен мати можливість примусово вивести кошти на довільну адресу. Права арбітра мають бути обмежені: або схвалити release покупцеві, або схвалити повернення продавцеві. Не більше.

Як ми будуємо еськроу-контракт

Базова структура

Три стани угоди: PENDING (кошти задепоновані, умова не виконана), COMPLETED (release виконаний), CANCELLED (повернення). Переходи між станами — строго через функції з перевірками. Ніякого прямого доступу до state ззовні.

Checks-effects-interactions скрізь без виключень. Це особливо важливо для ETH-еськроу: оновлюємо state (позначено як released) до відправки ETH, не після.

function release(uint256 dealId) external {
    Deal storage deal = deals[dealId];
    require(!deal.released, "Already released");
    require(msg.sender == deal.buyer || msg.sender == arbiter, "Unauthorized");
    
    deal.released = true; // Effects першим
    
    // Interactions останніми
    (bool success, ) = deal.seller.call{value: deal.amount}("");
    require(success, "Transfer failed");
    
    emit Released(dealId, deal.seller, deal.amount);
}

Робота з ERC-20 токенами

ETH-еськроу простіший: ETH не можна відозвати після deposit через approve(). З ERC-20 — інше. Якщо контракт тримає токени через transferFrom() у момент deposit — він фізично ними володіє, та approve-відозив після депозиту нічого не змінює. Це правильний паттерн.

Неправильний паттерн: контракт тільки записує allowance та робить transferFrom() у момент release. Між deposit та release покупець може відозвати approve(), та release() завершиться revert. Продавець виконав умову, але кошти не отримав.

Для fee-on-transfer токенів (USDT на деяких чейнах) рахуємо реально отриману суму: balanceBefore - balanceAfter, не довіряємо параметру amount у transferFrom().

Таймаути та дедлайни

Кожна угода повинна мати дедлайн. Без нього: продавець не виконує умову, покупець не може забрати гроші, кошти заморожені. Після закінчення дедлайну — автоматичний повернення покупцеві без необхідності згоди продавця.

Дедлайн перевіряємо через block.timestamp. Відома граблиця: block.timestamp може зміщуватись ±15 секунд на Ethereum. Для дедлайнів у днях це незначне, для дедлайнів у секундах — ні.

Reentrancy у еськроу

ETH-еськроу особливо уразливий до reentrancy через receive(). Використовуємо ReentrancyGuard з OpenZeppelin на функціях release() та refund(). Альтернатива — pull-паттерн: не відправляємо ETH напрямик, а записуємо у маппінг withdrawable[seller] += amount, продавець сам викликає withdraw(). Це повністю усуває reentrancy у release().

Підхід Reentrancy ризик UX
Push (пряма відправка) Є, потрібен ReentrancyGuard Автоматично
Pull (withdrawable маппінг) Відсутній Потребує окремої трансакції
Pull + permit Відсутній Gasless через підпис

Апгрейдність та багатоцільовий еськроу

Для маркетплейсів з великим обсягом угод має сенс фабричний паттерн: один EscrowFactory, який розгортає мінімальні proxies (EIP-1167) під кожну угоду. Це ізолює кошти різних угод у окремих контрактах та спрощує аудит.

Апгрейдність через Transparent Proxy або UUPS додає ризик: адміністратор може змінити логіку release() вже після депозиту. Для чесного еськроу апгрейдність має бути обмежена або виключена. Якщо апгрейдність потрібна для виправлення багів — використовуємо timelock (мінімум 48 годин) та multisig.

Строки

Базовий ETH/ERC-20 еськроу з арбітром та дедлайном: 2-3 робочих дні включаючи тести. NFT-еськроу з dispute-механізмом та фабричним паттерном: 4-6 робочих днів. Вартість розраховується індивідуально після уточнення вимог.