Створення subgraph The Graph: проектування, деплой та оптимізація

Ми часто стикаємося з проблемою: смарт-контракти не зберігають історію стану у зручному для запитів вигляді. `eth_getLogs` з фільтром за подіями — це грубий інструмент: немає сортування, немає агрегації, немає зв'язків між подіями різних контрактів. В результаті фронтенд або тягне тонни даних і обро

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

Часті запитання

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

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

Ми часто стикаємося з проблемою: смарт-контракти не зберігають історію стану у зручному для запитів вигляді. eth_getLogs з фільтром за подіями — це грубий інструмент: немає сортування, немає агрегації, немає зв'язків між подіями різних контрактів. В результаті фронтенд або тягне тонни даних і обробляє їх на клієнті, або команда піднімає власний індексуючий бекенд. The Graph вирішує це завдання стандартним способом — ви описуєте, що індексувати, а мережа робить це за вас. Наша команда розробила понад 20 subgraph для DeFi-протоколів та NFT-маркетплейсів, накопичивши досвід в оптимізації та налагодженні. Отримайте консультацію щодо вашого проєкту — допоможемо спроєктувати схему та вибрати стек.

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

Як оптимізувати schema для GraphQL-запитів?

Схема повинна проєктуватися виходячи з того, які запити потрібні фронтенду — не зі структури подій контракту. Типова помилка: робити entities один-до-одному з подіями. Це веде до того, що фронтенд робить N+1 запитів. Денормалізовані entities з предагрегованими даними скорочують кількість запитів у 3–5 разів.

Правильний підхід — денормалізовані entities з предагрегованими даними:

type Pool @entity { id: ID! # address пула token0: Token! token1: Token! feeTier: BigInt! totalVolumeUSD: BigDecimal! # накопичувальний обсяг — оновлюємо в кожному Swap totalValueLockedUSD: BigDecimal! txCount: BigInt! swaps: [Swap!]! @derivedFrom(field: "pool") } type Swap @entity { id: ID! # txHash + logIndex pool: Pool! sender: Bytes! recipient: Bytes! amount0: BigDecimal! amount1: BigDecimal! amountUSD: BigDecimal! timestamp: BigInt! blockNumber: BigInt! } 

@derivedFrom — віртуальний зв'язок, не зберігає масив ID в записі Pool. Це важливо для продуктивності: пул з тисячами свапів не буде рости в розмірі запису. Приклад запиту, який фронтенд може виконувати:

{ pools(first: 10) { id totalVolumeUSD swaps(first: 5) { amountUSD timestamp } } } 

Чому AssemblyScript небезпечний для розробників TypeScript?

AssemblyScript — строго типізована мова, компілюється в WebAssembly. Звички з TypeScript тут небезпечні:

// НЕПРАВИЛЬНО — null reference в AS викликає паніку let pool = Pool.load(event.address.toHexString()) pool.txCount = pool.txCount.plus(BigInt.fromI32(1)) // pool може бути null // ПРАВИЛЬНО let poolId = event.address.toHexString() let pool = Pool.load(poolId) if (pool === null) { pool = new Pool(poolId) pool.txCount = BigInt.fromI32(0) pool.totalVolumeUSD = BigDecimal.fromString("0") } pool.txCount = pool.txCount.plus(BigInt.fromI32(1)) pool.save() 

BigDecimal для фінансових значень — обов'язково. BigInt з контракту потрібно конвертувати з урахуванням decimals токена:

function convertTokenToDecimal(tokenAmount: BigInt, exchangeDecimals: BigInt): BigDecimal { if (exchangeDecimals == BigInt.fromI32(0)) { return tokenAmount.toBigDecimal() } return tokenAmount.toBigDecimal().div( BigInt.fromI32(10).pow(exchangeDecimals.toI32() as u8).toBigDecimal() ) } 

Як налагодити повільну синхронізацію?

Якщо subgraph синхронізується повільніше очікуваного, виконайте перевірку:

  1. Порахуйте кількість callHandlers — замініть на eventHandlers де можливо. eventHandlers в 5–10 разів швидші.
  2. Переконайтеся, що startBlock не занадто ранній. Ідеально — блок деплою контракту.
  3. Перевірте кількість eth_call в handlers — кожен виклик контракту з мапінгу додає RPC-запит.
  4. Використовуйте ipfs.cat мінімально — це повільна операція.
Тип обробника Швидкість Застосування
eventHandlers Швидко (2000–5000 блоків/хв) Будь-які події, емітовані контрактом
callHandlers Повільно (в 5–10 разів повільніше) Якщо контракт не емітує подій
blockHandlers Дуже повільно Тільки коли немає альтернативи, з filter: { kind: once }

Типові помилки в обробниках:

  • Забувають перевірити null перед Pool.load
  • Вказують startBlock = 0
  • Використовують callHandlers замість eventHandlers там, де можна навпаки
  • Не конвертують BigInt в BigDecimal з урахуванням decimals

Як вибрати між Hosted Service та Decentralized Network?

Для production протоколів рекомендується децентралізована мережа: вона забезпечує censorship resistance та стійкість до відключення. Hosted Service безкоштовний, але підходить тільки для розробки та тестування. Порівняння:

Hosted Service Decentralized Network
Вартість Безкоштовно (сервіс закривається) GRT токени (Indexer fees)
Latency Низька Вище (~100–500ms)
Censorship resistance Ні (centralized) Так
SLA Без гарантій Залежить від Indexers
Підходить для Розробка, тестування Production з вимогою decentralization

Для деплою в децентралізовану мережу використовуйте Graph Studio:

graph auth --studio <deploy-key> graph codegen && graph build graph deploy --studio <subgraph-name> 

Детальніше про архітектуру можна прочитати в документації The Graph. Зв'яжіться з нами для консультації з вибору мережі та оптимізації схеми.

Процес розробки subgraph: етапи та терміни

Ми працюємо за наступною схемою:

  1. Аналіз ABI контрактів та визначення списку подій і викликів для індексації.
  2. Проектування GraphQL-схеми під конкретні запити фронтенду (з акцентом на денормалізацію).
  3. Написання AssemblyScript-обробників з урахуванням обробки null, конвертації BigInt та оптимізації продуктивності.
  4. Локальне тестування за допомогою graph-cli та дебагінг повільних місць.
  5. Деплой у вибрану мережу та налаштування моніторингу синхронізації.

Терміни залежать від складності контрактів та кількості сутностей: від 3 до 10 робочих днів. Вартість розраховується індивідуально після аналізу вашого проєкту.

Що входить у нашу роботу з розробки subgraph

  • Аналіз ABI контрактів та визначення потрібних events/calls
  • Проектування schema під конкретні запити фронтенду
  • Написання та тестування AssemblyScript handlers
  • Оптимізація продуктивності (економія до 40% на RPC-запитах за рахунок денормалізації)
  • Деплой та моніторинг синхронізації
  • Документація GraphQL endpoints та приклади запитів

Наша команда має багаторічний досвід у розробці блокчейн-рішень, понад 30 успішних проектів на Ethereum, Polygon, BNB Chain, Solana. Замовте розробку subgraph у професіоналів та отримайте швидку індексацію без компромісів.