Developing Recurring Crypto Payment System
Cryptocurrency by nature doesn't support recurring payments: a blockchain transaction is always an explicit action by the initiator. You can't sign "withdraw USDC every month" the way you do with a bank card. Any subscription system in crypto is an architectural compromise between user convenience, security, and decentralization.
Two Fundamentally Different Approaches
Pull Payments via Smart Contract
User signs a transaction once, giving the contract right to withdraw tokens via approve. The contract initiates withdrawal on schedule through an external trigger (Keeper, Gelato Automation, Chainlink Automation).
Key vulnerability of this approach: unlimited approve is standard practice, but risky. If the contract is compromised — attacker withdraws everything. Modern alternative — EIP-2612 Permit (gasless approve with signature) with amount limit and expiration, or ERC-20 permit flow.
Second problem: Keeper must know when payment is due. Either an on-chain mapping subscriber → nextPaymentTimestamp or external scheduler. If Keeper crashed or didn't call the function on time — payment delays. No mechanism for "auto-withdraw at the right time" without external trigger.
Subscription contract storage:
subscriptions: mapping(address => Subscription)
struct Subscription {
uint256 amount;
uint256 interval; // seconds
uint256 nextPayment; // timestamp of next withdrawal
address token;
bool active;
}
Function charge(address subscriber) checks block.timestamp >= nextPayment, executes transferFrom, updates nextPayment. Called by Keeper network.
Custodial Approach
User deposits funds on a custodial account (wallet smart contract or centralized backend). Withdrawal is initiated by business logic on operator's side. Simpler to implement, works without Keeper infrastructure, but requires trust in the operator.
Hybrid: user deposits in non-custodial contract with ability to withdraw anytime, while operator can only withdraw fixed amount at fixed interval. Parameters are locked in the contract at subscription creation and can't be changed by the operator.
Integrating Gelato Automation
For a pull-payment system a reliable Keeper is needed. Gelato Automation (formerly Gelato Network) lets you set a condition and function to call, takes gas from deposit or via 1Balance.
Register the task:
const { taskId } = await automate.createTask({
execAddress: subscriptionContract.address,
execSelector: iface.getSighash("chargeAll"),
resolverAddress: resolverContract.address,
resolverData: iface.encodeFunctionData("checker"),
name: "Charge subscriptions",
});
Resolver contract is a view function returning (bool canExec, bytes calldata execPayload). Gelato calls it off-chain and if canExec = true, submits the transaction. Resolver can check if any subscriptions are due in the current block.
Gas problem with many subscriptions. chargeAll() in one transaction is an unbounded loop, classic gas griefing vector. With 1000 subscriptions the transaction hits block gas limit. Solution: batch with pagination, Keeper calls chargeBatch(uint256 offset, uint256 limit), or each subscription is a separate Gelato task.
Cancellation and Insufficient Balance Handling
User must be able to cancel subscription anytime. Contract: cancelSubscription() sets active = false. The approval on tokens remains — need to explicitly instruct user to do approve(subscriptionContract, 0) or implement this automatically in the cancellation function through IERC20.approve(address(this), 0) (but this only works if contract is the spender).
On insufficient balance transferFrom reverts and Keeper gets an error. Important: don't mark subscription as inactive automatically — could be temporary lack of funds. Correct: failure attempt counter, after N attempts — pause with notification via event.
Timeline
Basic recurring payment system (smart contract + Gelato Automation + basic frontend) — 5 business days. System with custom resolver, subscription management, multi-token support and monitoring — 7-10 days.
Cost is calculated after analyzing requirements for monetization model and target chains.







