Розробка системи делістинга токенів
Делістинг токена — це видалення торговельної пари з біржи. Процес вимагає чіткої процедури: сповіщення користувачів, фінальний дедлайн торгівлі, дедлайн виведення та технічне закриття. Погано керований делістинг викликає втрату користувачами доступу до коштів або отримання їх із великою затримкою.
Причини делістинга
Технічні причини:
- Уразливість у смарт-контракті або протоколі
- Припинення роботи блокчейну / hard fork без підтримки
- Низький обсяг торгівлі (неліквідний ринок)
Compliance причини:
- Проект визнаний невідповідною цінною папір
- OFAC санкції проти команди або проекту
- Відмова команди надати обов'язкові розкриття
Комерційні причини:
- Провал проекту / команда кинула розробку
- Rug pull або exit scam
- Порушення умов листинг-договору
Процедура делістинга
T-30 днів: Внутрішнє рішення про делістинг
T-14 днів: Публічний анонс
├── Офіційна сторінка поддержки
├── Email всім власникам токена
├── Push сповіщення
└── Announcement banner в інтерфейсі
T-7 днів: Нагадування, заморозка нових депозитів
T-0: Зупинка торгів
├── Видалення всіх відкритих ордерів (return margin)
├── Закриття торговельної пари у matching engine
└── Фінальний анонс
T+30 днів: Дедлайн виведення
└── Сповіщення користувачів з балансами
T+60 днів: Примусова ліквідація залишків
└── Заморозка або конвертація залишків
Технічна реалізація
Ініціювання делістинга
class DelistingManager:
async def initiate_delisting(
self,
symbol: str,
reason: str,
admin_id: str,
urgent: bool = False
) -> DelistingPlan:
# Перевіряємо поточний стан
token_info = await self.db.get_token(symbol)
affected_users = await self.db.count_users_with_balance(symbol)
# Для срочного делістинга (security incident) — скорочені сроки
if urgent:
notice_days = 2
trading_stop_days = 3
withdrawal_days = 30
else:
notice_days = 14
trading_stop_days = 14
withdrawal_days = 60
plan = DelistingPlan(
symbol=symbol,
reason=reason,
affected_users=affected_users,
announced_at=datetime.utcnow(),
trading_stops_at=datetime.utcnow() + timedelta(days=notice_days),
deposits_stop_at=datetime.utcnow() + timedelta(days=notice_days - 7),
withdrawal_deadline=datetime.utcnow() + timedelta(days=notice_days + withdrawal_days),
initiated_by=admin_id
)
await self.db.save_delisting_plan(plan)
# Запускаємо сповіщення
await self.notification_service.announce_delisting(plan)
return plan
async def stop_trading(self, symbol: str):
"""Зупиняємо торги по символу"""
# Видаляємо всі відкриті ордери
open_orders = await self.db.get_open_orders_by_symbol(symbol)
for order in open_orders:
await self.matching_engine.cancel_order(order.id)
# Повертаємо зарезервовані кошти
await self.balance_service.release_reserved(order.user_id, order)
# Сповіщуємо користувача
await self.notify_order_cancelled(order, reason='delisting')
# Деактивуємо пару у matching engine
await self.matching_engine.disable_symbol(symbol)
# Зупиняємо депозити та новий вивід (старі виводи все ще працюють)
await self.db.update_token_status(symbol, 'delisting_in_progress')
logger.info(f"Trading stopped for {symbol}, {len(open_orders)} orders cancelled")
Примусова ліквідація після дедлайну
async def process_expired_delisting(self, symbol: str):
"""Обробка істекших балансів після дедлайну виведення"""
remaining_balances = await self.db.get_token_balances(symbol)
for user_id, amount in remaining_balances.items():
# Опції в залежності від політики:
action = await self.determine_action(user_id, symbol, amount)
if action == 'auto_convert':
# Конвертуємо в USDT за останньою ціною
last_price = await self.get_last_price(symbol)
usdt_amount = amount * last_price * Decimal('0.95') # 5% штраф
await self.balance_service.convert(user_id, symbol, 'USDT', usdt_amount)
elif action == 'freeze':
# Замораживаємо з можливістю ручного виведення через support
await self.db.freeze_balance(user_id, symbol, amount)
await self.send_final_notice(user_id, symbol, amount, action)
Комунікація з користувачами
Email сповіщення
def generate_delisting_email(plan: DelistingPlan, user: User) -> EmailContent:
user_balance = get_user_balance(user.id, plan.symbol)
return EmailContent(
subject=f"Важливо: {plan.symbol} буде делістирований з біржи",
body=f"""
Шановний {user.first_name},
Інформуємо вас про передбачуваний делістинг токена {plan.symbol}.
**Причина:** {plan.reason}
**Ключові дати:**
• Зупинка депозитів: {plan.deposits_stop_at.strftime('%d.%m.%Y')}
• Зупинка торгів: {plan.trading_stops_at.strftime('%d.%m.%Y')}
• Дедлайн виведення: {plan.withdrawal_deadline.strftime('%d.%m.%Y')}
**Ваш поточний баланс:** {user_balance} {plan.symbol}
**Рекомендуємо до {plan.trading_stops_at.strftime('%d.%m.%Y')}:**
1. Вивести {plan.symbol} на зовнішній гаманець, або
2. Обміняти на інший актив через торговельний терміналу
Після {plan.withdrawal_deadline.strftime('%d.%m.%Y')} залишки
будуть оброблені відповідно до нашої політики.
З повагою,
Команда біржі
"""
)
Делістинг — болісна процедура, але прозора комунікація та достатній строк виведення мінімізують шкоду користувачам і репутації біржі. Галузевий стандарт: мінімум 14 днів сповіщення для некритичних делістингів.







