Подпись без транзакции: как permit тихо отдаёт твои токены
Привычный способ дать приложению доступ к токенам — транзакция approve: кошелёк
показывает её, ты платишь газ и подтверждаешь. Но есть второй путь, который выглядит совсем иначе —
обычная «подпись сообщения». Это permit, и именно через него работает большая часть
современных дрейнеров.
Что такое permit
Permit — это расширение стандарта ERC-20 (описано в EIP-2612). Вместо отправки транзакции
ты подписываешь off-chain сообщение в формате EIP-712: «я разрешаю адресу spender
списывать до value моих токенов до момента deadline». Подпись не идёт в сеть
сама по себе и не стоит газа. Её забирает приложение (или атакующий) и позже предъявляет контракту токена,
вызывая функцию permit(...) — и твой allowance выставлен, как будто ты сделал approve.
Почему это тихо — и опасно
Транзакцию approve кошелёк показывает как действие с токеном: видно контракт, сумму, газ.
А permit приходит как «Подпишите сообщение» — ни газа, ни перевода, многие кошельки показывают его невзрачно.
Психологически «подписать» ощущается безобиднее, чем «отправить транзакцию», хотя по последствиям это то же
самое разрешение на твои токены.
Схема дрейнера. Сайт просит «подпись для входа» или «подтвердите кошелёк». Ты
подписываешь permit с value = максимум и spender = контракт атакующего.
Транзакции в этот момент нет — тревога не срабатывает. Через минуту атакующий вызывает permit(),
затем transferFrom и выводит токены. Ты «просто подписал сообщение».
Как читать, что ты подписываешь
EIP-712 показывает структурированные (typed) данные — не бессмысленный хеш, а поля. У permit смотри на них:
spender— кому даёшь доступ. Это знакомый контракт приложения или неизвестный адрес?value— сколько. Очень часто тут стоит «безлимит» (2^256-1) — красный флаг, если сайту нужна разовая операция.deadline— до когда действует. Далёкая дата = разрешение живёт долго.nonce— защита от повтора. Один permit = один nonce.- домен (
verifyingContract,chainId) — какой токен и какая сеть. Подпись, выпрошенная «для входа», обращаться к контракту токена не должна.
EIP-2612 и Permit2 — в чём разница
EIP-2612 — это permit, встроенный в сам токен. Работает только если токен его реализует: далеко не все ERC-20 это умеют.
Permit2 — отдельный контракт-посредник от Uniswap, который приносит permit-логику любому токену,
даже без нативного permit(). Один раз даёшь Permit2 обычный approve, а дальше
разрешения конкретным приложениям выдаёшь off-chain подписями с суммой и сроком. Удобно — но риск тот же:
первый approve к Permit2 часто безлимитный, а подпись Permit2 так же можно выманить фишингом.
Как защититься
- Не подписывай typed-data на незнакомых сайтах. «Подпись для входа» не должна трогать контракт токена.
- Читай поля: сверяй
spender,value(берегись безлимита) иdeadline. - Аппаратный кошелёк показывает поля permit на экране устройства — пользуйся этим.
- Регулярно проверяй и отзывай выданные разрешения на revoke.cash.
- В MetaMask запрос permit приходит как «Signature request» с типом
Permit— раскрывай детали, не жми вслепую.
Хочешь увидеть ловушку вживую? В нашем тренажёре есть учебный permit-дрейнер на testnet — подписываешь, смотришь, что происходит, и учишься говорить «нет».
- Источники: EIP-2612 · Uniswap Permit2 · revoke.cash