Дерево ликвидности и рынки предсказаний в DeFi

На нашем EVM-Compatible Meetup в Тбилиси Денис Кайзер, Core Contributor в Azuro Protocol, рассказал про новую архитектуру для децентрализованных пулов ликвидности в докладе «Liquidity Tree: A New Liquidity Pool Design for Specialized Prediction Markets».

Про протокол Azuro

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

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

Мы посмотрели со стороны на классический букмекерский бизнес и поняли, что он состоит из четырех основных частей:

  • данные (о событиях, коэффициенты ставок, результаты);
  • ликвидность, чтобы делать выплаты победителям;
  • работа с пользователями;
  • управление.

alt_text

Мы разделили эти четыре элемента между разными механизмами, чтобы обеспечить децентрализацию и trustless-подход.

  • Пулы ликвидности, куда любой пользователь может внести средства, обеспечивают выплаты игрокам.
  • Дата-провайдеры, которые при помощи оракулов поставляют данные о коэффициентах, событиях, ставках и т.д.
  • Фронтенд-операторы — любой может создать свое решение поверх протокола.
  • Спорные моменты решаются за счет токенхолдеров.

Все эти четыре элемента системы делят между собой прибыль протокола.

alt_text

Как устроена монетизация проекта

В беттинге не приняты комиссии на транзакции. Вместо этого, комиссия вшита уже в коэффициенты. Что такое коэффициенты? Например, чистые коэффициенты в игре «Орел и решка» — 2.0 и 2.0. Шанс выпасть у той или иной стороны 50%. Но тут есть некий спред, благодаря которому участники зарабатывают. В таком случае коэффициент будет 1.9 и 1.9. В контексте длинной дистанции протокол будет зарабатывать примерно 5% от оборота.

alt_text

Наш протокол отличается от большинства, в том числе — от рынков предсказаний, потому что пул не привязан к конкретному событию. В Azuro есть один общий пул ликвидности, в который инвесторы закинули денег. Далее фид-провайдеры через оракулов создают маркеты (conditions в Azuro), на которые можно делать ставки. Их очень много, за счет чего достигается диверсификация провайдеров, что гарантирует доходность. Событий очень много и теория вероятности на стороне пользователей. Конечно, если коэффициент задан правильно.

alt_text

Устройство дерева ликвидности

Есть conditions — элементарное событие, на которое можно сделать скидку (да/нет или другой простой вариант). Conditions генерят определенную комиссию, все это заливается в пул ликвидности. Прибыль распределяется между провайдерами ликвидности, в соответствии с их долей.

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

alt_text

Самое простое «магловское» решение — просто считать, кто и в какой condition положит деньги. Но в этом случае приходится хранить данные про каждого холдера депозита: какую сумму он внес и когда, а потом каким-то образом это все синхронизировать.

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

alt_text

Мы придумали, соотнести timestamps и conditions при помощи логарифма. Даже при миллиарде депозитов это займет всего около 27 операций.

Есть такая структура данных — дерево отрезков. Она позволяет достаточно быстро выполнять математические операции внутри массива. Операции могут быть разные: найти большее или меньшее значение, их произведения, или, как в нашем случае, найти сумму.

alt_text

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

alt_text

Навигация по дереву

Дерево удобнее нумеровать не с 0, а с 1. Тогда мы получим удобную систему: у нас всегда левый ребенок — родитель, умноженный на два. А правый — родитель, умноженный на два + ребенок. Четные индексы — слева, правые индексы — нечетные. Легко подниматься по дереву вверх.

В этом примере четыре листочка — четыре депозита ликвидности. При такой структуре, максимум депозитов в пул ликвидности — четыре. Azuro использует около триллиона листочков. И это не требует много GAS fee.

alt_text

Как использовать ликвидность

Добавление ликвидности. Первый провайдер заливает $100 — мы записываем его в четвертый листик, после чего он попадает во второй, а потом и в первый. Второй провайдер, который внес $200, проделывает такой же путь. После этого в первом листике становится $300.

alt_text

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

alt_text

Чтобы избежать обмана, когда во время активного condition, кто-то может внести большой объем ликвидности — мы можем обновить только его родителя в дереве.

alt_text

В случае, когда протокол возвращает прибыль — он передает сумму, которую возвращает и последний полный элемент. Например, если это 5, мы можем понять, что это был правый (нечетный) ребенок, значит он — последний (так как у родителя всего два листочка). Тогда мы обновляем только верхнего родителя. При выводе листки тоже не обновляются, также вывод вычисляется через значения родителя. Выгрузка из газ-репортера, при триллионе элементов показывает всего 300 000 газа, что примерно, как swap.

alt_text

Читайте также

Больше мероприятний