Recurring crypto payments system development

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
Recurring crypto payments system development
Medium
~5 business days
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1238
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1167
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    867
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1080
  • image_logo-advance_0.png
    B2B Advance company logo design
    563
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    829

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.