Ищем мемкойны на Stonfi в TON или есть ли жизнь за Notcoin

Криптовалюты

Мемкойны на пару с нфт одни из моих самых нелюбимых трендов крипты, никакой технологичности, один маркетинг. Но взрывной рост в 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]

Отсортировав получим(данные пока не обогащаю, чтобы не выглядело рекламой тех или иных токенов):

Адреса пулов, токенов и TVL

Визуально воспринимать информацию легче, поэтому построим график:

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))

Итог:

Сравните с предыдущей диаграммой и вы поймете масштаб Ноткойна в рамках TON

Как можно видеть по сравнению с другими токенами Notcoin огромен и его доминацию стоит учитывать при обзоре рынка мемкойнов TON.

Проблема ликвидности

Окей, допустим вы выбрали какой-то порог TVL, и посмотрели доминацию Notcoin, но дальше рассматривать TVL бесполезно. Малые пулы страдают проблемой ликвидности - в них просто мало свапов. И заблокированная в них ликвидность никак не позволяет их сравнить. 

Именно поэтому, аналитические платформы мемкойнов часто выглядит как live feed. Приложения сканируют блоки на предмет свапов в малых пулах. Это позволяет за минуту примерно увидеть какой мемкойн сейчас растет. Чтобы было понятнее как это выглядит, я собрал подобное для пулов Stonfi: https://tonhotshot.fun/

  1. Сначала сканируются пулы и находится самый крупный пул до 69к TVL - царь горы

  2. Далее каждый блок сканируется на транзакции в 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, которую разгоняют с помощью большого капитала без оглядки, а вообще зачем это нужно пользователю.

$NOT