Мой опыт создания сабграфа

Vilagra
5 min readDec 20, 2020

Попытаюсь рассказать о своем опыте создания собственного сабграфа, чему я научился и что понял в момент создания.

Начнем с того, что я разработчик на Android OS, и до создания своего сабграфа был не сильно знаком с языком Solidity, на котором написаны смарт-контракты Ethereum, также языком TypeScript, на котором пишутся мепперы для сабграфов, и так же до этого не использовал GraphQl для создания сабграфов, поэтому заранее прошу прощения за неточности, если такие будут.

В этой статье не буду пересказывать официальную документацию про построение сабграфов, с которой вы можете ознакомиться здесь. Попытаюсь сосредоточиться на своем опыте, и что я узнал в процессе.

Для начала я стянул пример проекта, который уже содержит основные папки и файлы, как это сделать — описано здесь.

У меня была идея создать сабграф для проекта DODO DEX(exchange and liquidity provide), так как в процессе исследования уже созданных сабграфов для данного проекта, я обнаружил, что они создают отдельный сабграф для каждой пары, не используя все возможности, которые предоставляет граф-протокол.

Я решил попробовать слушать основные события из основного контракта фабрики и при создании новой пары добавлять новый контракт динамически используя шаблоны.

Теперь более подробно, я нашел все смарт-контракты для проекта DODO в их документации. Основной их контракт DODO Zoo, я зашел в Etherscan в секцию abi, скопировал его файл Zoo.json в папку abi, он понадобится нам в дальнейшем.

В смарт-контрактах нас в основном интересуют эвенты, которые данный контракт умеет отправлять, это основной источник информации для сабграфов. У данного контракта есть один основной event DODOBirth , код из смарт контракта:

который вызывается каждый раз после создания новой пары, и мы будем отслеживать его при создании сабграфа.

Дальше настраиваю манифест используя эти данные

Address — адрес контракта нашей фабрики

StartBlock — номер блока создания смарт контракта (обычно номер блока можно узнать по первой транзакции в этом контракте), можно не указывать, тогда синхронизация начнется с самого первого блока.

abi: abi этого контракта, которое мы скопировали в соответствующий файл.

abis: указываем имя и путь к нашему Zoo abi, также вы можете видеть три других abi, это вспомогательные abi, которые я добавил для того, чтобы извлекать информацию о токенах, в этой статье мы не будем это затрагивать.

eventHandlers: event, который мы отслеживаем из контракта, вместе с его параметрами, которые мы можем посмотреть в смарт-контракте и handler — обработчик для этого эвента, о котором я расскажу чуть позже, и путь к файлу, где мы прописали обработчик.

Далее в файле schema.graphql создал сущности DODOPair и Token (на скриншоте пример сущности токена)

Дальше создаю file main.ts в паке src, код которого выглядит приблизительно так:

Tут код пишем на TypeScript. Поскольку я работал с Java и другими объектно-ориентированными языками, мне было интуитивно понятно, иногда я подсматривал в туториалы, если вам будет не все непонятно, что тут происходит, советую посмотреть какие-то базовые уроки по TypeScript, думаю для построения сабграфа этого будет достаточно.

Ocновные момент, на который хотел бы обратить ваше внимание, сверху импортируем сущности, которые мы будем создавать (сущности из схемы) и получать (events) с сети Ethereum. Итак, я импортировал event DODOBirth, и он является входным параметром в нашу функцию-обработчик handleDododBirth, и наш метод будет отрабатывать каждый раз, когда когда в блокчейне Ethereum произойдет данный evet. Дальше у event мы можем получить параметры, делается это через event.params. В моем случае я могу получить адреса base токена и quote token, и на основе них создать объекты токена, которые я объявил в схеме. Так же обратите внимание на let mainStatistic = MainStatistic.load(FACTORY_ADDRESS). Мы пытаемся получить такую сущность по адресу, если она существует — мы ее получим, если же нет, то она будет null, мы делаем проверку, и если она null, то создаем новый объект, используя оператор new. На этом первая часть закончена.

Шаблоны

Как я говорил выше, контракт-фабрика создает другие контракты (контракты пар), которые, по сути, имеют одинаковый код, и, чтобы не прописывать каждый такой контракт в манифесте, мы можем использовать data source templates для динамически создаваемых контрактов.

Нам достаточно подгрузить abi одного из таких контрактов и создать в папке abi еще один файл (в моем случае это dodopair.ts) и вставить туда abi.

Дальше обновляем манифест

Добавляем шаблон, указываем abi для этого шаблона, файл, где мы объявили маппер для эвентов из данного контракта, путь к аби и, соответственно, эвенты (в моем сабграфе я обрабатываю еще и функции, но их может и не быть) и их функции-хендлеры (имя хендлера и функции в маппере должны совпадать, иначе мы получим ошибку на этапе компиляции).

Важный момент: при обработке DODOBirth в маппере для фабрики одной из строчек идет DODOPairTemplate.create(event.params.newBorn), эта строчка как раз берет адрес вновь созданного контракта и создает source на основе шаблона.

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

В принципе, этого может быть достаточно для того, чтобы попробовать задеплоить свой сабграф, а потом постепенно добавлять больше сущностей и усложнять их структуру.

Думаю, этого достаточно в рамках этого материала, вышло, наверное, очень сумбурно и запутанно, извините — у меня небольшой опыт в написании статей и сабграфов. Если что, задавайте вопросы, буду рад ответить. Надеюсь, этот материал был кому-то полезен.

С полным кодом моего сабграфа вы можете ознакомиться по ссылке.

--

--