setApprovalForAll — функція ERC-721 / ERC-1155, яка дає контракту або адресі загальний дозвіл переказувати кожен NFT чи токен певної колекції, що належить вашій адресі, — і нинішні, і майбутні. Один підпис, необмежений обсяг, жодного ліміту на окремий токен. На цьому тримається схема OpenSea «дозволив один раз — торгуєш багато разів», і саме цим користуються набори Inferno Drainer і Pink Drainer. У доларах це один із найдорожчих викликів функцій в історії Ethereum.

Навіщо потрібна setApprovalForAll

NFT-маркетплейси мають переказувати NFT від імені продавців, не вимагаючи окремої транзакції з дозволом для кожного виставленого лота. OpenSea, LooksRare, X2Y2, Blur — усі використовують setApprovalForAll, щоб контракт маркетплейсу міг переміщати NFT у момент продажу.

Для чесного використання це зручно. Але якщо контракт, якому ви дали дозвіл, виявиться шкідливим, один підпис обернеться катастрофою. На відміну від дозволів ERC-20, де є ліміт суми на токен, setApprovalForAll працює за принципом «так чи ні»: усе або нічого.

Як працює дрейнер

Фальшива сторінка мінту → користувач підключає гаманець → кнопка «Mint» просить setApprovalForAll для найціннішої NFT-колекції в гаманці → користувач підписує, не читаючи → зловмисник отримує право переказувати кожен NFT цієї колекції з цієї адреси.

Зазвичай зловмисник не поспішає. Іноді чекає, доки користувач докладе в гаманець більше NFT (здобич буде більшою). Іноді — ринкової події, яка приспить пильність. А іноді виводить одразу, якщо в гаманці є активи, прив'язані до часу, наприклад NFT у стейкінгу, які ось-ось розблокуються.

Як setApprovalForAll виглядає в гаманці

У полі функції транзакції буде написано «setApprovalForAll», і в неї два параметри: адреса «operator» (контракт, що отримує дозвіл) і логічне значення (true — надати, false — відкликати). Сучасні гаманці, як-от Rabby і MetaMask після 2024 року, показують це зрозуміло і часто попереджають, якщо адреса operator невідома.

Старіша прошивка апаратних гаманців показує «сиру» транзакцію з даними в шістнадцятковому вигляді. Прошивка Ledger Nano S Plus до 2024 року не розбирала setApprovalForAll у зрозумілий вигляд; Trezor Safe 3 і Safe 5 це вміють. Якщо апаратний гаманець показує вам незрозумілий шістнадцятковий код для незнайомого виклику, це тривожний сигнал: не підписуйте, оновіть прошивку й спробуйте знову.

Що захищає

Три правила, які працюють на практиці:

По-перше, давайте дозвіл лише тим маркетплейсам, якими справді користуєтеся. Якщо мінтите тільки на OpenSea, не давайте дозволу контракту LooksRare. Кожен непотрібний дозвіл — майбутня вразливість.

По-друге, після першої ж взаємодії з незнайомим контрактом відкликайте дозвіл. Якщо ви підключилися до нового dApp лише для того, щоб забрати ейрдроп, одразу після цього зайдіть на revoke.cash і видаліть дозвіл.

По-третє, розділяйте «торговий» гаманець і гаманець-«сейф». Цінні NFT тримайте на адресі, яка не видала жодного дозволу. Коли захочете виставити NFT на продаж, переведіть його на торгову адресу, виставте, а те, що не продалося, поверніть назад. Мороки більше, зате ціла категорія катастроф із setApprovalForAll вам більше не загрожує.

І ще одна звичка: раз на три місяці заходьте на revoke.cash, підключайте кожен свій гаманець і відкликайте всі дозволи, яких не впізнаєте або не пам'ятаєте, як видавали. Ця звичка окупиться повністю того єдиного разу, коли вона зупинить крадіжку.

Що почитати далі: EIP-2612 Permit, revoke.cash, Фішинг.