-
Notifications
You must be signed in to change notification settings - Fork 3
Описание протокола banker gateway
Шлюзы и банкер взаимодействуют между собой через протокол удалённого вызова процедур JSONRPC
поверх TCP-соединения ZeroMQ
.
-
Биржа - децентрализованная криптовалютная биржа как совокупность всех микросервисов (UI, API, Banker, Gateways) являющаяся надстройкой над целевым блокчейном
-
Целевой (Target) блокчейн - блокчейн, в котором выпускаются деривативы и происходит матчинг ордеров
-
Родительский (Native) блокчейн - внешний блокчейн, шлюз которого принимает транзакции на депозит и производит выплаты
Order есть сущность, хранящая пару транзакций (in и out) и некие метаданные ордера, доступ к которым шлюзы не должны иметь.
Order создается ТОЛЬКО банкером. Он создается в случаях:
- запрос из пользовательского интерфейса
"get_deposit_address"
- обнаружение транзакции в одном из блокчейнов
Order представлен в таблице банкера следующими полями:
далее все для наглядности будет описано как код python
from uuid import UUID
from time import time
from decimal import Decimal
pk: int
# Генерируется исключительно на стороне банкера, дабы избежать каши и коллизий.
order_id: UUID
# см. класс OrderType
# Разделение на Deposit и Withdraw необходимо (для статистики и понимания логики, ибо без них у нас не БИРЖА с торговлей деривативами, а простой обменник) и существует
# только внутри Банкера. Ни один шлюз не понимает, что он принимает - выводы или пополнения.
# определить тип можно по полю in_tx_coin:
# GATEWAY_PREFIX = "FINTEH"
# if GATEWAY_PREFIX in in_tx_coin:
# order_type = "Withdrawal"
# else:
# order_type = "Deposit"
order_type: int
# Предполагаю таблицу User, а это будет внешний ключ
user: int
# Становится True когда in_tx_status и out_tx_status имеют значение 3 (RECEIVED_AND_CONFIRMED)
comleted: bool = False
"""
in_-транзакция. Транзакция инициализированная юзером.
Первой всегда инициируется она
"""
# Валюта транзакции. Для депозитов 'COIN', для выводов 'FINTEH.COIN'
in_tx_coin: str
# Получатель транзакции. Для депозитов это горячий кошелек шлюза, для выводов это имя битшаровского аккаунта шлюза
in_tx_to: str
# отправитель транзакции.
# Для депозитов адрес кошелька юзера в блокчейне(в некоторых блокчейнах и реализациях шлюзов может быть пустым),
# для выводов - имя юзера в битшаре (или другом целевом блокчейне)
in_tx_from: str
# Хэшстринг из блокчейна в котором произошла транзакция
in_tx_hash: str
# Вещественное число (с примененным preсision)
in_tx_amount: Decimal
# см. class TxStatus
# Шлюз сам решает, когда наступило то или иное состояние,
# в зависимости от настроек шлюза(необходимого кол-ва подтверждений
in_tx_status: int
# Количество подтверждений
# Для блокчейнов с irreversible state предлагаю использовать 0 и 1 как ненаступивше и наступившее irreversible соответственно
in_tx_confirmations: int
in_tx_created_at: time() # время транслирования транзакции пользователем
in_tx_error: int = 0 # см. class TxError
"""
out_-транзакция. Транзакция инициализированная банкером, в ответ на in_транзакцию.
инизиализируется только при in_tx_status == TxStates.RECEIVED_AND_CONFIRMED
"""
# Валюта транзакции. Для депозитов 'FINTEH.COIN', для выводов 'COIN'
out_tx_coin: str
# Получатель транзакции.
# Для депозитов это имя юзера в битшаре (или в другом целевом чейне)
# для выводов 'это горячий кошелек шлюза,
out_tx_to: str
# отправитель транзакции.
# Для депозитов адрес кошелька в блокчейне(в некоторых блокчейнах и реализациях шлюзов может быть пустым),
# для выводов - имя юзера в битшаре (или другом целевом блокчейне)
out_tx_from: str
# Хэшстринг из блокчейна в котором произошла транзакция
out_tx_hash: str
# Вещественное число (с примененным preсision)
out_tx_amount: Decimal
# см. class TxStatus
# Шлюз сам решает, когда наступило то или иное состояние,
# в зависимости от настроек шлюза(необходимого кол-ва подтверждений
out_tx_status: int
# Количество подтверждений
# Для блокчейнов с irreversible state предлагаю использовать 0 и 1 как ненаступивше и наступившее irreversible соответственно
out_tx_confirmations: int
out_tx_created_at: time() # время транслирования транзакции пользователем
out_tx_error: int = 0 # см. class TxError
Опишем возможные значения order_type
from enum import Enum
class OrderType(Enum):
TRASH = 0
DEPOSIT = 1
WITHDRAWAL = 2
Опишем возможные значения out_tx_status и in_tx_status
from enum import Enum
class TxStates(Enum):
ERROR = 0
WAIT = 1
RECEIVED_NOT_CONFIRMED = 2
RECEIVED_AND_CONFIRMED = 3
Опишем возможные значения in_tx_error и out_tx_error
from enum import Enum
class TxError(Enum):
NO_ERROR = 0
UNKNOWN_ERROR = 1
... # TODO
Каждый шлюз ведет у себя внутренню таблицу, подобную этой, со своими нюансами(например, в битшаре также понадобится operation_id, в монеро sub-адреса и т.п.).
-
get_deposit_address
Банкер просит о депозитном адресе для пользователя. В случае с битшарой тупо отдается константа, с эфиром и т.п. генерятся адреса
from uuid import UUID
request = {
"jsonrpc": "2.0",
"method": "get_deposit_address",
"id": 666,
"params":
{
"order_id": UUID, #Если шлюз принял этот запрос изначально от пользователя, значит у него уже есть order_id
"user": "bitshares_name" # Имя пользователя на бирже. Пока наш целевой блокчейн - Битшара, то это битшаровское имя аккаунта
}
}
##################
response = {
"jsonrpc": "2.0",
"result": "finteh-account",
"id": 666
}
new_order
и update_order
Банкер уведомляет шлюз о новом ордере или об обновлении старого
request = {
'jsonrpc': "2.0",
"method": "new_order" or "update_order",
"id": 666,
"params":
# Если update_order, то кроме (order_id) присылаются только те поля, которые обновились
[
{
"order_id": ...,
"in_tx_to": ...,
"in_tx_from": ...,
"in_tx_coin": ...,
"in_tx_hash": "",
"in_tx_amount": ...,
"in_tx_status": ...,
"in_tx_created_at": ...,
"out_tx_to": ...,
}
]
}
##################
response = {"jsonrpc": "2.0",
"result": "ok",
"id": 666}
-
new_tx
Шлюз уведомляет банкер о новой транзакции и получает order_id.
request = {
"jsonrpc": "2.0",
"method": "new_tx",
"id": 666,
"params":
{
# Order id не будет, потому что в битшаре любой аккаунт
#может зайти через чужую морду, купить наши токены и попробовать вывести
# order_id создат и вернет банкер
"in_tx_to": ...,
"in_tx_from": ...,
"in_tx_coin": ...,
"in_tx_hash": "",
"in_tx_amount": ...,
"in_tx_status": ...,
"in_tx_created_at": ...,
"out_tx_to": ...,
}
}
##############
response = {"jsonrpc": "2.0",
"result": int, # order_id, который банкер присвоит ордеру
"id": 666}
-
update_order
Шлюз видит изменения в ордере и уведомляет об этом банкер
from uuid import UUID
request = {
"jsonrpc": "2.0",
"method": "update_order",
"id": 666,
"params":
{
"order_id": UUID,
"любые другие поля Order'a которые изменились": ...,
}
}
#####################
response = {"jsonrpc": "2.0",
"result": "ok",
"id": 666}
- Зачем нужна концепция deposit/withdrawal?
Нужно понимать, чем биржа (Exchange) отличается от обменника (Swap).
Swap не нужны такие понятия, ибо он ничего не эмитирует. Он просто меняет монеты, забирая комиссию и не имеет такой сущности как дериватив (фантик, ассет). Exchange они нужны как минимум для того, чтобы сделать быстро select * from orders where type='deposit', это пригодится для саппорта и бизнеса(аналитику будет нужна 100%). Потом будет проблематично поверх рабочей конструкции строить скрипты, которые выясняют что из транзакций депозит, что вывод, а что мусор. Проще добавить одно int-поле в БД сейчас.