Разработка системы Permit2 (токен-апрувалы)

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка системы Permit2 (токен-апрувалы)
Средняя
~2-3 рабочих дня
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1221
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1163
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    855
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1056
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    828

Разработка системы Permit2 (токен-апрувалы)

Классический ERC-20 требует двух транзакций для любого взаимодействия с DeFi: approve() и затем transferFrom(). Это UX-проблема и проблема безопасности одновременно — бесконечные approve на сторонние протоколы стали причиной потери миллионов долларов при взломах (одобрили протокол, его взломали, атакующий дренировал все одобренные токены). EIP-2612 добавил permit() для подписанных апрувалов без транзакций, но поддерживают его не все токены. Permit2 от Uniswap решает оба вопроса на уровне единого контракта-хаба.

Как работает Permit2

Идея проста: пользователь один раз делает approve(Permit2Address, type(uint256).max) для каждого токена. После этого Permit2 контракт управляет разрешениями от его имени — но уже через подписанные off-chain сообщения, без дополнительных транзакций.

Два режима работы:

AllowanceTransfer — аналог стандартного ERC-20 approve, но через Permit2. Разрешение имеет expiration. Протокол запрашивает у пользователя подпись PermitSingle или PermitBatch, после чего может вызывать transferFrom через Permit2.

SignatureTransfer — одноразовый перевод по подписи. Нет постоянного разрешения — только конкретная транзакция, подписанная off-chain. Атомарна: если транзакция reverted — нonce отмечается как использованный, но перевод не происходит.

Интеграция в смарт-контракт

import {IPermit2} from "permit2/src/interfaces/IPermit2.sol";
import {ISignatureTransfer} from "permit2/src/interfaces/ISignatureTransfer.sol";

contract MyProtocol {
    IPermit2 public immutable permit2;
    
    constructor(address _permit2) {
        permit2 = IPermit2(_permit2);
    }
    
    // Принимаем токены через SignatureTransfer (разовый перевод)
    function deposit(
        uint256 amount,
        ISignatureTransfer.PermitTransferFrom memory permit,
        bytes calldata signature
    ) external {
        permit2.permitTransferFrom(
            permit,
            ISignatureTransfer.SignatureTransferDetails({
                to: address(this),
                requestedAmount: amount
            }),
            msg.sender,
            signature
        );
        
        // amount токенов уже у нас, продолжаем логику
        _processDeposit(msg.sender, amount);
    }
}

На стороне фронтенда (wagmi/viem):

import { signTypedData } from "wagmi/actions";

const permitData = {
  permitted: {
    token: tokenAddress,
    amount: parseEther("100"),
  },
  nonce: await getPermit2Nonce(userAddress),
  deadline: BigInt(Math.floor(Date.now() / 1000) + 3600), // 1 час
};

const signature = await signTypedData({
  domain: {
    name: "Permit2",
    chainId: 1,
    verifyingContract: PERMIT2_ADDRESS,
  },
  types: PERMIT_TRANSFER_FROM_TYPES,
  primaryType: "PermitTransferFrom",
  message: permitData,
});

// Отправляем в контракт depositData + signature

Управление nonce в SignatureTransfer

В отличие от стандартного EIP-2612, где nonce линейный (каждая подпись = следующий nonce), Permit2 использует bitmap-based nonce. Nonce — это 256-битное число, где wordPosition = nonce >> 8 и bitPosition = nonce & 0xFF. Это позволяет инвалидировать конкретные разрешения без необходимости использовать все предыдущие nonce по порядку.

Пользователь может отозвать конкретный pending nonce через:

permit2.invalidateUnorderedNonces(wordPosition, mask);

Это критически важно для UX: если пользователь подписал разрешение с длинным deadline, он может отозвать его без новой транзакции approve.

AllowanceTransfer: постоянные разрешения с expiration

// Проверяем и используем существующее AllowanceTransfer разрешение
function depositWithAllowance(address token, uint160 amount) external {
    permit2.transferFrom(msg.sender, address(this), amount, token);
    // Permit2 проверит: есть ли разрешение, не истёк ли срок, достаточно ли суммы
}

Преимущество перед стандартным transferFrom: разрешение автоматически истекает по expiration. Пользователь видит в интерфейсе Permit2: «вы одобрили X токенов до Y даты». Это прозрачнее бесконечного ERC-20 approve.

Типичные ошибки интеграции

Не проверять requestedAmount против фактически переданного. Если контракт принимает любой amount из permit, атакующий может передать permit на большую сумму, но вывести меньше — или наоборот, если логика некорректна.

Hardcoded Permit2 address. Permit2 задеплоен по одному адресу (0x000000000022D473030F116dDEE9F6B43aC78BA3) через CREATE2 на всех EVM-сетях. Используем как константу, не как constructor-параметр в production.

Не обрабатывать revert от permit2. Если signature недействительна или nonce уже использован — permit2 reverted. Убедиться, что контракт корректно пропагирует этот revert, а не маскирует его.

Процесс работы

Анализ. Определяем, какой режим нужен: AllowanceTransfer для протоколов с постоянным доступом к средствам, SignatureTransfer для атомарных операций. Чаще используем комбинацию.

Разработка. Интеграция в смарт-контракт + типы для typed data signing на фронтенде. Foundry-тесты с PermitSignature хелпером из permit2 репозитория.

Тестирование. Fork-тесты на mainnet с реальным Permit2 контрактом. Проверяем сценарии истёкшего deadline, использованного nonce, неверной подписи.

Ориентиры по срокам

Интеграция Permit2 в существующий контракт + фронтенд: 2-3 дня. Включает оба режима (AllowanceTransfer и SignatureTransfer), тесты, и UI для просмотра/отзыва разрешений.