TGViewer
Channel Public Channel
Понакодили

Понакодили

@nacodili

Тут про разработку и TON Blockchain

чат https://t.me/+_QDp3C7EktAyNzFi
Subscribers
118
Photos
1
Videos
1
Links
6
Recent Posts 13 shown
Post #13 67
Это, наверное, самый безобидный баг, но мерзкий. Проявляется он так: dApp вызывает кошелек для отправки транзакции. Обычно в это время открывается приложение кошелька, где надо транзакцию подтвердить. Но, допустим, пользователь не хочет этого делать. Тогда он может:
- нажать на кнопку «Отмена»;
- закрыть приложение кошелька целиком;
- закрыть всплывающее уведомление крестиком;
- закрыть всплывающее уведомление кликом на свободную область.

По идее, если пользователь отказался от действия, кошелек должен прислать об этом уведомление в dApp. Но почти все кошельки в ранних версиях могли ничего не прислать, если пользователь закрыл подтверждение не через кнопку «Отмена». Из-за этого в dApp бесконечно долго крутится лоадер в ожидании реакции пользователя.

№9 Пропуск подтверждений транзакций

Еще один безобидный, но мерзкий баг был в Tonkeeper. Иногда подтверждение транзакции из TON Connect не появлялось на экране, если приложение кошелька уже было открыто и активно. Приходилось сворачивать приложение, разворачивать снова, и только в этот момент кошелек проверял, не появилось ли чего-то нового в TON Connect. Этот баг очень легко поймать, когда активно отправляешь через dApp несколько транзакций подряд: приложение кошелька не закрывается и не уходит в фон, но и не отображает новые транзакции из TON Connect.

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

Когда я только пришел в TON, было ощущение в стиле «ну кошелек — он же работает с деньгами, должен быть надежным, как банк». Но реальность оказалась другой: везде есть баги, даже в кошельках.
  • ❤ 4
Post #12 53
Последние 4 года я занимаюсь проектами на TON. Я участвовал в разработке Getgems, Lost Dogs и Predict. Все эти проекты — dApp, через которые пользователь взаимодействует с блокчейном посредством TON Connect и своего кошелька. За время разработки я встречал множество разнообразных багов на стыке dApp, TON Connect и кошельков.

Почти все эти баги уже пофикшены в популярных кошельках (@wallet, Tonkeeper Keeper, MyTonWallet). Но новые кошельки периодически появляются, поэтому полезно знать, что может сломаться.

№1 Недостаточно денег

Проявляется баг так: у пользователя на балансе 1.001 GRAM, вы отправляете транзакцию на 1 GRAM, но в блокчейне транзакция упала с ошибкой на контракте кошелька. Это произошло, потому что кошельку не хватило GRAM на оплату комиссий блокчейна.
Кошельки не сразу научились точно рассчитывать, хватит ли GRAM на балансе с учетом всех комиссий или нет, и подписывали транзакцию «как есть». В итоге такая транзакция падала в блокчейне, а в UI пользователь бесконечно долго ждал подтверждения транзакции.
Сейчас кошельки умеют точно рассчитывать стоимость транзакции в GRAM и показывать человекочитаемую ошибку о нехватке средств, но для жетонов (USDT) такую проблему все еще можно встретить: если не хватает баланса жетонов, кошельки могут отправлять транзакции, которые упадут в блокчейне.

Чтобы сгладить проблему, приходится на стороне dApp проверять баланс пользователя и рисовать предупреждения. Перенести проверку баланса на сторону dApp полностью нельзя, потому что в кошельках бывают «gasless»-транзакции. Например, батарейка в Tonkeeper. В этом случае у пользователя на балансе нет GRAM вообще, а сторонний сервис пришлет чуть-чуть GRAM в момент совершения транзакции.

№2 Транзакция отправлена частично

Отправка двух сообщений за раз появилась в экосистеме TON не сразу, поэтому была желанным обновлением в кошельках. Из-за бага №1 бывали случаи, когда на отправку какого-то сообщения GRAM не хватало, и вместо двух сообщений с кошелька пользователя уходило только одно. Причем уйти могло любое сообщение: первое или второе. Например, в первом сообщении вы отправляли 5 GRAM, а во втором — 3 GRAM. Если у пользователя было только 4 GRAM на балансе, то первое сообщение не отправлялось вообще, а второе уходило. Но могло быть и по-другому: если на балансе 6 GRAM, то первое сообщение уходило, а на второе уже не хватало.

Для выставления NFT на продажу как раз надо два действия: деплой контракта продажи и передача NFT на этот контракт. Из-за этого бага бывали случаи, когда контракт продажи не создавался, а NFT на него отправлялась. Поэтому на Getgems для этого появился специальный контракт, который занимается выставлением NFT на продажу: он требует только одно сообщение с кошелька пользователя для выставления на продажу.

№3 Модификация транзакции

Этот баг несколько раз встречался в связке MyTonWallet + Ledger. Суть в том, что ранние версии Ledger (это такой аппаратный криптокошелек) не умели отправлять все типы транзакций. Они умели только простые переводы GRAM или переводы с текстовым комментарием. В TON Connect таких ограничений никогда не было.

Из-за этого получалась такая цепочка событий: dApp просит кошелек отправить 5 GRAM + текстовый комментарий + код контракта. MyTonWallet получает этот запрос, видит текстовый комментарий, думает, что все ок, и пересылает данные в Ledger. Код контракта где-то в этом месте теряется. В итоге мы имеем GRAM, которые лежат в блокчейне на незадеплоенном контракте (потому что код так и не прислали).

Этот баг я встретил, когда мы делали в Getgems офферы на NFT. Само собой, без кода контракта оффера фича не работала. Команда MyTonWallet пофиксила этот момент, но после этого похожий баг был с трансфером NFT. Для поддержки Ledger сообщение для трансфера пересобиралось на стороне кошелька, и иногда некоторые биты терялись.

Этот баг на стороне dApp никак не пофиксить. Благо таких проблем я не встречал уже давно.

№4 Дубли транзакций

Такое казалось невозможным, но случилось в кошельках @wallet и Tonkeeper. В @wallet это было так: dApp отправляет одну транзакцию в TON Connect, а с кошелька пользователя уходят две транзакции с разницей в пару секунд. В транзакциях разный seqno, то есть это клиентский код кошелька решил одно и то же отправить дважды. Насколько я понял, это был баг в UI, где пользователь успевал дважды кликнуть по кнопке. В Tonkeeper было чуть по-другому: пользователь делал разные транзакции в dApp, и иногда Tonkeeper из какого-то кеша доставал «старую» транзакцию и предлагал подписать ее вместо новой.

То есть пользователь хотел купить NFT и выставить эту NFT на продажу. dApp присылал две разные транзакции в TON Connect, а в итоге с кошелька уходили две транзакции на покупку NFT.

Этот баг на стороне dApp не пофиксить, но иногда можно пофиксить в контрактах. Например, контракт продажи NFT будет выбрасывать ошибку, если попытаться купить NFT дважды. К сожалению, такое поведение не везде можно реализовать.

№5 Баунс-флаг

Когда TON Connect только появился, он принимал адреса в raw-формате. В этом формате не было информации о bounce-флаге, поэтому кошелек «рассчитывал» значение этого флага самостоятельно. Логика была простая: кошелек смотрел в блокчейн, и если по этому адресу уже был контракт, то ставил баунс-флаг, а если контракта не было, то не ставил. Сейчас в TON Connect надо передавать адреса в friendly-формате, а значит (по идее) кошелек должен брать значение bounce из адреса.

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

Сейчас такой проблемы быть и не должно: адреса передаются в friendly-формате. «Подмену» баунс-флага можно ловить в коде контракта: если вы рассчитываете на bounce-флаг, можно вручную в коде контракта обрабатывать возвраты для входящих сообщений без этого флага.

После того как этот баг был обнаружен, во все контракты продаж Getgems добавили возможность вернуть застрявшие GRAM и жетоны с контракта.

№6 dApp не знает, что его отключили

В кошельках есть список подключенных dApp. В любой момент любой dApp можно отключить, и после этого транзакции от этого dApp не придут в кошелек, даже если он их отправит. Функция полезная, но проблема в том, что dApp не узнает, что вы его отключили. Обычно dApp — это просто сайт, открытый в браузере, и работает он, только пока открыт браузер. Как правило, факт подключения к кошельку хранится в самом браузере в localStorage. Когда вы отключаете dApp, кошелек отправляет сообщение «тебя отключили», но это сообщение некому обработать: браузер закрыт, и никакой код не исполняется. Когда вы откроете браузер снова, dApp прочитает данные из localStorage и будет думать, что он все еще подключен к кошельку, но никакие транзакции больше не будут отправляться в кошелек. Будет просто бесконечное ожидание подтверждения транзакции.

Если вы попробуете «протестировать» это поведение — отключить dApp в кошельке и сразу открыть его, — то увидите, что dApp отключился. Так происходит, потому что мост между кошельком и dApp умеет кешировать недоставленные сообщения на несколько минут. Но какой нормальный пользователь будет открывать dApp, который он только что отключил?

Кстати, команда @wallet пофиксила это в своем кошельке: они кешируют сообщения об отключении на несколько дней.

№7 Ничего не работает без VPN

Это классическая проблема многих сервисов в РФ. Исправить ее никак нельзя. Даже если ваш dApp открывается без VPN, это еще не значит, что TON Connect будет нормально работать. Для связи с кошельком используются мосты, которые могут быть недоступны без VPN. Проявляться это будет в виде бесконечной загрузки или бесконечно долгого ожидания подключения.

№8 Потерянные уведомления
  • 💘 1
Post #10 444
Primate impact is too high Этот баг ведёт к тому, что NFT нельзя купить и нельзя снять с продажи привычным методом – всё действия ловят ошибку в блокчейне. Можно сказать, что они заморожены в подпространстве.
Как я починил fragment

Просто пополнил баланс нфт на 0.005 GRAM. После этого нфт хватило денег на газ для стандартного завершения продажи.
"Чужую" нфт можно пополнить если отправить граммы без баунс флага или с комментарием "#topup"

Целый год пользователи страдали от забитой выдачи сломанными гифтами на фрагменте
  • 🤝 5
  • 👍 2
Post #9 445
Недавно прочитал новость про неслучайные сид-фразы: https://t.me/ctodaily/2117
И решил попробовать поискать TON-разработчиков, которые поленились нормально сгенерировать приватный ключ.

Моё предположение было такое: в библиотеке @ton/crypto есть функция keyPairFromSeed(seed), где seed — это Buffer длиной 32 байта.
Правильно этот сид надо создавать так getSecureRandomBytes(32). Но так будет возня байтами, куда-то их придется сохранить. В общем, делать хорошо — сложно.

А еще, можно написать как-то так:

const keyPair = keyPairFromSeed(await sha256('my_secret'));


Тут my_secret может быть любой строкой, а sha256 сделает из неё хеш длиной 32 байта — как раз то, что требует keyPairFromSeed.

Идея такая: берём популярные пароли, считаем от них sha256-хеш, создаём ключ из этого сида и смотрим, есть ли кошельки c такими ключами в блокчейне.

Найти популярные пароли оказалось проще всего: есть репозиторий https://github.com/danielmiessler/SecLists/tree/master/Passwords, там собрано примерно 56 миллионов паролей. Правда, лежат они в разных файлах, но это не большая проблема.

Дальше я начал думать, как проверить, существует ли кошелёк в блокчейне. Первой идеей было взять бесплатные ключи для tonapi, toncenter и подобных сервисов и просто проверять баланс адреса: если не ноль, то считаем, что кошелёк найден. Но при таком подходе скорость перебора была бы очень низкой.

К счастью, что у tonapi есть крутой сервис TON Analytics. Суть в том, что можно делать SQL-запросы в их базу данных. На текущий момент разрешено создавать запросы, которые отдают миллион строк за раз. В TON всего ~190 миллионов активных адресов, так что выгрузить их все не составило труда и обошлось мне примерно в $20.

Кроме самих адресов, у них есть ещё и отдельная таблица с публичными ключами — там оказалось примерно 50 миллионов ключей. Эта таблица существенно облегчает поиск, потому что не надо генерировать адрес TON-кошелька, а можно проверить сразу публичный ключ. Без неё пришлось бы сначала сгенерировать адреса кошельков для разных версий (v3, v5, hl_v2, hl_v3) и проверять каждый адрес отдельно.

Дальше я попросил Claude написать мне скрипт на Rust. На удивление, получилось с первого раза.

В итоге я проверил:

- 56 миллионов самых популярных паролей;
- unix timestamp с текущего момента до начала 2022 года (134 миллиона чисел);
- просто все числа от 0 до 10 миллионов.

И нашёл только два адреса:

1. EQD36D7ngLSsURYGsDhGzRGrMPPBLs2U2WLDP_THFPvQy6Np — тут приватный ключ создан из слова storm.
2. EQDEW3qkxdgj20mymJ6hPX8AafSzGmT_epYAnOmtuzt9lM6b — тут из строки 1.3.. Оказывается, этот кошелёк создавал я сам :)

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

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

Создавайте ключи правильно
  • 🔥 9
  • 👍 3
  • 🕊 1
Post #8 470
TON не любит нищих

TON сделан таким образом, чтобы вы не задавались вопросом: «Ой, а хватит ли мне денег?». У вас всегда должно быть чуть больше TON, чем вы хотите отправить.

В TON есть классная штука — комиссия за хранение (storage fee). По сути, это как платное место в iCloud, только вы платите за то, что ваш кошелек не удалился из блокчейна. Особая прелесть этой комиссии в том, что вы не знаете точно, сколько именно нужно заплатить. Это решается в момент создания транзакции: рассчитывается, сколько секунд назад было последнее списание комиссии за хранение, и эта сумма списывается с вашего баланса дополнительно к тому, что вы переводите.

Суммы там копеечные: обычный W5-кошелек тратит около 0.000022124 TON за неделю. Это всего 0.01 TON в год.

Интересное начинается, когда вы пытаетесь рассуждать как-то так: «Я хочу перевести 11.54 TON, у меня на балансе 11.540419277 TON. За газ с меня возьмут 0.000329268 TON. Я хочу добавить комментарий к переводу, значит, за action fee уйдет еще 0.000089964 TON. Последний раз storage fee я платил 20 минут назад — это еще 0.000000045 TON... Ой, пока я считал, прошла еще одна секунда, значит, storage fee стал больше!»

И вот мы получаем такую транзакцию
(посмотрите на Action Phase — Total actions: 1, Skipped actions: 1):

https://tonviewer.com/transaction/d8ef607419a3e635344f9d7e0b20d35fbd8a370aa7cd08157ac5df1b3a432eb7

Кошелек попытался отправить тоны, но тонов на комиссии не хватило. В итоге ничего не отправилось: вы просто заплатили комиссии за газ и хранение, но само действие не совершилось.

TON существует уже 5 лет, но эта ошибка все еще встречается в MyTonWallet.
По-хорошему, кошелек должен был рассчитать, что денег на транзакцию не хватит, и не давать её отправлять. Но рассчитать это сложно, потому что TON не любит нищих и не дает удобных инструментов для таких расчетов. MyTonWallet тут не одиноки, в Tonkeeper такая ошиба тоже была долгое время
  • 🔥 8
  • 🤯 2
Post #7 609
Сегодня я узнал, что в func нельзя написать много условий подряд, компилятор из @ton-community/func-js упадет с ошибкой:
Maximum call stack size exceeded
RangeError: Maximum call stack size exceeded


Зачем вообще такое писать

NFT устроены так, что внутри у них есть число — индекс. Он уникальный в рамках коллекции. Обычно индексы начинаются с нуля и идут по возрастанию: 0, 1, 2, 3 и так далее. Но только не в коллекциях gomining.

У них первый индекс в коллекции — 348903. Сомнительно, но ок: у ребят сквозная нумерация индексов на всех блокчейнах. Но это только начало. Далее примерно тысяча индексов идет последовательно с шагом в единицу до 350002, после чего идёт пропуск на 9 номеров — следующий индекс 350012. И таких пропусков — 863 штуки.

Всё было бы нормально, если бы такую коллекцию нужно было просто заминтить. Тогда никаких проблем нет — можно подставлять нужные индексы в нужные NFT, как это сделано, например, в коллекциях TON DNS или Telegram Usernames.

Но коллекции gomining должны были продаваться с ланчпада. Ланчпад — это лендинг с одной кнопкой «Купить NFT». Кнопка списывает у пользователя TON и минтит NFT на кошелёк. Весь процесс покупки и минтинга происходит полностью ончейн, вся логика зашита в смарт-контрактах.

В этой логике было очень удобно считать от нуля до максимального количества NFT и использовать этот счётчик как индекс NFT. Такой подход хорошо работал несколько лет для «обычных» коллекций, но на gomining всё сломалось.

Так я узнал что нельзя написать 863 условия подряд, контракт не соберется. Но можно разбить их по 200 штук и разнести по разным функциям, тогда будет работать

В итоге я сделал так:
https://tonviewer.com/EQCN7SkHxlSkRwXopX5iReUDuhCDaGyBevt6Bp3D2jZQU0gb?section=code
  • 🤯 5
  • 👍 2
  • 🤡 2
  • 😁 1
Post #6 1.02K
  • ❤ 7
  • 👍 5
  • 🔥 1
  • 💯 1
Post #4 957
Более 15,000 TON «застряло» в NFT, но владельцы коллекций могут их вернуть

Как это произошло?

При минтинге NFT на её баланс нужно положить небольшое количество TON — обычно около 0.05 TON. Из этой суммы часть уходит на оплату газа. Точную сумму, которая будет потрачена на газ, рассчитать сложно, поэтому обычно отправляют чуть больше, чем нужно, а контракт возвращает неиспользованный остаток.

Однако в эталонной реализации NFT-коллекции от Ton Foundation этот механизм возврата не был реализован. В результате при минтинге NFT часть неиспользованных TON осталась на балансе коллекций.

Я проанализировал блокчейн TON и нашёл 196 NFT-коллекций с балансом более 10 TON. Вот некоторые из них с самыми большими остатками:
X Empire Pre-Market — 2,581 TON
W-Coin Pre-Market — 1,243 TON
Age of Farm — 177 TON

Полный список коллекций собран в отдельном файле — там указаны названия, баланс в TON и адреса владельцев.

Как вернуть TON?

Для этого нужно быть владельцем коллекции и владеть хотя бы одной NFT из этой коллекции. Процесс возврата состоит из двух шагов:

1. Отправка запроса на минтинг нового итема с указанием индекса уже существующей NFT. Так как такая NFT уже есть, минтинг не произойдёт. В запросе также указывается количество TON, которое нужно перевести с баланса коллекции на баланс NFT-итема. Чтобы NFT-итем не вернул ошибку, передаётся пустая ячейка данных. Таким образом, TONы переносятся с баланса коллекции на баланс NFT.

2. Передача NFT самому себе. В стандартных контрактах есть механизм, который возвращает излишки TON обратно владельцу NFT во время трансфера.

Таким образом, TON сначала передаётся от коллекции к NFT, а затем от NFT — на ваш кошелёк. Чтобы упростить этот процесс, я сделал инструмент, который автоматически формирует все необходимые сообщения. Также я записал видео, где наглядно показал, как всё работает.

Если у вас не NFT, а SBT, схема остаётся такой же, но вместо передачи токена самому себе нужно отправить ему специальный op-код op::take_excess. Отправить его можно через этот инструмент.

Ставьте лайк, подписывайтесь на канал — буду публиковать ещё больше полезных вещей про TON-блокчейн
  • ❤ 10
  • 🐳 3
  • 👍 1
  • 🔥 1
Post #3
Channel photo updated
Post #2 600
Кто индексирует все новые NFT на TON?

TL;DR tonapi, tonscan, redoubt, getgems и еще три неизвестных сервиса, некоторые индексируют только сами нфт и пропускают коллекции

Почти все NFT в тоне хранят метаданные offчейн, это значит что внутри блокчена нет названия NFT, есть только ссылка на json файл.
Чтобы отобразить название, описание и картинку NFT, маркетплейсы и индексаторы скачивают эти json файлы. (вообще этим можно не заниматься и показывать просто адрес нфт)
Когда маркетплейс скачивает файл он делает HTTP запрос на сервер, такие запросы можно залогировать и посмотреть кто интересовался метадатой NFT.
Есть классный сервис -- webhook.site он дает вам url и логирует все запросы которые были на этот url. Я создал коллекцию из одной NFT чтобы посмотреть кто придет скачивать метаднные NFT и коллекции.

1.
2a01:4f9:3a:1491::2 HETZNER-AS, DE (AS24940) user-agent: Go-http-client/1.1
2a01:4f9:6b:488e::2 HETZNER-AS, DE (AS24940) user-agent: undici

Я думаю что это Tonapi, но точных пруфвов нет. По заголовкам поятно что это какой-то код на goalng и (видимо) какой-то скрипт на NodeJS, undici это популярная библиотека для http запросов на NodeJS

2.
16.63.46.215 AMAZON-02, US (AS16509) user-agent: python-httpx/0.27.0
16.62.75.29 AMAZON-02, US (AS16509) user-agent: python-httpx/0.27.0

tonscan, сенсуc показывает названия ssl серификатов, там упоминается tonscan. Два ip потому что dev и prod окружения

3.
44.210.191.88 AMAZON-AES, US (AS14618) user-agent: Python/3.8 aiohttp/3.9.5

redoubt, сенсус показывает что на этот ip резолвится хост graphql.redoubt.online

4.
3.68.116.9 AMAZON-02, US (AS16509) user-agent: Getgems/1.0
3.66.224.126 AMAZON-02, US (AS16509) user-agent: Getgems/1.0

getgems, не стесняются и пишут свое название в user-agent. Два ip потому что есть dev и prod версии индексера

5.
138.197.186.110 DIGITALOCEAN-ASN, US (AS14061) user-agent: Go-http-client/1.1

Нет никакой информации про этот ip.

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

6.
51.250.53.56 YANDEXCLOUD, RU (AS200350) user-agent: Go-http-client/1.1

Нет никакой информации про этот ip. Индексирует только нфт

7.
94.74.84.248 HWCLOUDS-AS-AP HUAWEI CLOUDS, HK (AS136907) user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36
Нет никакой информации про этот ip. Индексирует только нфт, претворяется браузером

Индексировать весь блокчейн запарно, хорошо что есть несколько команд, которые делают это независимо друг от друга
  • ❤ 2
  • 🔥 2
  • 👍 1
Post #1
Channel created

About this channel

How can I read @nacodili without a Telegram account?
TGViewer shows the public web preview Telegram publishes for Понакодили: recent posts, photos, videos and the subscriber count, with no app, login or account.
How many subscribers does Понакодили have?
Понакодили (@nacodili) has 118 subscribers on Telegram, refreshed roughly every 30 minutes.
Does Понакодили know I viewed it here?
No. Public channel previews carry no viewer identity, and TGViewer has no accounts or tracking of what you look up.
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →