March 9

Проигравший Хронос

Или как ломался time.fun руками умельцев

I. Справки?

Для начала наведем справки по нашему пострадавшему объекту.
Технически невероятных масштабов SocialFi гигант, позволяющий любому пользователю покупать "минуты", которые могут быть использованы в дальнейшем для диалога/звонка с создателем этих самых минут.

На момент 10 марта 2025 года, на площадке находятся такие ребята как toly (он же Анатолий Яковенко, он же co-founder Solana, он же "толя пампни мой мемкоин"), и разной степени прожарки твиттер-инфлюенсеры на уровне notjerome/raj/kash и прочие. Каждый кто хотел, уже зарекламировал это детище у себя в Twitter, но самая главная любовь пришла от... toly? По всей видимости парень действительно тащится от продукта.

На практике площадка оказалась просто очередным станком для создания местных мемкоинов, да еще каким. На момент вышеупомянутой даты, актив на этой площадке уже спал, и теперь там заведуют исключительно снайпера несмотря на попытки разработчиков защитить свое детище.

II. Ломать не строить

Признаюсь честно, мои намерения были явно не добрыми, а самаритянина и крипто-энтузиаста я никогда из себя не строил, несмотря на то, что эта сфера мне очень интересна и ее продукты в целом.

Когда я увидел в просторах интернета об этой площадке, я понял что здесь точно можно заработать, вопрос как? Ответ пришел практически моментально - снайпинг. Для этого нужны:

  • Нода с Geyser RPC, для мониторинга минта токенов
  • Сервер, не буду же я делать это все со своего компьютера
  • Навыки в солане, к счастью какими-никакими обзавелся

В процессе разбора площадки, я понял один факт - это будет не просто. Начнем с самого начала, кому интересно, следите за моим ходом мысли.

Спойлер: если вам не интересна техническая часть, пропускайте смело до III пункта, здесь будут закрыты окна и работающие батареи.

В первоначальной версии сайта, транзакция формировалась на клиенте, в дальнейшем почему-то отправлялась на подпись вашим же кошельком на сервер, и отправка этой же транзакции для подписания и бродкаста он-чейн.

После долгих копаний в обфусцированном коде сайта, в голову бросилось примерное понимание как формируется транзакция:

Обычный вызов функции из IDL через Anchor, ничего необычного. К слову, IDL хранилась почему-то прямо на сайте.

Дальше, формирование инструкции с газом и отправка как таковой транзакции. На решение этой проблемы было убито по меньшей мере часов 5, в дальнейшем проблемы только начинались. Их можно было бы избежать, но я решил действовать решительно, уверенно и безрассудно.

Отправка этой же транзакции в hex-формате на сервер для подписи вашим же кошельком, несмотря на то, что я мог просто достать свой же приватник и подписать им свою же транзакцию, минуя этот шаг.

И здесь появилась новая проблема, а именно - turnkey. Выяснилось - что я не мог отправить запрос просто так, для этого нужен был такой header как x-stamp.
По-сути, обычный JWT токен. Только этот JWT токен формировался из credentialBundle, который юзер получает при первом логине и формировании cookies, а так же внутренних ключей которые хранились в localStorage. Для этого использовались библиотеки hpke и прочие кодировочные штуки которые я просто скачал с самого сайта, но прослеживал каждую деталь если вдруг какая-то функция вызывается из другого куска кода которой нет в файле.

Самое, наверное, сложное для меня было осознать что timestamp который используется в формировании stamp'а и который отправляется в запросе должен быть одинаковый. Но

пацан ломался, пацан превозмогал

Дальше все вполне тривиально, получение salt для запроса и отправка транзакции в формате base64. К слову, тот процесс описанный выше почему-то принимал транзакцию именно в hex-формате, и отдавал данные в hex-формате с rsv, свойственным только EVM сетям. Почему так, непонятно.

И на этом моменте возможно у вас возник вопрос, почему транзакция формируется на стороне клиента? Логики в этом не было, и проглядывая solscan я заметил что кошелек который подписывает транзакции всем почему-то чрезвычайно пустоват, и недостающая деталь пазла пришла сама.

Человек что разобрал данный механизм раньше чем я, просто встроил функцию трансфера на свой же кошелек, а сервер неглядя ее подписал feePayer кошельком и отправил в он-чейн недры. В дальнейшем я решил воспроизвести эту атаку и украл целых 0.002 SOL, ведь вшить эту инструкцию было вопросом 5 строк кода :)

В дальнейшем данный эксплоит пофиксили, так как я заходил проверить если это работает, и пытался провести ряд экспериментов ради своей же выгоды, но по всей видимости они проверяли параметры pre/postTokenBalance параметры и выдавали ошибку: "Transaction is not safe for Fee Payer"

III. Не в бровь, а в глаз.

Как я уже упомянул ранее, для снайпинга токенов на этой платформе мне нужен был определнный инструментарий, которым я к своему счастью обладал. Далее все было очень просто

  1. Настройка GRPC на мониторинг новых токенов.
  2. Создание дочерних GRPC для мониторинга минта токена, так как токен покупался через адрес создателя, а не адрес самого токена.
  3. Покупка при первой возможности.

На моменте покупки возникали некоторые сложности, так как в один момент сайт начал формировать транзакции сам, и здесь хочешь не хочешь приходилось мириться с тем, какой газ проставит тебе сервер. Вопрос скорости - 3 блока, переводя на время - 0.8-1.2с.

Решался вопрос категорично, сначала спам, затем JITO bundles, так как в нынешних реалиях встроить JITO tip в транзакцию было невозможным. Результат был хорошим, я входил буквально первым обходя приличное кол-во снайперов. В один момент меня подкосила нода и ее скорость бродкаста транзакций, потому было принято решение покупать через JITO.

Продажа была ручной, так как некоторые монеты выходили очень даже прилично и нужно было понимать кто есть пришедший, и чего он может стоить в потенциале.

К сожалению, лыжи наметил не я один. Через два-три дня, на площадку повалило очень много снайперов, которые не хотели оставаться без прибыли. В этот момент я понял что нужно понемногу сворачивать удочки и уходить восвояси, покуда меня не прибили молотком.

IV. Недовольства

Народ бухтел, брыкался, но продолжал быть exit liquidity

В дискорде набралось крайне много недовольных на квадратный метр, жалуясь на снайперов провоцируя меня/и других коллег по цеху быть еще более свирепыми увеличивая кол-во аккаунтов и напор.

Изначальное решение которое предприняли наши товарищи девелоперы - отдавать транзакцию уже готовую. В дальнейшем они сменили метод отправлять покупку исключительно через запрос, формируя подпись и отправку у себя уже на сервере, что и прибило мое желание находиться на этой платформе в дальнейшем.

Борьба со снайперами штука жесткая, но ты никогда от них не избавишься находясь в он-чейн пространстве. Даже сейчас можно попытаться урвать кусок, для этого все так же нужна нода и прокси, чтобы отправлять много запросов в надежде попасть в число первых покупателей.

Они вырыли себе могилу, увеличивая кол-во лимита на аккаунт с 1000 до 2000 минут, а так же несуразными идеями и изменением изначальной логики сайта и формирования транзакций, так как там было действительно нелегко и не каждый бы залез в эту пучину. Создатели выходили все хуже, их попытки борьбы со снайперами не увенчивались успехами. На текущий момент, все минуты что выходят - снайпятся с максимальным энтузиазмом.

V. Итоги

Удалось забрать XXXXX$ чистой прибыли, посоревноваться и действительно подумать головой.

Но как и всегда:

Недолго музыка играла, недолго фраер танцевал

https://t.me/zer0_source