Спалення токенів через продаж майже спорожнило пул ліквідності TENDRIL у BNB Chain

За даними CoinDesk, 4 листопада 2026 року спалення токенів, ініційоване ордером на продаж, майже спорожнило бік TENDRIL у пулі ліквідності TENDRIL у мережі BNB Chain. Унаслідок обміну з пулу було виведено майже 4,42 млн USDT. Чистий відтік за цією транзакцією виявився меншим — 555 670,538752928908475139 USDT, оскільки значна частина USDT надійшла до пулу ще до цієї самої транзакції. Як продаж запускає спалення токенів? Перед тим як залишок TENDRIL продавця потрапив до пулу ліквідності, було викликано контролер. О 16:02:45 UTC виклик transferFrom роутера ініціював продаж 39 053 180 124,060957132414461269 TENDRIL, що запустило логіку комісії та контролера. Перекази до основного пулу оподатковуються 30-відсотковим податком на продаж, крім випадків, коли вони надходять із двох налаштованих адрес — _poolControl і _markControl. Контракт, який виконував цю транзакцію, не підпадає під жодне з виключень. Спершу токен надсилає 11 715 954 037,218287139724338380 TENDRIL на _poolControl. Далі токен викликає функцію sellToken контролера, передаючи початкову суму продажу, а не лише суму податку. Цей виклик завершується до того, як токен зараховує до пулу залишкові 70%. Історичне трасування викликів показує послідовність: transferFrom, sellToken, controlburn і sync, після чого відбувається фінальний своп. Трасування опкодів контролера підтверджує, що він помножив початкову суму продажу на 2, щоб визначити точну кількість, яку згодом буде вилучено з пулу. Controlburn вилучає токени з пулу, не зменшуючи загальну пропозицію. Функція controlburn переказує TENDRIL з балансу пулу на адресу спалення, але не зменшує зафіксовану загальну пропозицію токена і не спалює токени постачальників ліквідності. Її перевірка дозволів вимагає, щоб викликач збігався з _poolControl. Після авторизації вона використовує _basicTransfer, щоб списати токени з балансу пулу та зарахувати їх на адресу спалення. Жодної авторизації пулу чи виведення ліквідності тут немає: контракт токена безпосередньо контролює власні записи балансу. Log 28 зафіксував вилучення 78 106 360 248,121914264828922538 TENDRIL, після чого в пулі залишилося лише 6 678 початкових одиниць. З урахуванням 18 знаків після коми в TENDRIL залишок становить лише 0,000000000000006678 TENDRIL. Це спалення не вилучало USDT одночасно. Майже всі баланси TENDRIL зникли, тоді як USDT у пулі залишився доступним для наступного обміну. Відмова від права власності не вимкнула цей шлях. У блоці 131653426 до інциденту owner() повертала нульову адресу. Однак controlburn перевіряє налаштований контролер, а не owner(), тому цей шлях доступу залишається чинним. Функція не відкрита для всіх: будь-який викликач не пройде перевірку авторизації. Скидання резервів дає змогу вивести майже весь USDT. Контролер викликає sync() одразу після знищення, фіксуючи баланс токена після спорожнення, ще до надходження решти токенів від продажу. Log 29 встановлює резерв на рівні 4 421 023,357469283419586501 USDT і 0,000000000000006678 TENDRIL. Після цього до пулу надходить 27 337 226 086,842669992690122889 TENDRIL. Фінальний своп виводить 4 421 023,357469283419586499 USDT, залишаючи лише 0,000000000000000002 USDT. Масштаб виводу пояснює формула постійного добутку. Якщо для ілюстрації знехтувати комісіями та округленням, вихід USDT можна обчислити так: резерв USDT помножити на вхідну кількість токенів, а потім поділити на суму резерву токенів і вхідної кількості токенів. Коли зафіксований резерв токенів близький до нуля, вхідна кількість домінує в знаменнику, і вихід наближається до всього резерву USDT. Щоправда, фінальна виведена сума цього разу не є чистою сумою, вилученою з пулу. Загальний відтік USDT сягнув 5 117 517,824288279504509510, тоді як загальний притік становив 4 561 847,285535350596034371. Різниця дає чистий відтік 555 670,538752928908475139 USDT. Код контракту та історична траєкторія дали змогу відтворити всю послідовність. Спалення токенів, спричинене цим продажем, було реконструйовано за допомогою перевіреного вихідного коду, історичних викликів, журналів подій і трасувань опкодів через оглядач блоків. Після повторної компіляції з Solidity v0.8.24+commit.e11b9ed9 з вимкненою оптимізацією виконуваний runtime-код за станом на блок 131653426 збігається з байткодом контракту, за винятком метаданих компілятора. Декодовані параметри спалення точно відповідають сумі, переказаній з пулу на адресу спалення. Цілочисельні операції також коректно відповідають сумі податку, залишку токенів для продажу та балансу резерву. Загальна пропозиція не змінюється між сусідніми блоками до і після транзакції. Успішна транзакція цієї події потрапила до блоку 131653427. Квитанції, перевірені через два публічні RPC-ендпоїнти BNB Chain, збіглися, а під час перегляду 6 листопада 2026 року потік USDT на рівні адрес був повністю узгодженим. Цю статтю підготовлено за допомогою штучного інтелекту та перевірено редакційною командою.