How to manage a CFA flow
Create, update, and delete continuous token streams
Constant Flow Agreement (CFA) enables continuous token streams between accounts. When we talk about "streams" in Superfluid, we're referring to CFA flows.
Understanding Flowrates
Flowrates are measured in tokens per second. The SDK provides a utility to calculate flowrates:
import { calculateFlowrate } from "@sfpro/sdk/util"
import { parseEther } from "viem"
// Stream 100 tokens per month
const monthlyFlowrate = calculateFlowrate({
amountWei: parseEther("100"),
timeUnit: "month"
})
// Stream 1 token per day
const dailyFlowrate = calculateFlowrate({
amountWei: parseEther("1"),
timeUnit: "day"
})
// Stream 0.1 tokens per hour
const hourlyFlowrate = calculateFlowrate({
amountWei: parseEther("0.1"),
timeUnit: "hour"
})
Create a Flow
There are two ways to create a flow: setFlowrate
(recommended) and createFlow
.
Using setFlowrate (Recommended)
setFlowrate
is more versatile - it creates a new flow or updates an existing one:
import { useWriteCfaForwarder } from "@sfpro/sdk/hook"
import { calculateFlowrate } from "@sfpro/sdk/util"
import { parseEther } from "viem"
const superToken = "0x..." // USDCx address
const receiver = "0x..." // Recipient address
const flowrate = calculateFlowrate({
amountWei: parseEther("100"),
timeUnit: "month"
})
function CreateFlow() {
const { writeContract: setFlowrate } = useWriteCfaForwarder({
functionName: "setFlowrate",
args: [superToken, receiver, flowrate]
})
return (
<button onClick={() => setFlowrate?.()}>
Stream 100 tokens/month to {receiver}
</button>
)
}
import { cfaForwarderAbi, cfaForwarderAddress } from "@sfpro/sdk/abi"
import { calculateFlowrate } from "@sfpro/sdk/util"
import { createWalletClient, http, parseEther } from "viem"
import { mainnet } from "viem/chains"
import { privateKeyToAccount } from "viem/accounts"
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
const walletClient = createWalletClient({
account,
chain: mainnet,
transport: http()
})
const superToken = "0x..." // USDCx address
const receiver = "0x..." // Recipient address
const flowrate = calculateFlowrate({
amountWei: parseEther("100"),
timeUnit: "month"
})
async function createFlow() {
const hash = await walletClient.writeContract({
address: cfaForwarderAddress[mainnet.id],
abi: cfaForwarderAbi,
functionName: "setFlowrate",
args: [superToken, receiver, flowrate]
})
return hash
}
import { writeCfaForwarder } from "@sfpro/sdk/action"
import { calculateFlowrate } from "@sfpro/sdk/util"
import { createConfig } from "@wagmi/core"
import { createWalletClient, http, parseEther } from "viem"
import { mainnet } from "viem/chains"
import { privateKeyToAccount } from "viem/accounts"
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
const wagmiConfig = createConfig({
chains: [mainnet],
client({ chain }) {
return createWalletClient({
account,
chain,
transport: http(),
})
},
})
const superToken = "0x..." // USDCx address
const receiver = "0x..." // Recipient address
const flowrate = calculateFlowrate({
amountWei: parseEther("100"),
timeUnit: "month"
})
async function createFlow() {
const hash = await writeCfaForwarder(wagmiConfig, {
chainId: mainnet.id,
functionName: "setFlowrate",
args: [superToken, receiver, flowrate]
})
return hash
}
Using createFlow
createFlow
explicitly creates a new flow (fails if flow already exists):
import { useWriteCfaForwarder } from "@sfpro/sdk/hook"
import { calculateFlowrate } from "@sfpro/sdk/util"
import { parseEther } from "viem"
import { useAccount } from "wagmi"
const superToken = "0x..." // USDCx address
const receiver = "0x..." // Recipient address
const flowrate = calculateFlowrate({
amountWei: parseEther("100"),
timeUnit: "month"
})
function CreateNewFlow() {
const { address } = useAccount()
const { writeContract: createFlow } = useWriteCfaForwarder({
functionName: "createFlow",
args: [superToken, address!, receiver, flowrate, "0x"]
})
return (
<button onClick={() => createFlow?.()}>
Create new flow
</button>
)
}
import { cfaForwarderAbi, cfaForwarderAddress } from "@sfpro/sdk/abi"
import { calculateFlowrate } from "@sfpro/sdk/util"
import { createWalletClient, http, parseEther } from "viem"
import { mainnet } from "viem/chains"
import { privateKeyToAccount } from "viem/accounts"
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
const walletClient = createWalletClient({
account,
chain: mainnet,
transport: http()
})
const superToken = "0x..." // USDCx address
const receiver = "0x..." // Recipient address
const flowrate = calculateFlowrate({
amountWei: parseEther("100"),
timeUnit: "month"
})
async function createNewFlow() {
const hash = await walletClient.writeContract({
address: cfaForwarderAddress[mainnet.id],
abi: cfaForwarderAbi,
functionName: "createFlow",
args: [superToken, account.address, receiver, flowrate, "0x"]
})
return hash
}
import { writeCfaForwarder } from "@sfpro/sdk/action"
import { calculateFlowrate } from "@sfpro/sdk/util"
import { createConfig } from "@wagmi/core"
import { createWalletClient, http, parseEther } from "viem"
import { mainnet } from "viem/chains"
import { privateKeyToAccount } from "viem/accounts"
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
const wagmiConfig = createConfig({
chains: [mainnet],
client({ chain }) {
return createWalletClient({
account,
chain,
transport: http(),
})
},
})
const superToken = "0x..." // USDCx address
const receiver = "0x..." // Recipient address
const flowrate = calculateFlowrate({
amountWei: parseEther("100"),
timeUnit: "month"
})
async function createNewFlow() {
const hash = await writeCfaForwarder(wagmiConfig, {
chainId: mainnet.id,
functionName: "createFlow",
args: [superToken, account.address, receiver, flowrate, "0x"]
})
return hash
}
Update a Flow
To change the flowrate of an existing flow:
import { useWriteCfaForwarder } from "@sfpro/sdk/hook"
import { calculateFlowrate } from "@sfpro/sdk/util"
import { parseEther } from "viem"
import { useAccount } from "wagmi"
const superToken = "0x..." // USDCx address
const receiver = "0x..." // Recipient address
const newFlowrate = calculateFlowrate({
amountWei: parseEther("200"),
timeUnit: "month"
})
function UpdateFlow() {
const { address } = useAccount()
const { writeContract: updateFlow } = useWriteCfaForwarder({
functionName: "updateFlow",
args: [superToken, address!, receiver, newFlowrate, "0x"]
})
return (
<button onClick={() => updateFlow?.()}>
Update flow to 200 tokens/month
</button>
)
}
import { cfaForwarderAbi, cfaForwarderAddress } from "@sfpro/sdk/abi"
import { calculateFlowrate } from "@sfpro/sdk/util"
import { createWalletClient, http, parseEther } from "viem"
import { mainnet } from "viem/chains"
import { privateKeyToAccount } from "viem/accounts"
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
const walletClient = createWalletClient({
account,
chain: mainnet,
transport: http()
})
const superToken = "0x..." // USDCx address
const receiver = "0x..." // Recipient address
const newFlowrate = calculateFlowrate({
amountWei: parseEther("200"), // Increased to 200 tokens/month
timeUnit: "month"
})
async function updateFlow() {
const hash = await walletClient.writeContract({
address: cfaForwarderAddress[mainnet.id],
abi: cfaForwarderAbi,
functionName: "updateFlow",
args: [superToken, account.address, receiver, newFlowrate, "0x"]
})
return hash
}
import { writeCfaForwarder } from "@sfpro/sdk/action"
import { calculateFlowrate } from "@sfpro/sdk/util"
import { createConfig } from "@wagmi/core"
import { createWalletClient, http, parseEther } from "viem"
import { mainnet } from "viem/chains"
import { privateKeyToAccount } from "viem/accounts"
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
const wagmiConfig = createConfig({
chains: [mainnet],
client({ chain }) {
return createWalletClient({
account,
chain,
transport: http(),
})
},
})
const superToken = "0x..." // USDCx address
const receiver = "0x..." // Recipient address
const newFlowrate = calculateFlowrate({
amountWei: parseEther("200"),
timeUnit: "month"
})
async function updateFlow() {
const hash = await writeCfaForwarder(wagmiConfig, {
chainId: mainnet.id,
functionName: "updateFlow",
args: [superToken, account.address, receiver, newFlowrate, "0x"]
})
return hash
}
Delete a Flow
To stop a flow completely:
import { useWriteCfaForwarder } from "@sfpro/sdk/hook"
import { useAccount } from "wagmi"
const superToken = "0x..." // USDCx address
const receiver = "0x..." // Recipient address
function DeleteFlow() {
const { address } = useAccount()
const { writeContract: deleteFlow } = useWriteCfaForwarder({
functionName: "deleteFlow",
args: [superToken, address!, receiver, "0x"]
})
return (
<button onClick={() => deleteFlow?.()}>
Stop streaming
</button>
)
}
import { cfaForwarderAbi, cfaForwarderAddress } from "@sfpro/sdk/abi"
import { createWalletClient, http, parseEther } from "viem"
import { mainnet } from "viem/chains"
import { privateKeyToAccount } from "viem/accounts"
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
const walletClient = createWalletClient({
account,
chain: mainnet,
transport: http()
})
const superToken = "0x..." // USDCx address
const receiver = "0x..." // Recipient address
async function deleteFlow() {
const hash = await walletClient.writeContract({
address: cfaForwarderAddress[mainnet.id],
abi: cfaForwarderAbi,
functionName: "deleteFlow",
args: [superToken, account.address, receiver, "0x"]
})
return hash
}
import { writeCfaForwarder } from "@sfpro/sdk/action"
import { createConfig } from "@wagmi/core"
import { createWalletClient, http, parseEther } from "viem"
import { mainnet } from "viem/chains"
import { privateKeyToAccount } from "viem/accounts"
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
const wagmiConfig = createConfig({
chains: [mainnet],
client({ chain }) {
return createWalletClient({
account,
chain,
transport: http(),
})
},
})
const superToken = "0x..." // USDCx address
const receiver = "0x..." // Recipient address
async function deleteFlow() {
const hash = await writeCfaForwarder(wagmiConfig, {
chainId: mainnet.id,
functionName: "deleteFlow",
args: [superToken, account.address, receiver, "0x"]
})
return hash
}
Reading Flow Information
Check the current flowrate between accounts:
import { useReadCfaForwarder } from "@sfpro/sdk/hook"
const superToken = "0x..." // USDCx address
const sender = "0x..." // Sender address
const receiver = "0x..." // Receiver address
function FlowInfo() {
const { data: flowrate } = useReadCfaForwarder({
functionName: "getFlowrate",
args: [superToken, sender, receiver]
})
return (
<div>
Current flowrate: {flowrate?.toString()} tokens/second
</div>
)
}
import { cfaForwarderAbi, cfaForwarderAddress } from "@sfpro/sdk/abi"
import { createPublicClient, http } from "viem"
import { mainnet } from "viem/chains"
const client = createPublicClient({
chain: mainnet,
transport: http()
})
const superToken = "0x..." // USDCx address
const sender = "0x..." // Sender address
const receiver = "0x..." // Receiver address
async function getFlowInfo() {
const flowrate = await client.readContract({
address: cfaForwarderAddress[mainnet.id],
abi: cfaForwarderAbi,
functionName: "getFlowrate",
args: [superToken, sender, receiver]
})
return flowrate
}
import { readCfaForwarder } from "@sfpro/sdk/action"
import { createConfig } from "@wagmi/core"
import { http } from "viem"
import { mainnet } from "viem/chains"
const wagmiConfig = createConfig({
chains: [mainnet],
transports: {
[mainnet.id]: http()
}
})
const superToken = "0x..." // USDCx address
const sender = "0x..." // Sender address
const receiver = "0x..." // Receiver address
async function getFlowInfo() {
const flowrate = await readCfaForwarder(wagmiConfig, {
chainId: mainnet.id,
functionName: "getFlowrate",
args: [superToken, sender, receiver]
})
return flowrate
}
Best Practices
- Use setFlowrate for most cases - it handles both create and update
- Check balance before creating flows to ensure sufficient funds
- Monitor flows to avoid liquidation
- Handle errors appropriately in your UI
Next Steps
- Create GDA pools for one-to-many distributions
- Learn about batch operations
- Explore the CFA Forwarder API