forked from Exzender/dex223-liquidations
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtodo.txt
188 lines (146 loc) · 19.8 KB
/
todo.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
Задача: реализовать референсный скрипт "авто-ликвидаций".
Функции скрипта:
Мониторить контракт Margin Trading'a и смотреть какие позиции могут удовлетворить критериям ликвидации в ближайшее время.
Запоминать какие позиции будет выгоднее ликвидировать (за ликвидацию назначена награда в момент когда ордер создавали)
Исполнять ликвидации позиций, которые ликвидировать выгодно (т.е. награда выше gasPrice транзакции)
---------------------------------------
Стартовая информация по теме:
1. Margin Trading модуль будет отдельным смарт-контрактом, в нём будут физически находиться все "одолженные" активы.
Из этого контракта будут совершаться все сделки по рынку (в теории не только по рынку Dex223, но и по другим DEX'ам
типа Uniswap которые торгуют тот же актив).
2. Ликвидация - это функция от "времени" и "ожидаемого баланса" в ордере. При определенных условиях ликвидацию
какой-либо позиции можно вызвать функцией в контракте (и получить за это награду).
Пример:
Lender поставил в ордер 10 ETH под 20% на 30 дней с требованием залога 5 ETH и наградой за ликвидацию $25.
Borrower положил в ордер 5 ЕТН и получил доступ к совершению торговых операций с теми 10 ЕТН которые в ордере
были изначально. Он пошёл и купил на них DOGE.
Прошло 15 дней, с ценой DOGE что-то произошло, с ценой ETH что-то произошло. Мы можем проверить удовлетворяет
ли данная позиция критериям ликвидации. Т.к. прошла половина срока действия позиции то должно быть на 10%
больше ЕТН чем было изначально (половина от 20%) и того 11 ЕТН.
Для этого мы берём количество DOGE которое в ней находится (изначально купленных на 10 ЕТН) и рассчитываем
"а сколько было бы ЕТН если бы мы сейчас по рынку продали все DOGE которые у нас есть с учётом slippage", з
атем прибавляем 5 ЕТН которые collateral и если получается больше 11 ЕТН в сумме то позицию ликвидировать нельзя.
Если меньше 11 ЕТН в сумме, то можно ликвидировать и получить "награду за ликвидацию".
Смотрим больше ли "награда за ликвидацию" чем GAS транзакции и если больше, то ликвидируем.
Пересчитывать сколько в позиции какого актива в принципе не обязательно. В контракте будет функция
subjectToLiquidation которую можно вызвать на любом ордере (у каждого ордера есть orderID) и если она
вернёт true то нужно вызывать функцию liquidate для этого orderID уже транзакцией (если "награда за
ликвидацию" больше чем GAS транзакции).
Теоретически в каждом блоке может что-то измениться. Когда происходят торги - позиции с изменением цен
или ликвидности могут стать доступными к ликвидации.
Вот так будет выглядеть контракт https://github.com/Dexaran/Dex223-exchange/blob/main/MarginModule.sol
Зависимость ликвидации от времени.
От времени зависит PnL. Если ты встал в лонг или шорт ты не платишь interest rate за месяц вперёд,
а платишь раз в день или раз в некоторый интервал времени который на конкретной бирже определён.
У нас соответственно "раз в блок". Поэтому от времени то сколько "ты уже должен был заплатить"
вычитается из баланса который доступен для торговли, но не всё сразу.
Алгоритм, чтобы не дергать ноду, получается таким:
1. Мониторинг получает уведомление о появившемся маржин-ордере.
2. Мониторинг раз в указанный интервал по всем ордерам проверяет сумму активов (опять же без обращения к нодам) -
по объему токенов и их ценам. Значит нам нужна будет актуальная информация по ценам, соотвествующая выбранному
интервалу (а не обновляющаяся раз в 5-10 минут...).
3. Если пересчет указывает на необходимость ликвидации - уже запрашиваем функцию subjectToLiquidation у контракта.
4. Если нужна ликвидация - проверяем размер комиссии сети, если разница в нашу пользу больше заданного порога -
посылаем запрос в контракт.
5. Мониторинг уведомления о закрытии ордера - чтобы перестать его мониторить в нужный момент.
Q & A
Q: Вызывать функцию ликвидации может кто угодно? Т.е. это будет гонка между желающими получить награду?
A: Кто может вызывать функцию ликвидации определяется типом ордера. Lender указывает "может кто угодно"
или "может тот кто в whitelist'e". Теоретически Lender может сам крутить этот скрипт у себя чтобы не платить
за ликвидации сторонним сервисам. Либо он может заключить контракт о ликвидации позиций и заплатить в оффчейне,
и только тому с кем заключен контракт предоставлять возможность ликвидировать позиции.
Q: Если вызывать ликвидацию для ордера имеющего subjectToLiquidation = false что будет? Потеряем комиссию за
транзакцию, но ордер останется?
A: Не произойдёт ничего. Отправитель потеряет газ который заплатил за транзакцию.
Q: Что делать, если размер комиссии больше потенциального профита? Позволяем Лендеру уходить в минус, выжидая
пока упадет комиссия?
A: Скрипт должен быть конфигурируемым и нам нужна возможность сделать так чтобы он даже себе в убыток
ликвидировал любые позиции, в которых "награда за ликвидацию" больше определенного значения.Если награда
слишком маленькая - никто не будет вручную ликвидировать позиции себе в убыток, так что это в интересах
Lender'a либо назначать достаточно, либо ликвидировать самому.
Нам самим скорее всего придётся выделить часть бюджета и запускать такой скрипт на ранних этапах и он
должен мониторить позиции, в которых, скажем, больше чем $20 награды. Таким образом юзеры будут знать
что если ставить награду больше $20 то их позиция в любом случае попадает под мониторинг и им будет спокойнее.
Я сейчас думаю над тем чтобы реализовать оплату газа Lender'ом. Мы можем получить tx.gasPrice и посчитать
сколько газа потратила транзакция и возместить исполнителю ликвидации затраты на газ отдельно от выплат награды.
-------------------
+/- 1. Локально хранить все позиции - (быстрая локальная БД: LowDB vs LokiJS vs AceBase vs NeDB) : LowDB
(юзер-позиция-токены в позиции-параметры займа)
https://github.com/typicode/lowdb
- чистый JSON, который каждый раз перезаписывается.
- зависимость от размера (объема) данных
- не получится, если будет большой поток данных
https://github.com/appy-one/acebase
- A fast, low memory, transactional, index & query enabled NoSQL database engine and server
(*) 2. Расчет и сохранение исходной цены позиции.
USD? Base Token? Native Coin?
(все-таки в исходном "занятом" токене/коине)
(*) 3. Сейчас у позиции нет даты создания? Только дедлайн?
(дату создания можно брать по дате ивента - появления в БД)
+ 4. Первоначальный расчет позиции и последующие пересчеты - одна функция
(считаем все в USD, суммируем, переводим в "базовый" токен)
5. Хранить историю "закрытия" позиций и расчетную прибыль.
Модуль пересчета активных позиций
2. Интервал пересчета всех активных позиций ?
(прикинуть скорость расчета одной позиции)
2.1. Способ распараллелить проверку/оценку позиций
(читаем позиции из БД, имеем конфиг по кол-ву "воркеров" - раскидываем по ним равномерно кол-во позиций)
(воркеры проверят и отправляют запрос на ликвидацию в отдельную очередь - Редис?)
worker_threads - https://blog.logrocket.com/multithreading-node-js-worker-threads/
https://nodejs.org/api/worker_threads.html
https://www.digitalocean.com/community/tutorials/how-to-use-multithreading-in-node-js
2.2. Конфигурация расчета порога ликвидации (сумма в позиции + стоимость вызова ликвидации + учет размера наград за ликвидацию)
3. Если нашли объект для ликвидации - кидаем его в очередь ликвидаций
4. Когда объект отправлен в очередь ликвидаций мы его перемещаем в "отдельный" массив "на_ликвидации", откуда он будет
либо удален при успешной ликвидации, либо возвращен в основной массив, если ликвидации не произошло.
4.1. Можно обмен реализовать также через Редис. (0 - ожидание ликвидации, 1 - ликвидирован, -1 - ошибка ликвидации)
5. Глобально хранить стоимость выполнения транзакции ликвидации
6. При расчете стоимости "позиции" нужно еще как-то учитывать транзакционные издержки на "продажу/закрытие"
(*) 7. Автоматический возврат позиций, если они не были обработаны скриптом ликвидаций за какой-то срок (интервал?)
(м.б. проходить по списку позиций, отправленных на ликвидацию, и если их нет в Редис - переносить обратно?
Или сначала проверять их наличие в Смарт Контракте?)
8. Если мы пересчитываем позиции пакетом - то результат расчета мы также получаем пакетом, поэтому в очередь на ликвидацию
они будут попадать пачками (не самый удобный вариант) - лучше их отправлять туда сразу. Но если мы будем грузить
основной процесс постоянным дерганием результатами расчета - тоже может стать узким местом.
(?) 9. Можно не двигать никуда позицию по результатам пересчета. И не проверять результат ликвидации. А учитывать только
события из Блокчейна - как позиция оттуда исчезает - так удаляем ее из БД. А до тех пор она участвует в расчетах.
Просто при постановке в очередь ликвидаций - не допускать дублирования данных.
(как в этом случае вести учет - наш ли скрипт закрыл позицию?)
Модуль мониторинга транзакций
1. Можно запустить в основном потоке (просто по ивентам) - не будет гонки по записи в БД
(*) 2. Нужно, чтобы на все изменения в позициях были ивенты (к примеру, повесить на addAsset - но ловить, к примеру просто свопы будет нереально).
3. Мониторинг за изменениями в позициях? Монитор всех транзакций с контрактом Маржин Трейдинга?
4. Мониторинг "появления" новых позиций.
(*) 5. Большинство публичных нод не позволяют мониторить ивенты
10. Мониторинг уведомления о закрытии ордера - чтобы перестать его мониторить в нужный момент.
12. Учесть флаг, что не все могут ликвидировать ту или иную позицию - отсекать "ненужные" на стадии их появления.
13. Фильтр позиций по размеру награды
14. Возможность использования нескольких нод (с авто-переключением)
15. Обработка "пропущенных" ивентов - парсинг начиная с какого-то блока и применение изменений к данным в БД
Модуль выполнения ликвидаций
1. Можно запустить отдельным процессом
2. Нужно учесть, что позиция, отправленная на ликвидацию можеть быть НЕ ликвидирована (если изменились условия, либо
расчеты в контракте не совпали с расчетами на клиенте) - и этот объект должен "вернуться" в исходную обойму для
дальнейшего мониторинга.
2.1. Нужен механизм "уведомления" основного модуля о результатх ликвидации
3. Может быть несколько параллельных запросов на ликвидацию - это важно. Но делать их через разные ноды можно только если
использовать несколько аккаунтов. Либо прямое управление нонсами и включение транзакций в один блок.
5. Скрипт ликвидаций (вызова функции в контракте) - очередь ликвидаций (Redis)
+/- 7. Хранение ключа юзера от чьего имени выполяются ликвидации (приз за ликвидацию падает на его адрес?)
(указать в ENV путь к кейстору - и запрашивать ввод пароля при запуске скрипта)
(предусмотреть запуск без пароля - с передачей пароля в виде параметра)
7.1. (отдельный воркер работает с очередью ликвидаций - сколько запросов к контракту можно будет вместить в 1 блок?)
(*) 8. Если вызвать ликвидацию, но она не сработала - потерялось кол-во на транзакци. Вычитать это из "потенциальной" прибыли за ликвидацию?
Т.е. может получиться, что второй раз вызывать ликвидацию не будем - т.к. это стало невыгодно?
9. Возможность для ликвидаций с низким нонсом ставить газ повыше.
Отслеживать если кто-то уже ликвиднул "нашу" позицию - сделать отмену (замещающую тразу)
Модуль мониторинга цен
+/- 1. Обновление цен по таймеру (настраиваемый интервал)
+/- 2. Составление/хранение списка цен, которые нужно обновлять
(*) 3. Возможность запросить у АПИ сразу несколько цен
(*) 4. Цены могут быть подтянуты из АПИ, если нет - то откуда? Из Сабграфа? Из DEX?
Доп вопросы
1. Пункты со (*) требуют обсуждения
6. Способ обойти "каскад" ликвидаций
9. Perpetual positions ?
11. Как выиграть гонку с другими скрипатми