Современная реализация пулов ликвидности. Дерево ликвидности Azuro

от автора

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

Для начала.

Пулы ликвидности – это смарт-контракты, содержащие заблокированные крипто-токены, которые были предоставлены пользователями платформы. Они самоисполняются и не нуждаются в посредниках, чтобы заставить их работать. Они поддерживаются другими частями кода, такими как автоматизированные маркет-мейкеры (AMM) , которые помогают поддерживать баланс в пулах ликвидности с помощью математических формул.

За предоставляемые криптоактивы провайдеры ликвидности получают долю от торговых комиссий. Или токены протокола.

Реализация пула ликвидности в беттинг-протоколе.

Давайте немного погрузимся в беттинг.

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

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

Самое простое решение

Самое простое решение

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

Что придумали.

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

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

Работает эта структура данных за О-большое от логарифма.

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

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

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

Как работают механизмы в дереве.

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

nodeAddLiquidity(100$) +--------------------------------------------+ |                    1 (100$)                | +------------------------+-------------------+ |         2 (100$)       |         3         | +-------------+----------+---------+---------+ |   4 (100$)  |     5    |    6    |    7    | +-------------+----------+---------+---------+      +100$  nodeAddLiquidity(200$) +--------------------------------------------+ |                    1 (300$)                | +------------------------+-------------------+ |         2 (300$)       |         3         | +-------------+----------+---------+---------+ |   4 (100$)  | 5 (200$) |    6    |    7    | +-------------+----------+---------+---------+                   +200$

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

remove(30$) +--------------------------------------------+ |                    1 (270$)                | +------------------------+-------------------+ |         2 (270$)       |         3         | +-------------+----------+---------+---------+ |   4 (100$)  | 5 (200$) |    6    |    7    | +-------------+----------+---------+---------+

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

addLimit(15$, 5) +15$  [4, 5] +--------------------------------------------+ |                    1 (585$)                | +------------------------+-------------------+ |         2 (285$)       |    3 (300$)       | +-------------+----------+---------+---------+ |    4 (100$) | 5 (200$) | 6 (300$)|    7    | +-------------+----------+---------+---------+

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

nodeWithdraw(5)  +--------------------------------------------+ |                     1 (300$)               | +------------------------+-------------------+ |           2 (0$)       |    3 (300$)       | +-------------+----------+---------+---------+ |    4 (0$)   |  5 (0$)  | 6 (300$)|    7    | +-------------+----------+---------+---------+                   -190$


ссылка на оригинал статьи https://habr.com/ru/articles/872462/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *