Subscription billing on-chain has a well-documented failure mode. A subscriber's wallet runs low. The pull payment fails. The subscription cancels. The subscriber is offboarded — not because they intended to cancel, but because their USDC balance was $2.00 short at 00:00 UTC on billing day.
This is involuntary churn. It is the single largest source of silent revenue loss in recurring crypto billing. And until now, the on-chain tooling to handle it simply did not exist.
AuthOnce introduces programmable grace periods as a first-class protocol primitive. This article explains how it works technically, and why it matters for any team building non-custodial USDC subscription billing on EVM chains.
The Root Problem: Blockchains Have No Native Retry Logic
Traditional payment processors implement dunning logic at the infrastructure layer. A failed charge triggers a retry schedule — typically at 3, 5, and 7 days after initial failure — with automatic subscriber communication and access management throughout.
Blockchains have none of this natively. A failed transaction is a failed transaction. There is no built-in scheduler, no retry queue, no grace state. The EVM executes or reverts. That is the full vocabulary.
Early crypto subscription protocols addressed this by pushing retry logic entirely off-chain. The problem: off-chain retry logic introduces custodial risk and centralization — the same structural vulnerabilities that make custodial billing unattractive in the first place. To understand why this distinction matters at a treasury level, see our article on the real cost of custodial billing for DAOs.
AuthOnce implements grace period logic at the contract level, enforced on-chain, with off-chain execution triggering handled by the Keeper.
The Four On-Chain Subscription States
AuthOnce's subscription lifecycle is defined by four discrete states, each enforced by SubscriptionVault.sol:
| State | Condition | Subscriber Access | Next Transition |
|---|---|---|---|
| Active | Permit valid, payments executing on schedule | Full access | → Grace (on failed pull) |
| Grace | Payment failed, within configured grace window | Maintained | → Active (retry succeeds) or Suspended (window expires) |
| Suspended | Grace period expired, no successful pull | Revoked | → Active (subscriber tops up + retry) or Cancelled |
| Cancelled | Permit revoked by subscriber or merchant | Revoked | Terminal state |
The grace period duration (1–30 days) is set by the merchant at subscription plan creation. It is stored in MerchantRegistry.sol and enforced by SubscriptionVault at execution time.
When executePull() fails due to insufficient balance, the Keeper records the failure timestamp on-chain and transitions the subscription to Grace state. No merchant intervention required. No off-chain database update. State is canonical and verifiable.
How It Connects to EIP-2612 Permit Authorization
Grace period logic works because AuthOnce's authorization model gives the protocol the right tools. Subscribers sign an EIP-2612 permit — an off-chain cryptographic authorization — during onboarding. This permit remains valid throughout the grace period. The Keeper retries executePull() against the same permit. If the subscriber's wallet balance recovers, the retry succeeds and the subscription returns to Active without any re-authorization step.
This is the architectural advantage of gasless permit authorization: the subscriber's original intent is cryptographically preserved for the duration of the permit's validity. A failed payment does not invalidate the authorization — only an explicit revocation does.
function executePull(address merchant, address subscriber) external {
Subscription storage sub = subscriptions[merchant][subscriber];
require(sub.status == Status.Active || sub.status == Status.Grace, "Invalid state");
bool success = _attemptTransfer(subscriber, merchant, sub.amount);
if (!success && sub.status == Status.Active) {
sub.status = Status.Grace;
sub.graceStart = block.timestamp;
emit GracePeriodInitiated(merchant, subscriber, block.timestamp);
}
if (!success && sub.status == Status.Grace) {
uint256 gracePeriod = merchantRegistry.getGracePeriod(merchant);
if (block.timestamp > sub.graceStart + gracePeriod) {
sub.status = Status.Suspended;
emit SubscriptionSuspended(merchant, subscriber);
}
}
if (success) {
sub.status = Status.Active;
sub.lastPull = block.timestamp;
emit PaymentExecuted(merchant, subscriber, sub.amount);
}
}
The Keeper: Execution Without Centralization
The Keeper is AuthOnce's off-chain execution layer. It monitors subscription schedules and triggers executePull() at each billing cycle and on retry attempts during grace periods.
Current Keeper architecture scales in three tiers: sequential execution up to 20 active merchants; 25 parallel workers up to 50 merchants; and Gelato Network or Chainlink Automation as the decentralized path beyond that. The Keeper is the only centralized component in the current architecture — and its decentralization is the explicit post-mainnet roadmap.
ERC-1271: AI Agent Compatibility
AuthOnce implements ERC-1271 for smart contract wallet signature verification. This means AI agents operating through smart contract wallets can authorize and manage subscriptions — including navigating grace period retries — natively. For a full treatment of this capability, see our article on AI agent payments and ERC-1271 support.
Why This Is a Protocol Primitive, Not a Feature
Programmable grace periods are infrastructure, not a product differentiator that can be toggled off. Any team building subscription protocols on EVM chains needs a defined answer to one question: what happens when a pull payment fails?
The options are: cancel immediately (high involuntary churn, poor subscriber experience); retry off-chain (custodial risk, centralization, no on-chain auditability); or encode grace logic at the contract level (trustless, verifiable, subscriber-friendly).
AuthOnce chose the third path. The contracts are open. The architecture is documented. Source is available on GitHub. Builders can read every line before integrating.
Configuring Grace Periods for Your Use Case
Merchants set grace period duration at plan creation via the AuthOnce merchant dashboard. The configurable range is 1–30 days. Recommended configurations by use case:
- SaaS tools (monthly billing): 7–14 days. Balances recovery time against access risk.
- DAO membership dues: 14–30 days. Member wallet balances fluctuate with market conditions. Extended grace reduces governance disruption.
- Creator platforms (weekly billing): 3–7 days. Shorter cycles need tighter windows.
- High-value B2B contracts: 14–30 days. Enterprise treasury operations may have deliberate settlement timing.
Grace period configuration is stored on-chain in MerchantRegistry.sol at plan creation. It cannot be retroactively changed for existing active subscriptions — only for new subscriber authorizations. This protects subscribers from unilateral merchant changes to agreed billing terms.
Contract Addresses
Base Sepolia Testnet (current):
SubscriptionVault: 0xeb068B47731261F7B4A5ae8535686D67D7f72321
MerchantRegistry: 0xAE681E431c353f5930dDFfBC74037d3f2afE3264
Mainnet deployment targeting Q3 2026. Contracts are frozen pre-audit. Audit status and compliance posture →
Ready to implement grace periods?
AuthOnce is live on Base Sepolia. Mainnet launches Q3 2026. Read the integration guide or start building now.