Imagine: your dApp accepts subscriptions, and every second a user's balance changes without extra transactions. Superfluid makes this possible, unlocking a new UX level for DeFi services, grants, and salary streams. We professionally integrate streaming payments into your application — from a simple funnel to a complex system with ACL and liquidation monitoring. Let's break down how this works under the hood and why Superfluid reduces transaction count by 1000x compared to traditional subscriptions. In our practice, there was a project where integration cut gas costs by 40% compared to a scheduled transaction approach.
Why streaming payments are more beneficial than the traditional approach?
The traditional approach to periodic payments in Web3 — approve + transferFrom on schedule, or prepayment for several periods. Both options require either active user participation or trusting the contract to hold large amounts upfront. Superfluid solves this differently: money flows per-second, balance updates in real time without separate transactions. For subscription dApps, salary streaming, or grant distribution — this is a significant UX difference.
| Aspect | Traditional approach | Superfluid |
|---|---|---|
| Transaction frequency | Each payment = one tx | One tx to open/close stream |
| Funds lockup | Full amount for the period | Only solvency buffer (4 hours) |
| Flexibility | Requires contract changes | Instant flowRate adjustment |
| Risks | Allowance overflow, gas spikes | Liquidation if funds insufficient |
Superfluid reduces the number of transactions by 1000x compared to traditional subscriptions, and gas costs by 3-5x per unit of time.
How does Superfluid update balance without transactions?
Super Tokens and real time
Superfluid doesn't work with regular ERC-20. You need a Super Token — an overlay over ERC-20 via the upgrade() function. A user deposits 100 USDC → receives 100 USDCx (Super Token). USDCx is an ERC-20 that can stream.
balanceOf(address account) in Super Token returns the real value considering all active streams: staticBalance + netFlowRate * (block.timestamp - lastUpdated). This is a view function that looks into the future and past simultaneously. No on-chain records every second — only updates when a stream is opened/closed/changed.
Practical consequence: balance changes every second without transactions. This means transfer(recipient, amount) with an amount of "full balance" is dangerous: between your calculation of the amount and execution of the transaction, time has passed, the actual balance has decreased.
CFAv1 (Constant Flow Agreement)
The main tool is IConstantFlowAgreementV1. Open a stream:
ISuperfluid(host).callAgreement(
cfa,
abi.encodeWithSelector(
cfa.createFlow.selector,
token, // USDCx
receiver, // address of receiver
flowRate, // wei per second (int96)
new bytes(0) // userData
),
"0x"
);
flowRate is int96, not uint256. A negative value means an incoming stream. To calculate flowRate: monthlyAmount * 1e18 / (30 * 24 * 3600) — amount of wei USDCx per second.
Important nuance: int96 is limited to ~39.6 * 10^27 wei/sec. For most use cases it's safe, but when working with tokens with non-standard decimals, check for overflow.
Liquidation and solvency buffer
Superfluid protects recipients from the situation where the sender runs out of funds through a liquidation mechanism. When opening a stream, the sender deposits a solvency buffer — usually 4 hours of stream. If the balance drops to zero but the stream is not closed, anyone can call liquidation via deleteFlow, receiving part of the buffer as a reward.
This changes UX requirements: when integrating into a dApp, you need to warn the user about the minimum required balance. If a user has USDCx for 3 hours of stream, they cannot open a new stream (buffer = 4 hours). This is a common cause of confusing INSUFFICIENT_BALANCE errors.
What risks arise when integrating streaming payments?
The main risks are incorrect buffer calculation, neglecting liquidations, and lack of event monitoring. For example, a subscription dApp without monitoring FlowDeleted from liquidations — users continued to receive content after the subscription ended because the frontend didn't know the stream was liquidated. Solution: event listener + status check via cfa.getFlow(). Also risk: error in calculating flowRate due to differences in decimals: USDC has 6, USDCx has 18. We always test contracts on a mainnet fork before deployment.
How to ensure stable operation of Superfluid?
Superfluid SDK
import { Framework } from "@superfluid-finance/sdk-core";
import { ethers } from "ethers";
const sf = await Framework.create({
chainId: 137, // Polygon
provider,
});
const usdcx = await sf.loadSuperToken("USDCx");
const createFlowOperation = usdcx.createFlow({
sender: userAddress,
receiver: recipientAddress,
flowRate: "385802469135802", // ~1000 USDC/month
});
const tx = await createFlowOperation.exec(signer);
SDK abstracts the callAgreement calls. For production code — use batchCall to combine multiple operations into one transaction: upgrade + createFlow in one gas.
Handling protocol events
Key events for monitoring:
-
FlowCreated(token, sender, receiver, flowRate, totalSenderFlowRate, totalReceiverFlowRate)— new stream -
FlowUpdated(...)— rate change -
FlowDeleted(...)— stream closure (including liquidations)
For frontend real-time updates: WebSocket subscription via wagmi watchContractEvent or The Graph subscription (if Superfluid subgraph is deployed for your network). Superfluid has an official subgraph on mainnet, Polygon, Optimism, Arbitrum, BNB Chain.
Real case: a subscription dApp without monitoring FlowDeleted from liquidations — users continued to receive content after the subscription ended because the frontend didn't know the stream was liquidated. Solution: event listener + status check via cfa.getFlow().
Working with userData
createFlow accepts bytes userData — arbitrary data emitted in the event. We use it for:
- Binding a stream to a subscription ID
- Passing a referral code
- Identifying a tariff plan
bytes memory userData = abi.encode(subscriptionId, planId);
On the event handler side — decode:
const [subscriptionId, planId] = ethers.utils.defaultAbiCoder.decode(
["uint256", "uint256"],
event.userData
);
ACL (Access Control List) for automation
If you need a smart contract to manage streams on behalf of the user (e.g., automatic flowRate update on plan change), use Superfluid ACL:
// User grants permission to the contract
cfa.authorizeFlowOperatorWithFullControl(token, operatorContract, "0x");
This is analogous to ERC-20 approve, but for stream management. The operator can create, modify, and close streams on behalf of the user within the granted permissions.
Supported networks and tokens
| Network | USDCx | ETHx | Native liquidity |
|---|---|---|---|
| Ethereum mainnet | Yes | Yes | Low (gas expensive) |
| Polygon | Yes | Yes | High |
| Optimism | Yes | Yes | Medium |
| Arbitrum One | Yes | Yes | Medium |
| BNB Chain | Yes | — | Medium |
For custom tokens: deploy a Pure Super Token (without wrapper, native super token) via SuperTokenFactory. Used for in-app currencies where no underlying ERC-20 is needed.
What is included in the work
We provide a full integration cycle:
- Use case analysis and network selection
- Smart contract development (if necessary)
- Superfluid SDK integration on the frontend
- Setup of event handlers and liquidation monitoring
- Testing on testnet and fork tests (Foundry)
- API documentation for frontend and deployment instructions
- Transfer of source code and access
- Guarantee of stable operation for 30 days after delivery
Process of work
Analytics (0.5-1 day). Determine use case: subscriptions, salary, grants, rewards streaming. Choose network. Do we need ACL for automatic stream management.
Development (2-4 days). Smart contract (if custom logic needed) + SDK integration on frontend + event handlers + liquidation monitoring.
Testing. Superfluid has testnets: Sepolia, Mumbai (deprecated). Fork tests with mainnet state via Foundry for complex business logic.
Time estimates
Basic integration (creating/managing streams on frontend) without custom smart contract — 2-3 days. Full subscription system with custom contract, ACL, and liquidation monitoring — 4-7 days.
Cost is calculated individually after analyzing the business logic. We estimate your project in 1 business day — contact us for a consultation. Our engineers have 5+ years of experience in web development and have delivered 30+ Web3 projects.







