Ви запустили SaaS на криптоплатежах. Клієнти хочуть платити USDC щомісяця, але не підписувати кожну транзакцію вручну. Ви шукаєте спосіб автоматизувати рекурентні списання без компромісу безпеки. За кілька років практики ми вирішили цю задачу для кількох проєктів: замовники економили до 30% газу на streaming порівняно з дискретними транзакціями, а користувацький досвід покращувався завдяки автоматизації. Нижче — технічна архітектура, яку можна взяти за основу. Оцінимо ваш проєкт безкоштовно — зв'яжіться з нами.
Блокчейн — push-система. Ніхто не може зняти кошти без підпису. Як організувати автоматичні виплати без постійної присутності користувача? Розглянемо моделі.
Яку архітектуру обрати для рекурентних виплат?
Pull-модель з аппрувом. Отримувач (або протокол) може зняти кошти сам, але тільки в рамках схваленого allowance. Це стандартна ERC-20 схема: користувач один раз робить approve(spender, amount), далі spender викликає transferFrom за розкладом. Використовуємо специфікацію ERC-20. Проблема — необмежений approve. Користувач апруває type(uint256).max, і якщо контракт скомпрометовано, всі кошти вразливі. Правильно: approve на конкретну суму + allowance скидається після кожної виплати.
Escrow з розкладом. Користувач вносить кошти в контракт-сховище, контракт виплачує за розкладом. Контроль у користувача зберігається через функцію паузи/скасування. Це більш безпечна архітектура — кошти заблоковані, але користувач знає точно, скільки і коли піде.
Потокова оплата (streaming). Протоколи Superfluid і Sablier реалізують безперервний потік токенів: кошти течуть посекундно, отримувач може забрати накопичене в будь-який момент. Особливо добре для зарплат, вестингу, орендних платежів. Газ знижується на 30% порівняно з дискретними транзакціями.
Архітектура контракту
Для кастомної системи періодичних виплат будуємо навколо кількох ключових елементів:
struct PaymentSchedule {
address payer;
address payee;
address token; // address(0) для ETH
uint256 amount; // сума за період
uint256 period; // в секундах
uint256 nextPaymentAt; // timestamp наступної виплати
uint256 maxPayments; // 0 = нескінченно
uint256 completedPayments;
bool active;
}
mapping(bytes32 => PaymentSchedule) public schedules;
Ключові функції:
-
createSchedule()— користувач створює підписку, перший платіж опціонально одразу -
processPayment(bytes32 scheduleId)— виконує чергову виплату (викликається keeper-ом) -
cancelSchedule()— користувач скасовує підписку -
pauseSchedule()/resumeSchedule()— тимчасова призупинка
Захист від double-spending. nextPaymentAt оновлюється перед переказом коштів (Check-Effects-Interactions). Додаємо paymentNonce — унікальний лічильник для кожної виплати, захист від replay в мультисіг сценаріях.
Як автоматизувати виклики контракту?
Контракт сам себе не викличе. Потрібен зовнішній тригер.
Chainlink Automation (колишній Keepers). Децентралізована мережа нод, яка моніторить умову і викликає контракт:
import "@chainlink/contracts/src/v0.8/automation/AutomationCompatible.sol";
contract RecurringPayments is AutomationCompatibleInterface {
function checkUpkeep(bytes calldata)
external view override
returns (bool upkeepNeeded, bytes memory performData)
{
bytes32[] memory dueSchedules = getDueSchedules(); // schedules з nextPaymentAt <= block.timestamp
upkeepNeeded = dueSchedules.length > 0;
performData = abi.encode(dueSchedules);
}
function performUpkeep(bytes calldata performData) external override {
bytes32[] memory scheduleIds = abi.decode(performData, (bytes32[]));
for (uint i = 0; i < scheduleIds.length; i++) {
_processPayment(scheduleIds[i]);
}
}
}
Chainlink Automation — надійний вибір для mainnet. Вартість — оплата LINK за кожен upkeep виклик плюс газ. Реєстрація upkeep займає кілька хвилин через веб-інтерфейс або програмно.
Чому варто використовувати Chainlink замість власного keeper?
Власний backend keeper централізований, але потребує постійного моніторингу та ризику збоїв. Chainlink забезпечує децентралізоване виконання та захист від цензури.Gelato Network. Альтернатива Chainlink Automation з більш гнучкими умовами тригера. Підтримує time-based та event-based тригери. Можна платити в ETH замість нативного токена.
Власний backend keeper. Для B2B рішень або коли потрібна повна кастомізація: backend моніторить контракт, викликає processPayment. Централізований, але простіший у налагодженні. Для enterprise-клієнтів часто кращий.
| Параметр | Chainlink Automation | Gelato | Backend keeper |
|---|---|---|---|
| Децентралізація | Так | Так | Ні |
| Оплата | LINK | ETH/токени | Інфра |
| Гнучкість тригерів | Середня | Висока | Повна |
| Надійність | Висока | Висока | Залежить від ops |
Управління лімітами та безпека
Ліміт суми за період. Користувач встановлює максимальний розмір разової виплати при створенні підписки. Спроба keeper-а викликати виплату з сумою вище ліміту — revert.
Часове вікно. Виплата вважається простроченою, якщо не виконана протягом graceWindow після nextPaymentAt. Якщо keeper не викликав функцію у вікні — виплата пропускається (або накопичується, залежить від бізнес-логіки).
Пауза при нестачі коштів. Якщо на escrow рахунку недостатньо токенів — замість revert контракт емітує подію InsufficientFunds і деактивує розклад. Keeper читає подію та надсилає сповіщення користувачеві (через backend + email/push).
Нативна валюта vs токени
ETH-виплати простіші в реалізації, але складніші в управлінні: користувач повинен тримати ETH в контракті. Токени (ERC-20) зручніші для stablecoin-платежів (USDC, DAI) — користувач апруває контракту тратити токени зі свого гаманця, сам тримає їх у себе. Для рекурентних B2C платежів (підписки) — рекомендуємо USDC на Polygon або Arbitrum. Низький газ, стабільна вартість, широка підтримка.
| Критерій | ETH/MATIC native | ERC-20 (USDC) |
|---|---|---|
| Складність | Простіше | Трохи складніше |
| Зберігання коштів | У контракті (escrow) | У користувача (approve) |
| Передбачуваність суми | Залежить від курсу | Стабільна (stablecoin) |
| UX для користувача | Гірше (треба поповнювати контракт) | Краще |
Процес розробки
Проєктування (1-2 дні). Визначаємо модель (pull/escrow/streaming), обираємо keeper, малюємо state machine для розкладу (active → paused → cancelled → completed).
Розробка контракту (4-6 днів). Пишемо на Solidity 0.8+, OpenZeppelin ReentrancyGuard, Pausable. Тести через Foundry — fuzzing граничних умов за часом особливо важливий.
Інтеграція keeper (1-2 дні). Реєстрація в Chainlink Automation або деплой Gelato task.
Backend та сповіщення (2-3 дні). Моніторинг подій контракту через ethers.js або viem, надсилання сповіщень користувачам.
Загальний термін — 1-2 тижні залежно від складності та кількості інтеграцій. Ми реалізували понад 20 подібних рішень — гарантуємо якість та безпеку. Замовте розробку системи рекурентних платежів — отримайте консультацію та оцінку термінів.







