<100 subscribers
Share Dialog
Share Dialog


Source - link
Ласкаво просимо до першого випуску блогу The Graph Builders! The Graph Builders Blog - це місце, де розробники можуть збиратися разом, вчитися один у одного та ділитися своїми знаннями з усією спільнотою The Graph. Щоб дізнатися більше та подати заявку на участь у блозі, перейдіть до кінця цієї статті.
Цей допис належить Denver Baumgartner з Rubicon. Ознайомтеся з прикладами підграфів у цій статті в репозиторії Rubicon на GitHub.
У цій статті я представлю концепцію подійно-орієнтованої розробки (EDD), яка може покращити розробку смарт-контрактів і підграфів при використанні The Graph.
Але перш ніж ми заглибимось в це поняття, розглянемо деякі основи.
Що таке event, та як відбувається його обробка у підграфах?
У Solidity event (подія) - це механізм реєстрації та сповіщення блокчейну Ethereum і його користувачів про певну дію в смарт-контракті. Коли смарт-контракт генерує подію, він створює повідомлення, яке зберігається в блокчейні. Зовнішні додатки можуть отримувати доступ до цих журналів і дізнаватися більше про них , що робить EDD зручним способом повідомляти про зміни стану і запускати відповідні дії. Ethers.js, одна з найпоширеніших бібліотек web3, дозволяє створювати фільтри подій (тільки для індексованих параметрів) саме для цієї мети. Ви можете ознайомитися з документацією тут. Підграфи, використовують eventHandlers для обробки цих подій у зіставленнях підграфів.
Події визначаються за допомогою ключового слова event, за яким слідує її назва та визначення в дужках. Нижче наведений приклад визначення події та функції, яка її викликає:
pragma solidity ^0.8.9;
/// @notice Events contract for logging trade activity on Rubicon Market
/// @dev Provides the key event logs that are used in all core functionality of exchanging on the Rubicon Market
contract EventfulMarket {
// Define the event
event RecordOffer(
bytes32 indexed id,
bytes32 indexed pair,
address indexed maker,
ERC20 pay_gem,
ERC20 buy_gem,
uint128 pay_amt,
uint128 buy_amt
);
...
/// @notice Key function to make a new offer. Takes funds from the caller into market escrow.
function offer(
uint256 pay_amt,
ERC20 pay_gem,
uint256 buy_amt,
ERC20 buy_gem,
address owner,
address recipient
) public virtual can_offer synchronized returns (uint256 id) {
require(uint128(pay_amt) == pay_amt);
require(uint128(buy_amt) == buy_amt);
require(pay_amt > 0);
require(pay_gem != ERC20(address(0)));
require(buy_amt > 0);
require(buy_gem != ERC20(address(0)));
require(pay_gem != buy_gem);
OfferInfo memory info;
info.pay_amt = pay_amt;
info.pay_gem = pay_gem;
info.buy_amt = buy_amt;
info.buy_gem = buy_gem;
info.recipient = recipient;
info.owner = owner;
info.timestamp = uint64(block.timestamp);
id = _next_id();
offers[id] = info;
require(pay_gem.transferFrom(msg.sender, address(this), pay_amt));
emit LogItemUpdate(id);
emit RecordOffer(
bytes32(id),
keccak256(abi.encodePacked(pay_gem, buy_gem)),
msg.sender,
pay_gem,
buy_gem,
uint128(pay_amt),
uint128(buy_amt)
);
}
}
У цьому прикладі ми пояснюємо визначення події RecordOffer з відповідними параметрами для нашого підграфа:
id: унікальний id пропозиції
pair: торгова пара для пропозиції (тобто ETH-USDC)
maker: адреса, з якої було зроблено пропозицію
pay_gem: актив, який продає (або оплачує) пропозицію
buy_gem: актив, який купує пропозицію
pay_amt: сума, яку потрібно сплатити (або продати)
buy_amt: кількість, яку потрібно купити
співвідношення pay_amt / buy_amt визначає ціну пропозиції
Функція offer (пропозиція) дозволяє користувачеві створити пропозицію, вказавши актив, який він хотів би продати, актив, який він хотів би отримати натомість, і суму кожного активу відповідно (що визначає "ціну" цієї пропозиції). Після успішного використання функції пропозиції транслюється подія RecordOffer з відповідною інформацією щодо самої пропозиції. Це дозволяє нам індексувати відповідну інформацію пропозиції без виклику стану всередині мережі, підвищуючи ефективність індексації та зменшуючи витрати на ресурси.
The Graph має чудовий набір інструментів для автоматизації генерування коду, необхідного для обробки подій під час індексування, а саме codegen. Існує безліч ресурсів з розробки підграфів, доступних у документації The Graph, які я рекомендую переглянути, якщо ви хочете дізнатися більше про розробку підграфів з практичної точки зору.
Говорячи про мету цієї статті,все, що вам потрібно знати, це те, що codegen використовує бінарний інтерфейс додатку договору (ABI) і створює класи для подій, до яких ви можете отримати доступ у відображеннях, приклад якого наведено нижче:
export class RecordOffer extends ethereum.Event {
get params(): RecordOffer__Params {
return new RecordOffer__Params(this);
}
}
export class RecordOffer__Params {
_event: RecordOffer;
constructor(event: RecordOffer) {
this._event = event;
}
get id(): Bytes {
return this._event.parameters[0].value.toBytes();
}
get pair(): Bytes {
return this._event.parameters[1].value.toBytes();
}
get maker(): Address {
return this._event.parameters[2].value.toAddress();
}
get pay_gem(): Address {
return this._event.parameters[3].value.toAddress();
}
get buy_gem(): Address {
return this._event.parameters[4].value.toAddress();
}
get pay_amt(): BigInt {
return this._event.parameters[5].value.toBigInt();
}
get buy_amt(): BigInt {
return this._event.parameters[6].value.toBigInt();
}
}
Для ознайомлення, ми швидко розглянули.
Тепер, коли ви розумієте ці основи, давайте познайомимося з подійно-орієнтованою розробкою!
Що таке подійно-орієнтована розробка (EDD)?
Подійно-орієнтована розробка (EDD) - це стратегія розробки, яка базується на створенні смарт-контрактів з великою кількістю даних для децентралізованих додатків . Вона закладає основу подій для смарт-контрактів з урахуванням кінцевого застосування або варіанту використання, що, в свою чергу, допомагає ефективно надавати користувачам як поточні, так і історичні дані.
Одним з ключових принципів EDD є забезпечення того, щоб смарт-контракти генерували багаті та відповідні події. Цей підхід є невід'ємною частиною побудови надійного фундаменту для вашого додатку він допоможе оптимізувати процес індексації та запитів. Ця оптимізація значно покращує роботу зовнішнього інтерфейсу та загалом досвід використання, сприяючи масштабованості та зручності вашого додатку.
Акцент на смарт-контрактах, багатих на події, допомагає створити багате на дані середовище, сприятливе для створення та масштабування децентралізованих додатків і підграфів. Давайте розглянемо, як ця проста концепція може мати каскадний ефект для подальшого розвитку вашого децентралізованого додатку.
Переваги EDD
Покращене планування децентралізованого додатку: Критично обмірковуючи конкретні події, дані, які вони містять, і час, в який вони генеруються, перед написанням зовнішнього інтерфейсу вашого децентралізованого додатка, ви не витрачаєте час на рефакторинг і можете більш впевнено планувати взаємодію з користувачем.
Масштабованість та адаптивність: EDD вигідна для оптимізації підграфів, оскільки підграфи набагато швидше індексують події за допомогою eventHandlers, а не callHandlers або blockHandlers. Якщо ваш додаток потребує масштабування, то написання смарт-контрактів таким чином, щоб кожен ключовий момент генерував подію з усіма відповідними метаданими, дозволить вашому підграфу масштабуватися, відповідаючи вашим вимогам до даних.
Зручність обслуговування: Модульна структура EDD спрощує обслуговування та усунення несправностей коду. Організовуючи кодову базу навколо подій, розробники можуть легше виявляти і вирішувати проблеми, скорочуючи час і зусилля, необхідні для усунення несправностей.
Покращена взаємодія: Розглянемо декілька смарт-контрактів з декількома підграфами, які в даний час індексують дані смарт-контрактів, кожен з яких має власні відображення та схеми. Така ситуація може швидко стати переважаючою, якщо стратегія не буде розглянута на ранній стадії розробки. Включення EDD в процес роботи робить події ключовим фокусом для обговорення та оптимізації між командою смарт-контрактів і командою підграфів.
Ще однією важливою перевагою EDD є вартість.
На практиці наша команда змогла значно зменшити витрати на підтримку додатків виробничого рівня, різко скоротивши використання RPC в додатках. Наприклад, ви можете перейти від 1000 користувачів, які здійснюють один RPC-виклик для отримання поточного балансу пулу, до 1000 викликів GraphQL до сервера PostgreSQL. Крім того, цей PostgreSQL можна налаштувати під ваш конкретний підграф. Шардинг, оптимізація для кеш-зв'язків і безліч інших дій індексатора - це окрема тема для окремого посту.
Загалом, варто масштабувати протокол, звертаючи увагу на підграфи.
Використання EDD зі смарт-контрактами
Тепер, коли ви розумієте, що таке EDD, давайте розглянемо, як ми використовуємо EDD в Rubicon Finance, починаючи з наших смарт-контрактів.
Щоб включити в наші смарт-контракти підхід, який базується на EDD, ми почали з інтерфейсу нашого додатку і працювали в зворотному напрямку вниз по стеку.
В контексті подій і функцій, описаних вище, ми знаємо, що користувачі захочуть не тільки розміщувати пропозиції, а й бачити минулі пропозиції і статус інших пропозицій. Тому в наших контрактах, коли відбувається оновлення пропозиції (хтось здійснює торгівлю з автором пропозиції, автор пропозиції скасовує пропозицію або пропозиція збігається з іншою пропозицією), ми слідкуємо за тим, щоб вся відповідна інформація про зміну стану цієї пропозиції була опублікована як подія.
Визначаючи ці події заздалегідь, ми можемо використовувати EDD для планування всього потоку даних нашого додатку під час створення самих смарт-контрактів.
З точки зору схеми, ми можемо створити багато важливих структур даних, які можуть керувати різними компонентами програми. Чудовим прикладом цього є дані для свічкової діаграми:

Оскільки наші контракти передають дані по мірі того, як відбувається торгівля, ми можемо в реальному часі оновлювати вигляд діаграми, шляхом відображення цих подій на об’єктах в наших підграфах!
Звідси наш децентралізований додаток може використовувати live-polling в реальному часі через graph-client, щоб відслідковувати оновлення певних об'єктів підграфів, таких як остання свічкова діаграма, і відповідно оновлювати інтерфейс! Це неймовірно ефективний спосіб для отримання та відображення даних з мережі. Ви зможете не тільки реагувати на події, щойно вони відбудуться, але й зможете уникнути необхідності запускати або платити за ноди для отримання даних.
Якщо ви ще не використовували graph-client, я рекомендую вам це зробити. Існує безліч корисних конфігурацій, таких як шаблони резервного копіювання, які дозволяють керувати мережею підграфів та індексаторів, щоб забезпечити користувачам безперебійну роботу з високим рівнем доступності.
Події також дозволяють відтворити поточний стан смарт-контрактів у ваших відображеннях підграфів і можуть допомогти в історичному аналізі, коли ви хочете перевірити стан контракту в певному блоці в часі. Прикладом цього є відстеження балансу користувача в пулі ліквідності Rubicon. Якщо ми знаємо про кожен депозит, зняття коштів і переказ, які відбулися, ми можемо визначити баланс користувача в будь-який момент часу. Запити з можливістю переміщення в часі корисні для цього, але вони позбавляють можливості вилучати підграфи, що може підвищити продуктивність при масштабуванні (особливо, якщо об’єкти оновлюються, якщо ні, то зробити їх незмінними). На практиці ми виявили, що корисно розподіляти різні потреби додатків між кількома підграфами.
Загалом, ми виявили, що найкраще дотримуватися процесу розробки, який виглядає наступним чином:
Вирішити, як повинен виглядати користувацький інтерфейс додатку, і яким буде його використання, як користувач буде переміщатися по додатку. Все це залежить від базової функціональності смарт-контрактів, для Rubicon це протокол книги ордерів і пов'язані з ним пули ліквідності.
Визначте схему, яка забезпечить роботу інтерфейсу користувача, який ви розробили. Після того, як ви створили макет інтерфейсу, відносно легко зрозуміти, які дані вам знадобляться для наповнення додатку. Якщо є сумніви, краще зробити його простішим.
Реалізувати події смарт-контракту, які можуть заповнити визначену нами схему. Іноді це може бути складно, особливо в міру того, як протокол ускладнюється, і вимагає глибокого розуміння базових смарт-контрактів, щоб знати, де і коли слід генерувати події. Створення діаграми всіх потенційних взаємодій користувача зі смарт-контрактами може допомогти на цьому етапі процесу.
Використовуючи описаний вище підхід, Rubicon зміг створити додаток, який повністю покладається на підграфи для внутрішнього інтерфейсу (backend), усуваючи необхідність покладатися на централізований інтерфейс і закладаючи основу для повністю децентралізованого додатку.
Зауваження щодо нод. Кожен, хто має змогу, повинен запустити ноду. Різноманітність клієнтів не просто важлива, вона має вирішальне значення для успіху наших спільних зусиль задля створення дійсно децентралізованого інтернету.
Використання EDD з проксі-контрактами, які можна оновлювати
Якщо ви не знайомі з Upgradeable Proxy Contracts і хотіли б дізнатися більше, у OpenZeppelin є багато інформації на цю тему. Якщо коротко, то проксі-контракти з можливістю оновлення дозволяють вам оновлювати ваші смарт-контракти з часом, відокремлюючи основний алгоритм від контракту, до якого має доступ користувач. Це дозволяє оновлювати алгоритм, в той час як точка доступу залишається незмінною. Це чудово, але може призвести до дивної поведінки при оновленні подій контракту.
Існує безліч сценаріїв, які можна використати при оновленні події, щоб включити більше, менше або зовсім інші дані. Використовуючи проксі-контракти, це дуже легко зробити. Отже, ви входите, переміщуєте деякі змінні, оновлюєте контракти, але при оновленні зв'язків виявляєте, що не можете індексувати одну і ту ж назву події з різними структурами параметрів! Це сумна реальність для багатьох розробників підграфів, і ми сподіваємося, що ви зможете уникнути її, дотримуючись належного використання EDD.
Якщо ви використовували event в минулому і хочете оновити його, щоб отримати нові дані, ПЕРЕЙМЕНУЙТЕ EVENT. Це дозволить вам продовжувати індексувати старі дані, паралельно індексуючи нову. Щоб зробити це, вам потрібно буде змінити оновлений ABI контракту, щоб внести цю історичну подію.
У цьому прикладі LogMake є подією з минулого з першої версії контракту RubiconMarket.sol, який ми розглядали в цій статті. Мітка часу - це змінна, яку можна отримати з самої транзакції, і тому її не потрібно включати в подію. Для того, щоб змінити цю подію, не втрачаючи при цьому зворотної сумісності, ми просто вилучаємо стару подію на користь нової з новою назвою, як показано нижче.
/// V1 Legacy event that is being depreciated:
/// event LogMake(
/// bytes32 indexed id,
/// bytes32 indexed pair,
/// address indexed maker,
/// ERC20 pay_gem,
/// ERC20 buy_gem,
/// uint128 pay_amt,
/// uint128 buy_amt,
/// uint64 timestamp
/// );
/// V2 currently used event, ABI of LogMake altered to reflect changes:
event RecordOffer(
bytes32 indexed id,
bytes32 indexed pair,
address indexed maker,
ERC20 pay_gem,
ERC20 buy_gem,
uint128 pay_amt,
uint128 buy_amt
);
Тепер нам потрібно виконати деякі зміни в наших контрактних ABI. Для цього ми просто знаходимо LogMake-частину нашого ABI з першої версії протоколу і оновлюємо наш ABI у другій версії у нашому підграфі, щоб включити цю подію.
{
"anonymous":false,
"inputs":[
{
"indexed":true,
"internalType":"bytes32",
"name":"id",
"type":"bytes32"
},
{
"indexed":true,
"internalType":"bytes32",
"name":"pair",
"type":"bytes32"
},
{
"indexed":true,
"internalType":"address",
"name":"maker",
"type":"address"
},
{
"indexed":false,
"internalType":"contract ERC20",
"name":"pay_gem",
"type":"address"
},
{
"indexed":false,
"internalType":"contract ERC20",
"name":"buy_gem",
"type":"address"
},
{
"indexed":false,
"internalType":"uint128",
"name":"pay_amt",
"type":"uint128"
},
{
"indexed":false,
"internalType":"uint128",
"name":"buy_amt",
"type":"uint128"
},
{
"indexed":false,
"internalType":"uint64",
"name":"timestamp",
"type":"uint64"
}
],
"name":"LogMake",
"type":"event"
},
Тепер, у нашому оновленому ABI, ми можемо оновити наш файл subgraph.yaml, щоб переконатися, що ми охоплюємо як застарілі події першої версії, так і поточні події другої версії. Це перетворюється на щось на кшталт наступного:
abis:
- name: RubiconMarket
file: ./abis/RubiconMarketOptimism.json
eventHandlers:
- event: RecordOffer(indexed bytes32,indexed bytes32,indexed address,address,address,uint128,uint128)
handler: handleOffer
- event: RecordTake(indexed bytes32,indexed bytes32,indexed address,address,address,address,uint128,uint128)
handler: handleTake
- event: RecordCancel(indexed bytes32,indexed bytes32,indexed address,address,address,uint128,uint128)
handler: handleCancel
- event: RecordFee(indexed bytes32,indexed address,indexed address,bytes32,address,uint256)
handler: handleFee
- event: RecordDelete(indexed bytes32,indexed bytes32,indexed address)
handler: handleDelete
# these are events from the v1 protocol stack, and are included to ensure data congruity
- event: LogMake(indexed bytes32,indexed bytes32,indexed address,address,address,uint128,uint128,uint64)
handler: handleLogMake
- event: LogTake(bytes32,indexed bytes32,indexed address,address,address,indexed address,uint128,uint128,uint64)
handler: handleLogTake
- event: LogKill(indexed bytes32,indexed bytes32,indexed address,address,address,uint128,uint128,uint64)
handler: handleLogKill
- event: OfferDeleted(indexed bytes32)
handler: handleOfferDeleted
- event: FeeTake(indexed bytes32,indexed bytes32,address,indexed address,address,uint256,uint64)
handler: handleFeeTake
Ось і все!
Використовуючи проксі, ми можемо оновлювати наші контракти між версіями без зміни основної адреси доступу, навколо якої побудована екосистема. Дотримуючись принципів EDD, ми можемо просто модифікувати наші підграфи, щоб індексувати як старі, так і поточні події, а це означає, що наш додаток може працювати на основі існуючих структур схем. Навіть більше, ми не втрачаємо всі наші дані, коли відбувається оновлення протоколу.
Rubicon скористався перевагами EDD, щоб забезпечити безперебійну роботу користувачів при оновленні наших контрактів з першої версії протоколу на другу. Це означає, що користувачі можуть взаємодіяти з тим самим інтерфейсом, мати доступ до всіх своїх історичних даних і використовувати найновішу версію протоколу, не роблячи ніяких спеціальних дій задля цього. Це те, чим ми неймовірно пишаємося, і ми продовжуємо працювати над тим, щоб надавати користувачам найкращий досвід використання DeFi , і все це завдяки EDD.
Хоча EDD не є універсальним рішенням, його варто розглянути як частину вашої роботи над розробкою децентралізованого додатку. Визначаючи критичні події, створюючи смарт-контракти, спрямовані на події, і використовуючи підграфи, ви можете створювати масштабовані, підтримувані і швидко реагуючі децентралізовані додатки. Ми пропонуємо вам дослідити потенціал EDD і оцінити, чи може він стати цінним доповненням до вашого набору інструментів для розробки.
Про Rubicon
Rubicon - це протокол книг ордерів, побудований на Ethereum, який має на меті прискорити і демократизувати світові фінанси, створюючи кращі ринки для людей. Книги ордерів допомагають справлятися з асиметричною інформацією на ринках, і з часом стали найбільш широко використовуваною системою в традиційних фінансах. Повністю відкритий і доступний для всіх, Rubicon прагне до створення справедливих і нейтральних ринків з високою довірою у всьому світі. Якщо Ethereum - це світовий комп'ютер, то Rubicon - це світовий ринок ордерів.
Внесення вкладу до блогу The Graph Builders
Як децентралізований проект, ми щиро віримо, що обмін знаннями має вирішальне значення для зростання і розвитку всієї екосистеми. Блог The Graph Builders - це платформа для розробників і тих, хто працює з екосистемою The Graph, де вони можуть ділитися своїми ідеями, досвідом і практикою, пов'язаними зі створенням децентралізованих додатків за допомогою The Graph.
Беручи участь у блозі The Graph Builders Blog, ви матимете можливість продемонструвати свій досвід, поділитися розв'язанням певних проблем та отримати доступ до спільноти розробників-однодумців. Ми впевнені, що ваші ідеї надихатимуть і навчатимуть інших, а також внесуть свій вклад у повністю децентралізоване майбутнє.
Переваги авторства у блозі The Graph Builders Blog
Після того, як редактори The Graph затвердять ваш блог, ви будете представлені на сайті The Graph, який має охоплення в понад сотні тисяч читачів, з зазначенням вас як автора блогу;
Ми виділимо та позначимо вас у соціальних мережах, включаючи Twitter з майже 300 тис. підписників;
Ви отримаєте POAP “The Graph Builders Blog Author”;
Ви зможете додати, що ви є автором блогу The Graph Builders Blog до свого LinkedIn та резюме.
Щоб подати заявку на участь у блозі The Graph Builders Blog, заповніть цю форму, і ми зв'яжемося з вами.
Про The Graph
The Graph - це складова індексації та запитів у web3. Розробники створюють та публікують відкриті API, так звані підграфи, до яких додатки можуть звертатися за допомогою GraphQL. Наразі Graph підтримує індексацію даних з понад 40 різних мереж, включаючи Ethereum, NEAR, Arbitrum, Optimism, ZkSync, Polygon, Avalanche, Celo, Fantom, Moonbeam, IPFS, Cosmos Hub та PoA, а незабаром буде додано ще більше мереж. На сьогодні на хостинговому сервісі розгорнуто понад 88900 підграфів. Десятки тисяч розробників використовують The Graph для таких додатків, як Uniswap, Synthetix, KnownOrigin, Art Blocks, Gnosis, Balancer, Livepeer, DAOstack, Audius, Decentraland та багатьох інших.
Сервіс самообслуговування для розробників The Graph Network був запущений у липні 2021 року; з того часу понад 800+ підграфів мігрували до Мережі, а 450+ індексаторів обслуговують запити до підграфів, 11 300+ делегатів та 2 500+ кураторів на сьогодні.Нині було використано понад 5,6 мільйона токенів GRT для подачі сигналів.
Якщо ви розробник, який створює додаток або програму у web3, ви можете використовувати підграфи для індексації та запитів даних з блокчейнів. The Graph дозволяє додаткам ефективно і продуктивно представляти дані в інтерфейсі користувача і дозволяє іншим розробникам також використовувати ваш підграф! Ви можете розгорнути підграф в мережі за допомогою нещодавно запущеної Subgraph Studio або запитувати наявні підграфи, які знаходяться в Graph Explorer. The Graph буде радий вітати вас як Індексаторів, Кураторів та/або Делегатів в основній мережі The Graph. Приєднуйтесь до спільноти The Graph, представивши себе в The Graph Discord для технічних обговорень, приєднуйтесь до чату The Graph в Telegram, а також слідкуйте за The Graph у Twitter, LinkedIn,
The Graph Foundation контролює The Graph Network. The Graph Foundation контролюється Technical Council, Edge & Node, StreamingFast, Semiotic Labs, The Guild, Messari та GraphOps - це лише кілька з основних організацій, що входять в екосистему The Graph.
Source - link
Ласкаво просимо до першого випуску блогу The Graph Builders! The Graph Builders Blog - це місце, де розробники можуть збиратися разом, вчитися один у одного та ділитися своїми знаннями з усією спільнотою The Graph. Щоб дізнатися більше та подати заявку на участь у блозі, перейдіть до кінця цієї статті.
Цей допис належить Denver Baumgartner з Rubicon. Ознайомтеся з прикладами підграфів у цій статті в репозиторії Rubicon на GitHub.
У цій статті я представлю концепцію подійно-орієнтованої розробки (EDD), яка може покращити розробку смарт-контрактів і підграфів при використанні The Graph.
Але перш ніж ми заглибимось в це поняття, розглянемо деякі основи.
Що таке event, та як відбувається його обробка у підграфах?
У Solidity event (подія) - це механізм реєстрації та сповіщення блокчейну Ethereum і його користувачів про певну дію в смарт-контракті. Коли смарт-контракт генерує подію, він створює повідомлення, яке зберігається в блокчейні. Зовнішні додатки можуть отримувати доступ до цих журналів і дізнаватися більше про них , що робить EDD зручним способом повідомляти про зміни стану і запускати відповідні дії. Ethers.js, одна з найпоширеніших бібліотек web3, дозволяє створювати фільтри подій (тільки для індексованих параметрів) саме для цієї мети. Ви можете ознайомитися з документацією тут. Підграфи, використовують eventHandlers для обробки цих подій у зіставленнях підграфів.
Події визначаються за допомогою ключового слова event, за яким слідує її назва та визначення в дужках. Нижче наведений приклад визначення події та функції, яка її викликає:
pragma solidity ^0.8.9;
/// @notice Events contract for logging trade activity on Rubicon Market
/// @dev Provides the key event logs that are used in all core functionality of exchanging on the Rubicon Market
contract EventfulMarket {
// Define the event
event RecordOffer(
bytes32 indexed id,
bytes32 indexed pair,
address indexed maker,
ERC20 pay_gem,
ERC20 buy_gem,
uint128 pay_amt,
uint128 buy_amt
);
...
/// @notice Key function to make a new offer. Takes funds from the caller into market escrow.
function offer(
uint256 pay_amt,
ERC20 pay_gem,
uint256 buy_amt,
ERC20 buy_gem,
address owner,
address recipient
) public virtual can_offer synchronized returns (uint256 id) {
require(uint128(pay_amt) == pay_amt);
require(uint128(buy_amt) == buy_amt);
require(pay_amt > 0);
require(pay_gem != ERC20(address(0)));
require(buy_amt > 0);
require(buy_gem != ERC20(address(0)));
require(pay_gem != buy_gem);
OfferInfo memory info;
info.pay_amt = pay_amt;
info.pay_gem = pay_gem;
info.buy_amt = buy_amt;
info.buy_gem = buy_gem;
info.recipient = recipient;
info.owner = owner;
info.timestamp = uint64(block.timestamp);
id = _next_id();
offers[id] = info;
require(pay_gem.transferFrom(msg.sender, address(this), pay_amt));
emit LogItemUpdate(id);
emit RecordOffer(
bytes32(id),
keccak256(abi.encodePacked(pay_gem, buy_gem)),
msg.sender,
pay_gem,
buy_gem,
uint128(pay_amt),
uint128(buy_amt)
);
}
}
У цьому прикладі ми пояснюємо визначення події RecordOffer з відповідними параметрами для нашого підграфа:
id: унікальний id пропозиції
pair: торгова пара для пропозиції (тобто ETH-USDC)
maker: адреса, з якої було зроблено пропозицію
pay_gem: актив, який продає (або оплачує) пропозицію
buy_gem: актив, який купує пропозицію
pay_amt: сума, яку потрібно сплатити (або продати)
buy_amt: кількість, яку потрібно купити
співвідношення pay_amt / buy_amt визначає ціну пропозиції
Функція offer (пропозиція) дозволяє користувачеві створити пропозицію, вказавши актив, який він хотів би продати, актив, який він хотів би отримати натомість, і суму кожного активу відповідно (що визначає "ціну" цієї пропозиції). Після успішного використання функції пропозиції транслюється подія RecordOffer з відповідною інформацією щодо самої пропозиції. Це дозволяє нам індексувати відповідну інформацію пропозиції без виклику стану всередині мережі, підвищуючи ефективність індексації та зменшуючи витрати на ресурси.
The Graph має чудовий набір інструментів для автоматизації генерування коду, необхідного для обробки подій під час індексування, а саме codegen. Існує безліч ресурсів з розробки підграфів, доступних у документації The Graph, які я рекомендую переглянути, якщо ви хочете дізнатися більше про розробку підграфів з практичної точки зору.
Говорячи про мету цієї статті,все, що вам потрібно знати, це те, що codegen використовує бінарний інтерфейс додатку договору (ABI) і створює класи для подій, до яких ви можете отримати доступ у відображеннях, приклад якого наведено нижче:
export class RecordOffer extends ethereum.Event {
get params(): RecordOffer__Params {
return new RecordOffer__Params(this);
}
}
export class RecordOffer__Params {
_event: RecordOffer;
constructor(event: RecordOffer) {
this._event = event;
}
get id(): Bytes {
return this._event.parameters[0].value.toBytes();
}
get pair(): Bytes {
return this._event.parameters[1].value.toBytes();
}
get maker(): Address {
return this._event.parameters[2].value.toAddress();
}
get pay_gem(): Address {
return this._event.parameters[3].value.toAddress();
}
get buy_gem(): Address {
return this._event.parameters[4].value.toAddress();
}
get pay_amt(): BigInt {
return this._event.parameters[5].value.toBigInt();
}
get buy_amt(): BigInt {
return this._event.parameters[6].value.toBigInt();
}
}
Для ознайомлення, ми швидко розглянули.
Тепер, коли ви розумієте ці основи, давайте познайомимося з подійно-орієнтованою розробкою!
Що таке подійно-орієнтована розробка (EDD)?
Подійно-орієнтована розробка (EDD) - це стратегія розробки, яка базується на створенні смарт-контрактів з великою кількістю даних для децентралізованих додатків . Вона закладає основу подій для смарт-контрактів з урахуванням кінцевого застосування або варіанту використання, що, в свою чергу, допомагає ефективно надавати користувачам як поточні, так і історичні дані.
Одним з ключових принципів EDD є забезпечення того, щоб смарт-контракти генерували багаті та відповідні події. Цей підхід є невід'ємною частиною побудови надійного фундаменту для вашого додатку він допоможе оптимізувати процес індексації та запитів. Ця оптимізація значно покращує роботу зовнішнього інтерфейсу та загалом досвід використання, сприяючи масштабованості та зручності вашого додатку.
Акцент на смарт-контрактах, багатих на події, допомагає створити багате на дані середовище, сприятливе для створення та масштабування децентралізованих додатків і підграфів. Давайте розглянемо, як ця проста концепція може мати каскадний ефект для подальшого розвитку вашого децентралізованого додатку.
Переваги EDD
Покращене планування децентралізованого додатку: Критично обмірковуючи конкретні події, дані, які вони містять, і час, в який вони генеруються, перед написанням зовнішнього інтерфейсу вашого децентралізованого додатка, ви не витрачаєте час на рефакторинг і можете більш впевнено планувати взаємодію з користувачем.
Масштабованість та адаптивність: EDD вигідна для оптимізації підграфів, оскільки підграфи набагато швидше індексують події за допомогою eventHandlers, а не callHandlers або blockHandlers. Якщо ваш додаток потребує масштабування, то написання смарт-контрактів таким чином, щоб кожен ключовий момент генерував подію з усіма відповідними метаданими, дозволить вашому підграфу масштабуватися, відповідаючи вашим вимогам до даних.
Зручність обслуговування: Модульна структура EDD спрощує обслуговування та усунення несправностей коду. Організовуючи кодову базу навколо подій, розробники можуть легше виявляти і вирішувати проблеми, скорочуючи час і зусилля, необхідні для усунення несправностей.
Покращена взаємодія: Розглянемо декілька смарт-контрактів з декількома підграфами, які в даний час індексують дані смарт-контрактів, кожен з яких має власні відображення та схеми. Така ситуація може швидко стати переважаючою, якщо стратегія не буде розглянута на ранній стадії розробки. Включення EDD в процес роботи робить події ключовим фокусом для обговорення та оптимізації між командою смарт-контрактів і командою підграфів.
Ще однією важливою перевагою EDD є вартість.
На практиці наша команда змогла значно зменшити витрати на підтримку додатків виробничого рівня, різко скоротивши використання RPC в додатках. Наприклад, ви можете перейти від 1000 користувачів, які здійснюють один RPC-виклик для отримання поточного балансу пулу, до 1000 викликів GraphQL до сервера PostgreSQL. Крім того, цей PostgreSQL можна налаштувати під ваш конкретний підграф. Шардинг, оптимізація для кеш-зв'язків і безліч інших дій індексатора - це окрема тема для окремого посту.
Загалом, варто масштабувати протокол, звертаючи увагу на підграфи.
Використання EDD зі смарт-контрактами
Тепер, коли ви розумієте, що таке EDD, давайте розглянемо, як ми використовуємо EDD в Rubicon Finance, починаючи з наших смарт-контрактів.
Щоб включити в наші смарт-контракти підхід, який базується на EDD, ми почали з інтерфейсу нашого додатку і працювали в зворотному напрямку вниз по стеку.
В контексті подій і функцій, описаних вище, ми знаємо, що користувачі захочуть не тільки розміщувати пропозиції, а й бачити минулі пропозиції і статус інших пропозицій. Тому в наших контрактах, коли відбувається оновлення пропозиції (хтось здійснює торгівлю з автором пропозиції, автор пропозиції скасовує пропозицію або пропозиція збігається з іншою пропозицією), ми слідкуємо за тим, щоб вся відповідна інформація про зміну стану цієї пропозиції була опублікована як подія.
Визначаючи ці події заздалегідь, ми можемо використовувати EDD для планування всього потоку даних нашого додатку під час створення самих смарт-контрактів.
З точки зору схеми, ми можемо створити багато важливих структур даних, які можуть керувати різними компонентами програми. Чудовим прикладом цього є дані для свічкової діаграми:

Оскільки наші контракти передають дані по мірі того, як відбувається торгівля, ми можемо в реальному часі оновлювати вигляд діаграми, шляхом відображення цих подій на об’єктах в наших підграфах!
Звідси наш децентралізований додаток може використовувати live-polling в реальному часі через graph-client, щоб відслідковувати оновлення певних об'єктів підграфів, таких як остання свічкова діаграма, і відповідно оновлювати інтерфейс! Це неймовірно ефективний спосіб для отримання та відображення даних з мережі. Ви зможете не тільки реагувати на події, щойно вони відбудуться, але й зможете уникнути необхідності запускати або платити за ноди для отримання даних.
Якщо ви ще не використовували graph-client, я рекомендую вам це зробити. Існує безліч корисних конфігурацій, таких як шаблони резервного копіювання, які дозволяють керувати мережею підграфів та індексаторів, щоб забезпечити користувачам безперебійну роботу з високим рівнем доступності.
Події також дозволяють відтворити поточний стан смарт-контрактів у ваших відображеннях підграфів і можуть допомогти в історичному аналізі, коли ви хочете перевірити стан контракту в певному блоці в часі. Прикладом цього є відстеження балансу користувача в пулі ліквідності Rubicon. Якщо ми знаємо про кожен депозит, зняття коштів і переказ, які відбулися, ми можемо визначити баланс користувача в будь-який момент часу. Запити з можливістю переміщення в часі корисні для цього, але вони позбавляють можливості вилучати підграфи, що може підвищити продуктивність при масштабуванні (особливо, якщо об’єкти оновлюються, якщо ні, то зробити їх незмінними). На практиці ми виявили, що корисно розподіляти різні потреби додатків між кількома підграфами.
Загалом, ми виявили, що найкраще дотримуватися процесу розробки, який виглядає наступним чином:
Вирішити, як повинен виглядати користувацький інтерфейс додатку, і яким буде його використання, як користувач буде переміщатися по додатку. Все це залежить від базової функціональності смарт-контрактів, для Rubicon це протокол книги ордерів і пов'язані з ним пули ліквідності.
Визначте схему, яка забезпечить роботу інтерфейсу користувача, який ви розробили. Після того, як ви створили макет інтерфейсу, відносно легко зрозуміти, які дані вам знадобляться для наповнення додатку. Якщо є сумніви, краще зробити його простішим.
Реалізувати події смарт-контракту, які можуть заповнити визначену нами схему. Іноді це може бути складно, особливо в міру того, як протокол ускладнюється, і вимагає глибокого розуміння базових смарт-контрактів, щоб знати, де і коли слід генерувати події. Створення діаграми всіх потенційних взаємодій користувача зі смарт-контрактами може допомогти на цьому етапі процесу.
Використовуючи описаний вище підхід, Rubicon зміг створити додаток, який повністю покладається на підграфи для внутрішнього інтерфейсу (backend), усуваючи необхідність покладатися на централізований інтерфейс і закладаючи основу для повністю децентралізованого додатку.
Зауваження щодо нод. Кожен, хто має змогу, повинен запустити ноду. Різноманітність клієнтів не просто важлива, вона має вирішальне значення для успіху наших спільних зусиль задля створення дійсно децентралізованого інтернету.
Використання EDD з проксі-контрактами, які можна оновлювати
Якщо ви не знайомі з Upgradeable Proxy Contracts і хотіли б дізнатися більше, у OpenZeppelin є багато інформації на цю тему. Якщо коротко, то проксі-контракти з можливістю оновлення дозволяють вам оновлювати ваші смарт-контракти з часом, відокремлюючи основний алгоритм від контракту, до якого має доступ користувач. Це дозволяє оновлювати алгоритм, в той час як точка доступу залишається незмінною. Це чудово, але може призвести до дивної поведінки при оновленні подій контракту.
Існує безліч сценаріїв, які можна використати при оновленні події, щоб включити більше, менше або зовсім інші дані. Використовуючи проксі-контракти, це дуже легко зробити. Отже, ви входите, переміщуєте деякі змінні, оновлюєте контракти, але при оновленні зв'язків виявляєте, що не можете індексувати одну і ту ж назву події з різними структурами параметрів! Це сумна реальність для багатьох розробників підграфів, і ми сподіваємося, що ви зможете уникнути її, дотримуючись належного використання EDD.
Якщо ви використовували event в минулому і хочете оновити його, щоб отримати нові дані, ПЕРЕЙМЕНУЙТЕ EVENT. Це дозволить вам продовжувати індексувати старі дані, паралельно індексуючи нову. Щоб зробити це, вам потрібно буде змінити оновлений ABI контракту, щоб внести цю історичну подію.
У цьому прикладі LogMake є подією з минулого з першої версії контракту RubiconMarket.sol, який ми розглядали в цій статті. Мітка часу - це змінна, яку можна отримати з самої транзакції, і тому її не потрібно включати в подію. Для того, щоб змінити цю подію, не втрачаючи при цьому зворотної сумісності, ми просто вилучаємо стару подію на користь нової з новою назвою, як показано нижче.
/// V1 Legacy event that is being depreciated:
/// event LogMake(
/// bytes32 indexed id,
/// bytes32 indexed pair,
/// address indexed maker,
/// ERC20 pay_gem,
/// ERC20 buy_gem,
/// uint128 pay_amt,
/// uint128 buy_amt,
/// uint64 timestamp
/// );
/// V2 currently used event, ABI of LogMake altered to reflect changes:
event RecordOffer(
bytes32 indexed id,
bytes32 indexed pair,
address indexed maker,
ERC20 pay_gem,
ERC20 buy_gem,
uint128 pay_amt,
uint128 buy_amt
);
Тепер нам потрібно виконати деякі зміни в наших контрактних ABI. Для цього ми просто знаходимо LogMake-частину нашого ABI з першої версії протоколу і оновлюємо наш ABI у другій версії у нашому підграфі, щоб включити цю подію.
{
"anonymous":false,
"inputs":[
{
"indexed":true,
"internalType":"bytes32",
"name":"id",
"type":"bytes32"
},
{
"indexed":true,
"internalType":"bytes32",
"name":"pair",
"type":"bytes32"
},
{
"indexed":true,
"internalType":"address",
"name":"maker",
"type":"address"
},
{
"indexed":false,
"internalType":"contract ERC20",
"name":"pay_gem",
"type":"address"
},
{
"indexed":false,
"internalType":"contract ERC20",
"name":"buy_gem",
"type":"address"
},
{
"indexed":false,
"internalType":"uint128",
"name":"pay_amt",
"type":"uint128"
},
{
"indexed":false,
"internalType":"uint128",
"name":"buy_amt",
"type":"uint128"
},
{
"indexed":false,
"internalType":"uint64",
"name":"timestamp",
"type":"uint64"
}
],
"name":"LogMake",
"type":"event"
},
Тепер, у нашому оновленому ABI, ми можемо оновити наш файл subgraph.yaml, щоб переконатися, що ми охоплюємо як застарілі події першої версії, так і поточні події другої версії. Це перетворюється на щось на кшталт наступного:
abis:
- name: RubiconMarket
file: ./abis/RubiconMarketOptimism.json
eventHandlers:
- event: RecordOffer(indexed bytes32,indexed bytes32,indexed address,address,address,uint128,uint128)
handler: handleOffer
- event: RecordTake(indexed bytes32,indexed bytes32,indexed address,address,address,address,uint128,uint128)
handler: handleTake
- event: RecordCancel(indexed bytes32,indexed bytes32,indexed address,address,address,uint128,uint128)
handler: handleCancel
- event: RecordFee(indexed bytes32,indexed address,indexed address,bytes32,address,uint256)
handler: handleFee
- event: RecordDelete(indexed bytes32,indexed bytes32,indexed address)
handler: handleDelete
# these are events from the v1 protocol stack, and are included to ensure data congruity
- event: LogMake(indexed bytes32,indexed bytes32,indexed address,address,address,uint128,uint128,uint64)
handler: handleLogMake
- event: LogTake(bytes32,indexed bytes32,indexed address,address,address,indexed address,uint128,uint128,uint64)
handler: handleLogTake
- event: LogKill(indexed bytes32,indexed bytes32,indexed address,address,address,uint128,uint128,uint64)
handler: handleLogKill
- event: OfferDeleted(indexed bytes32)
handler: handleOfferDeleted
- event: FeeTake(indexed bytes32,indexed bytes32,address,indexed address,address,uint256,uint64)
handler: handleFeeTake
Ось і все!
Використовуючи проксі, ми можемо оновлювати наші контракти між версіями без зміни основної адреси доступу, навколо якої побудована екосистема. Дотримуючись принципів EDD, ми можемо просто модифікувати наші підграфи, щоб індексувати як старі, так і поточні події, а це означає, що наш додаток може працювати на основі існуючих структур схем. Навіть більше, ми не втрачаємо всі наші дані, коли відбувається оновлення протоколу.
Rubicon скористався перевагами EDD, щоб забезпечити безперебійну роботу користувачів при оновленні наших контрактів з першої версії протоколу на другу. Це означає, що користувачі можуть взаємодіяти з тим самим інтерфейсом, мати доступ до всіх своїх історичних даних і використовувати найновішу версію протоколу, не роблячи ніяких спеціальних дій задля цього. Це те, чим ми неймовірно пишаємося, і ми продовжуємо працювати над тим, щоб надавати користувачам найкращий досвід використання DeFi , і все це завдяки EDD.
Хоча EDD не є універсальним рішенням, його варто розглянути як частину вашої роботи над розробкою децентралізованого додатку. Визначаючи критичні події, створюючи смарт-контракти, спрямовані на події, і використовуючи підграфи, ви можете створювати масштабовані, підтримувані і швидко реагуючі децентралізовані додатки. Ми пропонуємо вам дослідити потенціал EDD і оцінити, чи може він стати цінним доповненням до вашого набору інструментів для розробки.
Про Rubicon
Rubicon - це протокол книг ордерів, побудований на Ethereum, який має на меті прискорити і демократизувати світові фінанси, створюючи кращі ринки для людей. Книги ордерів допомагають справлятися з асиметричною інформацією на ринках, і з часом стали найбільш широко використовуваною системою в традиційних фінансах. Повністю відкритий і доступний для всіх, Rubicon прагне до створення справедливих і нейтральних ринків з високою довірою у всьому світі. Якщо Ethereum - це світовий комп'ютер, то Rubicon - це світовий ринок ордерів.
Внесення вкладу до блогу The Graph Builders
Як децентралізований проект, ми щиро віримо, що обмін знаннями має вирішальне значення для зростання і розвитку всієї екосистеми. Блог The Graph Builders - це платформа для розробників і тих, хто працює з екосистемою The Graph, де вони можуть ділитися своїми ідеями, досвідом і практикою, пов'язаними зі створенням децентралізованих додатків за допомогою The Graph.
Беручи участь у блозі The Graph Builders Blog, ви матимете можливість продемонструвати свій досвід, поділитися розв'язанням певних проблем та отримати доступ до спільноти розробників-однодумців. Ми впевнені, що ваші ідеї надихатимуть і навчатимуть інших, а також внесуть свій вклад у повністю децентралізоване майбутнє.
Переваги авторства у блозі The Graph Builders Blog
Після того, як редактори The Graph затвердять ваш блог, ви будете представлені на сайті The Graph, який має охоплення в понад сотні тисяч читачів, з зазначенням вас як автора блогу;
Ми виділимо та позначимо вас у соціальних мережах, включаючи Twitter з майже 300 тис. підписників;
Ви отримаєте POAP “The Graph Builders Blog Author”;
Ви зможете додати, що ви є автором блогу The Graph Builders Blog до свого LinkedIn та резюме.
Щоб подати заявку на участь у блозі The Graph Builders Blog, заповніть цю форму, і ми зв'яжемося з вами.
Про The Graph
The Graph - це складова індексації та запитів у web3. Розробники створюють та публікують відкриті API, так звані підграфи, до яких додатки можуть звертатися за допомогою GraphQL. Наразі Graph підтримує індексацію даних з понад 40 різних мереж, включаючи Ethereum, NEAR, Arbitrum, Optimism, ZkSync, Polygon, Avalanche, Celo, Fantom, Moonbeam, IPFS, Cosmos Hub та PoA, а незабаром буде додано ще більше мереж. На сьогодні на хостинговому сервісі розгорнуто понад 88900 підграфів. Десятки тисяч розробників використовують The Graph для таких додатків, як Uniswap, Synthetix, KnownOrigin, Art Blocks, Gnosis, Balancer, Livepeer, DAOstack, Audius, Decentraland та багатьох інших.
Сервіс самообслуговування для розробників The Graph Network був запущений у липні 2021 року; з того часу понад 800+ підграфів мігрували до Мережі, а 450+ індексаторів обслуговують запити до підграфів, 11 300+ делегатів та 2 500+ кураторів на сьогодні.Нині було використано понад 5,6 мільйона токенів GRT для подачі сигналів.
Якщо ви розробник, який створює додаток або програму у web3, ви можете використовувати підграфи для індексації та запитів даних з блокчейнів. The Graph дозволяє додаткам ефективно і продуктивно представляти дані в інтерфейсі користувача і дозволяє іншим розробникам також використовувати ваш підграф! Ви можете розгорнути підграф в мережі за допомогою нещодавно запущеної Subgraph Studio або запитувати наявні підграфи, які знаходяться в Graph Explorer. The Graph буде радий вітати вас як Індексаторів, Кураторів та/або Делегатів в основній мережі The Graph. Приєднуйтесь до спільноти The Graph, представивши себе в The Graph Discord для технічних обговорень, приєднуйтесь до чату The Graph в Telegram, а також слідкуйте за The Graph у Twitter, LinkedIn,
The Graph Foundation контролює The Graph Network. The Graph Foundation контролюється Technical Council, Edge & Node, StreamingFast, Semiotic Labs, The Guild, Messari та GraphOps - це лише кілька з основних організацій, що входять в екосистему The Graph.
No comments yet