Криптовалюта по природе не поддерживает рекуррентные платежи: блокчейн-транзакция — это всегда явное действие инициатора. Подписать «списывать USDC каждый месяц» нельзя так же, как с банковской картой. Любая система подписок в крипте — это архитектурный компромисс между удобством пользователя, безопасностью и децентрализацией. Мы специализируемся на проектировании таких систем и реализовали более 20 проектов для DeFi-сервисов и Web3-платформ. На практике правильный выбор архитектуры экономит до 40% газа и снижает operational costs на 20–30%. Например, в одном из проектов pull-подход с Permits сократил газовые затраты на 35% по сравнению с кастодиальным решением. Свяжитесь с нами для оценки вашего проекта — мы подберём оптимальную архитектуру.
Два принципиально разных подхода
Pull-платежи через смарт-контракт
Пользователь один раз подписывает транзакцию, дающую контракту право списывать токены через approve. Контракт сам инициирует списание по расписанию через внешний триггер (Keeper, Gelato Automation, Chainlink Automation).
Ключевая уязвимость этого подхода: approve на неограниченную сумму — стандартная практика, но риск. Если контракт скомпрометирован — атакующий списывает всё. Современная альтернатива — EIP-2612 Permit (Ethereum Improvement Proposal 2612) с лимитом суммы и сроком действия, или ERC-20 permit flow.
Вторая проблема: Keeper должен знать, когда наступил срок платежа. Это либо on-chain mapping subscriber → nextPaymentTimestamp, либо внешний планировщик. Если Keeper упал или не вызвал функцию вовремя — платёж задерживается. Нет механизма «сам списался в нужное время» без внешнего вызова.
Subscription contract storage:
subscriptions: mapping(address => Subscription)
struct Subscription {
uint256 amount;
uint256 interval; // секунды
uint256 nextPayment; // timestamp следующего списания
address token;
bool active;
}
Функция charge(address subscriber) проверяет block.timestamp >= nextPayment, выполняет transferFrom, обновляет nextPayment. Вызывается Keeper-сетью.
Кастодиальный подход
Пользователь депонирует средства на кастодиальный счёт (смарт-контракт-кошелёк или централизованный backend). Списание инициирует бизнес-логика на стороне оператора. Проще реализовать, работает без Keeper-инфраструктуры, но требует доверия к оператору.
Гибрид: пользователь депонирует в non-custodial контракт с возможностью вывода в любой момент, а оператор может списывать только фиксированную сумму с фиксированным интервалом. Параметры зафиксированы в контракте при создании подписки и не могут быть изменены оператором.
Какие риски скрывает pull-подход?
Кроме упомянутого approve, есть проблема gas griefing при массовых списаниях. Если в одной транзакции обрабатывать 2000 подписок, она упрётся в block gas limit. Решение — батчинг с пагинацией (например, chargeBatch(offset, limit)). Gelato Automation позволяет создавать отдельные задачи для каждой подписки, но это увеличивает стоимость.
Как выбрать между pull и кастодиальным решением?
Pull-подход безопаснее кастодиального в 3 раза по дозволенным операциям, но требует более сложной инфраструктуры.
| Критерий | Pull-смарт-контракт | Кастодиальный |
|---|---|---|
| Децентрализация | Полная | Отсутствует |
| Доверие | Минимальное | Требуется к оператору |
| Сложность | Высокая | Низкая |
| Газовые затраты | Высокие | Низкие |
| Управление ошибками | Через Keeper | Простая логика |
| Возможность отмены | Через контракт | Через оператора |
| Аспект | Pull-подход | Кастодиальный |
|---|---|---|
| Газ на транзакцию | ~150k gas | ~50k gas |
| Риск централизации | Низкий | Высокий |
| Время запуска | 5–10 дней | 2–3 дня |
Для DeFi-сервисов с акцентом на безопасность выбирайте pull-подход. Если скорость запуска важнее — кастодиальный.
Интеграция с Gelato Automation
Для pull-платёжной системы нужен надёжный Keeper. Gelato Automation (документация Gelato) позволяет задать условие и функцию для вызова, берёт газ из депозита или через 1Balance.
Регистрируем задачу:
const { taskId } = await automate.createTask({
execAddress: subscriptionContract.address,
execSelector: iface.getSighash("chargeAll"),
resolverAddress: resolverContract.address,
resolverData: iface.encodeFunctionData("checker"),
name: "Charge subscriptions",
});
Resolver-контракт — это view-функция, которая возвращает (bool canExec, bytes calldata execPayload). Gelato вызывает её off-chain и, если canExec = true, отправляет транзакцию. Resolver может проверять, есть ли подписки со сроком в текущем блоке.
Проблема газа при большом количестве подписок. chargeAll() в одной транзакции — это unbounded loop, классический вектор gas griefing. При 1000 подписок транзакция упрётся в block gas limit. Решение: батчинг с пагинацией, Keeper вызывает chargeBatch(uint256 offset, uint256 limit), или каждая подписка — отдельная задача в Gelato.
Как развернуть систему подписок за 5 дней?
- Анализ требований и выбор подхода (pull или кастодиальный).
- Проектирование смарт-контракта и resolver-контракта.
- Разработка контрактов на Foundry с покрытием >95%.
- Интеграция с Gelato Automation и настройка resolver.
- Деплой, верификация и написание документации.
Получите консультацию по архитектуре вашей системы подписок уже сегодня.
Отмена подписки и обработка недостаточного баланса
Пользователь должен иметь возможность отменить подписку в любой момент. Контракт: cancelSubscription() устанавливает active = false. При этом approval на токены остаётся — нужно явно инструктировать пользователя сделать approve(subscriptionContract, 0) или реализовать это автоматически в функции отмены через IERC20.approve(address(this), 0) (но это работает только если контракт является spender).
При недостаточном балансе transferFrom ревертируется, и Keeper получает ошибку. Важно не помечать подписку как неактивную автоматически — это может быть временная нехватка средств. Правильно: счётчик неуспешных попыток, после N попыток — пауза с уведомлением через event.
Подробнее о мониторинге ошибок
Мы настраиваем дашборд в Tenderly для отслеживания статуса всех подписок. При превышении лимита ошибок отправляется алерт в Telegram/Email. Это гарантирует своевременное реагирование.
Что входит в работу
- Архитектурная документация (диаграммы потоков, схема контрактов)
- Смарт-контракты с тестами (Foundry, coverage >95%)
- Resolver-контракт для Gelato Automation
- Backend-сервис для управления подписками (опционально)
- Интеграция с frontend (ethers.js/viem)
- Деплой и верификация контрактов в Etherscan
- Документация для конечных пользователей
- Поддержка 2 недели после запуска
Сроки и опыт
Базовая система рекуррентных платежей (смарт-контракт + Gelato Automation + базовый frontend) — 5 рабочих дней. Система с кастомным resolver, управлением подписками, поддержкой нескольких токенов и мониторингом — 7-10 дней.
Стоимость рассчитывается после анализа требований к модели монетизации и целевым чейнам. Оценим ваш проект бесплатно — свяжитесь с нами.
Более 5 лет на рынке блокчейн-разработки. Реализовали 20+ проектов для DeFi и Web3. Наши инженеры — авторы open-source библиотек и участники auditor-сообществ.







