Мемкойны на пару с нфт одни из моих самых нелюбимых трендов крипты, никакой технологичности, один маркетинг. Но взрывной рост в Q1 2024, привлекает внимание к нарративу мемкойнов. (По версии coingecko это самый прибыльный нарратив Q1 2024, но есть вопросы к методологии). Поэтому предлагаю попробовать, найти мемкойны на TON, попробовав собрать простенький дэшборд мемкойнов..
В статье я хочу разобрать, почему аналитические платформы мем койнов выглядят как live лента покупок этих самых мемкойнов. Пробежаться по новым API Stonfi, данные этой DEX теперь отображаются на Dexscreener, и под это появились отдельные открытые API, что сильно влияет на доступность данных(а это проблема в TON) И третье, посмотреть некоторые свои статистические гипотезы относительно пулов..
Что будем искать?
Если погуглить определение мемкойнов, то определения будут разница от пирамид нашего времени, до цифровой мем валюты, нового слова в сфере social tech.Поэтому в рамках этой статьи я предлагаю свое определение: Мемкойн это динамично растущий токен без изначального утилити, использующий механизмы Fomo для обеспечения роста. Данное определение дает мне возможность сформулировать гипотезу: Мемкойны это быстрорастущие малые проекты, а значит можно сначала отрезать крупные проекты по объему их пулов(Total Value Locked), а далее рассмотреть маленькие проекты по количеству свапов за последний, например, день.
Строим диаграмму TVL для пулов Stonfi - ищем порог за которым мемкойны
Начнем с TVL. У Stonfi есть две API v1/pools - возвращающий текущее состояние пулов и v1/stats/pools - статистика по пулам за период. Воспользуемся v1/pools, нам нужен адрес пула, адреса токенов из которых состоит пул и lp_total_supply_usd - общее предложение lp токенов пула. Lp токены это автоматически генерируемые DEX и начисляемые провайдеру ликвидности за внесения активов в пул ликвидности. Эти токены представляют собой долю комиссий, заработанных пулом ликвидности. Соответственно их предложение в долларовом эквиваленте будет отражать TVL.
import requests
r = requests.get('https://api.ston.fi/v1/pools')
result = r.json()['pool_list']
# упомянуть что есть еще но грузит там долго
# возьмем нужные нам поля #замечу tvl храниться строкой - надо менят ь
temp_pool_list = [{'pool_address': pool['address'], 'token0_address': pool['token0_address'], 'token1_address': pool['token1_address'], 'tvl': round(float(pool['lp_total_supply_usd']),2)} for pool in result]
# Отсортируем
sorted_pool_list = sorted(temp_pool_list, key=lambda d: d['tvl'],reverse=True)
sorted_pool_list[0:5]
Отсортировав получим(данные пока не обогащаю, чтобы не выглядело рекламой тех или иных токенов):
Визуально воспринимать информацию легче, поэтому построим график:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
pool_addresses = [d['pool_address'][-4:] for d in sorted_pool_list]
tvl_values = [d['tvl'] for d in sorted_pool_list]
plt.bar(pool_addresses, tvl_values, color='skyblue',log=True)
plt.xlabel('Pool Address')
plt.ylabel('TVL')
plt.title('TVL for Pools')
plt.xticks(color='w')
plt.tight_layout()
Результат:
Из графика хорошо видно, что первые пару пулов перекрывают по объему все остальные, также видно, что бывают плато, и объем залоченных средств хорошо позволяет классифицировать токены по неким лигам,от мелочи до просто огромных пулов.
Чтобы поиграться с гипотезами сделаем круговую диаграмму, разбив все пулы неким порогом, а количество пулов вынесем в название, тогда будет очень хорошо видно, например, что первые три пула по объему, содержат в себе больше половины залоченной ликвидности.
threshold = 10000000
big_pools = sum(item['tvl'] for item in sorted_pool_list if item['tvl']>=threshold)
small_pools = sum(item['tvl'] for item in sorted_pool_list if item['tvl']<threshold)
big_pools_count = len([item['tvl'] for item in sorted_pool_list if item['tvl']>=threshold])
small_pools_count = len([item['tvl'] for item in sorted_pool_list if item['tvl']<threshold])
labels = 'Big pools', 'Small pools'
sizes = [big_pools, small_pools]
fig, ax = plt.subplots()
ax.pie(sizes, labels=labels)
ax.set_title("Big pools count:{}, Small pools count {} ".format(big_pools_count,small_pools_count))
Получим следующую диаграмму:
На блокчейне Solana есть лаунчапад pump fun, в нем заложено ограничение на 69к долларов, т.е. вы можете запустить свой токен, но как только он вырастет выше 69к долларов он “уйдет” на крупную биржу, попробуем такой порог:
Но и здесь не без нюансов, пулы могут содержать в себе пары любых жеттонов(стандарт токенов на ТОН) или ТОН. Но в большинстве своем это пулы:
жеттон - TON
жеттон - стейблкойн
жеттон - Notcoin
Notcoin можно назвать самым крупным мемкойном TON’а, поэтому наш простой дэшборд стоит начать с доминации Notcoin. Проверим диаграммой:
Notcoin = 'EQAvlWFDxGF2lXm67y4yzC17wYKD9A0guwPkMs1gOsM__NOT'
not_pools = sum(item['tvl'] for item in sorted_pool_list if item['token0_address']==Notcoin or item['token1_address']==Notcoin )
notnot_pools = sum(item['tvl'] for item in sorted_pool_list if item['token0_address']!=Notcoin or item['token1_address']!=Notcoin )
not_count = len([item['tvl'] for item in sorted_pool_list if item['token0_address']==Notcoin or item['token1_address']==Notcoin])
notnot_count = len([item['tvl'] for item in sorted_pool_list if item['token0_address']!=Notcoin or item['token1_address']!=Notcoin])
# посчитать кол-во и вывести в название
labels = 'Notcoin pools', 'Other pools count'
sizes = [not_pools, notnot_pools]
fig, ax = plt.subplots()
ax.pie(sizes, labels=labels)
ax.set_title("Notcoin pools count:{}, Other pools count {} ".format(not_count,notnot_count))
Итог:
Как можно видеть по сравнению с другими токенами Notcoin огромен и его доминацию стоит учитывать при обзоре рынка мемкойнов TON.
Проблема ликвидности
Окей, допустим вы выбрали какой-то порог TVL, и посмотрели доминацию Notcoin, но дальше рассматривать TVL бесполезно. Малые пулы страдают проблемой ликвидности - в них просто мало свапов. И заблокированная в них ликвидность никак не позволяет их сравнить.
Именно поэтому, аналитические платформы мемкойнов часто выглядит как live feed. Приложения сканируют блоки на предмет свапов в малых пулах. Это позволяет за минуту примерно увидеть какой мемкойн сейчас растет. Чтобы было понятнее как это выглядит, я собрал подобное для пулов Stonfi: https://tonhotshot.fun/
Сначала сканируются пулы и находится самый крупный пул до 69к TVL - царь горы
Далее каждый блок сканируется на транзакции в Stonfi в пулах до 69к.
Причем данные беруться из общедоступных API Stonfi о которых я упоминал ранее. Попробуем построить свой дэшборд на этих данных.
Ранжируем мемкойны на Stonfi
Данные о свапах мы будем брать из нового API созданного под Dexscreener, это API событий(export/dexscreener/v1/events). Данное API отдает все события DEX Stonfi между двумя блоками. Пускай для нашего дэшборда мы выберем период в день, где же нам взять текущий блок от которого оттолкнуться? Здесь два варианта:
Первый вариант, воспользоваться соседней ручкой export/dexscreener/v1/latest-block, она вернет последний блок обработанный бэкендом биржи, которая индексирует блокчейн и позволяет нам получить данные в агрегированном виде. Плюс данного подхода, что мы получим последний обработанный индексатором блок, минус то, что ручка отрабатывает в среднем 10 секунд и это не всегда удобно.
ltb = requests.get('https://api.ston.fi/v1/screener/latest-block')
lastest_block = ltb.json()['block']['blockNumber']
Второй вариант, взять прост последний блок из блокчейна, да последний блок в блокчейне не равен последнему блоку обработанному индексатором биржи, но зато это быстро, один из вариантов как это сделать
# RPS 1 sec
ltb = requests.get('https://toncenter.com/api/v3/masterchainInfo')
return ltb.json()['last']['seqno']
Допустим мы возьмем все события, как убрать крупные блоки? Точно также как мы делали вначале - достать все пулы и убрать те, что нам не нужны:
def get_block_list(sorted_pool_list,threshold):
Notcoin = 'EQAvlWFDxGF2lXm67y4yzC17wYKD9A0guwPkMs1gOsM__NOT'
return [item['pool_address'] for item in sorted_pool_list if item['tvl']>=threshold or item['token0_address'] == Notcoin or item['token1_address'] == Notcoin]
Также сразу уберем пулы с ноткойном, так как мы ищем новые мемкойны.
После сбора событий, сразу посчитаем количество используя Counter:
def count_swap_events(sorted_pool_list,threshold):
blocker = get_block_list(sorted_pool_list,threshold)
ltb = requests.get('https://api.ston.fi/v1/screener/latest-block')
lastest_block = ltb.json()['block']['blockNumber']
start_block=lastest_block - int(86400/5) # TON "обновляет" блоки каждые 5 секунд в дне 86400 секунд
payload = {'fromBlock': start_block, 'toBlock': lastest_block}
r = requests.get('https://api.ston.fi/export/dexscreener/v1/events', params=payload)
count_arr=[]
for item in r.json()['events']:
if(item['eventType']=='swap'):
if(item["pairId"] not in blocker):
count_arr.append(item)
c = Counter()
for event in count_arr:
c[event["pairId"]] += 1
Чтобы зацепить еще пару ручек, обогатим наши данные используя только адрес пула, для этого с помощью /export/dexscreener/v1/pair/ достанем адреса токенов и с помощью /v1/assets/ достанем названия жетонов или TON.
def pool_pair(pool_addr):
p = requests.get('https://api.ston.fi/export/dexscreener/v1/pair/{}'.format(pool_addr))
try:
pair=p.json()['pool']
return jetton_name(pair['asset0Id']) +"-"+ jetton_name(pair['asset1Id'])
except:
return pool_addr
Здесь отмечу, что это просто туториал и весь код пишется максимально примитивно, чтобы вы могли прочитать его по диагонали. Обогатим наш Counter и отсортируем его:
def count_swap_events(sorted_pool_list,threshold):
blocker = get_block_list(sorted_pool_list,threshold)
ltb = requests.get('https://api.ston.fi/v1/screener/latest-block')
lastest_block = ltb.json()['block']['blockNumber']
start_block=lastest_block - int(86400/5) # TON "обновляет" блоки каждые 5 секунд в дне 86400 секунд
payload = {'fromBlock': start_block, 'toBlock': lastest_block}
r = requests.get('https://api.ston.fi/export/dexscreener/v1/events', params=payload)
count_arr=[]
for item in r.json()['events']:
if(item['eventType']=='swap'):
if(item["pairId"] not in blocker):
count_arr.append(item)
c = Counter()
for event in count_arr:
c[event["pairId"]] += 1
enriched_arr=[]
for pool in sorted(list(c.items()), key=lambda d: d[1],reverse=True)[0:30]:
enriched_arr.append({"pool": pool_pair(pool[0]),'24h_swaps':pool[1]})
return enriched_arr
Получим примерно следующее:
Конечно, можно много что улучшить, но предлагаю читателю самому дособирать дэшборд, все API Stonfi можно глянуть здесь - https://api.ston.fi/swagger-ui/
Заключение
Мне нравится блокчейн TON своей технической изящностью, как минимум это не очередная копия Ethereum, которую разгоняют с помощью большого капитала без оглядки, а вообще зачем это нужно пользователю. Если вы хотите узнать больше о блокчейне TON, у меня есть опенсорсные уроки, благодаря которым вы научитесь создавать полноценные приложения на TON.
https://github.com/romanovichim/TonFunClessons_ru
Новые туториалы и дата аналитику я кидаю сюда