Architecture
Understanding how the Superfluid SDK is structured
SDK Structure
The Superfluid SDK is organized into three main import paths, each serving a specific purpose.
Important: The SDK primarily exposes Forwarder contracts (CFA Forwarder, GDA Forwarder) which are the recommended way to interact with Superfluid. These contracts handle the complexity of encoding calls and routing them through the Host contract.
1. ABIs (@sfpro/sdk/abi
)
Raw contract ABIs with enhanced type information:
import {
superTokenAbi,
cfaForwarderAbi,
gdaForwarderAbi,
cfaForwarderAddress
} from "@sfpro/sdk/abi"
Use ABIs when:
- Working directly with viem
- Building custom abstractions
- Need maximum flexibility
2. Actions (@sfpro/sdk/action
)
Core functions for non-React environments:
import {
readSuperToken,
writeSuperToken,
readCfaForwarder,
writeCfaForwarder
} from "@sfpro/sdk/action"
Use actions when:
- Building server-side applications
- Working in non-React frameworks
- Need wagmi's conveniences without React
3. Hooks (@sfpro/sdk/hook
)
React hooks for seamless integration:
import {
useReadSuperToken,
useWriteSuperToken,
useReadCfaForwarder,
useWriteCfaForwarder
} from "@sfpro/sdk/hook"
Use hooks when:
- Building React applications
- Need reactive data updates
- Want built-in loading/error states
Import Path Organization
Each import path has sub-paths for different contract categories:
Remember: All SDK exports use singular names (action
not actions
, hook
not hooks
, util
not utils
). This consistent naming makes imports predictable!
Root Imports (Main)
Default imports contain the most commonly used contracts:
- Super Token operations
- CFA Forwarder (streaming) - Recommended for flow management
- GDA Forwarder (distributions) - Recommended for pool management
These forwarders are the simplest and safest way to interact with Superfluid.
Core Imports
import { hostAbi } from "@sfpro/sdk/abi/core"
import { readHost } from "@sfpro/sdk/action/core"
import { useReadHost } from "@sfpro/sdk/hook/core"
Protocol-level contracts for advanced use cases:
- Host (core protocol)
- CFA/GDA/IDA (agreement contracts - use forwarders instead when possible)
- TOGA (liquidations)
Note: Direct interaction with agreement contracts (CFA, GDA, IDA) requires encoding calls through the Host. Use the forwarders instead for a simpler interface.
Automation Imports
import { vestingSchedulerAbi } from "@sfpro/sdk/abi/automation"
import { readVestingScheduler } from "@sfpro/sdk/action/automation"
import { useReadVestingScheduler } from "@sfpro/sdk/hook/automation"
Automation contracts for scheduled operations:
- AutoWrap (automatic token wrapping)
- VestingScheduler (token vesting)
- FlowScheduler (scheduled streams)
Why Forwarders?
Superfluid's architecture requires all agreement operations to go through the Host contract. This means:
- Direct calls don't work: You cannot call CFA/GDA/IDA contracts directly
- Complex encoding: Operations must be encoded and sent via
Host.callAgreement()
- Changed msg.sender: The Host becomes the msg.sender for operations
Forwarders solve these complexities by:
- Handling all encoding automatically
- Being trusted by the protocol (can use
forwardBatchCall
) - Providing a simple, direct interface
- Maintaining the correct msg.sender context
Contract Naming Convention
Contract names are transformed for consistency:
CFAv1Forwarder
→cfaForwarder
GeneralDistributionAgreementV1
→gda
ISuperToken
→superToken
Contract Interaction Patterns
Recommended Pattern: Use Forwarders
// Simple and direct - handles all complexity
import { cfaForwarderAbi, cfaForwarderAddress } from "@sfpro/sdk/abi"
import { createWalletClient, http } from "viem"
import { mainnet } from "viem/chains"
// @noErrors
const walletClient = {} as any
// ---cut---
// Direct call to forwarder - recommended!
await walletClient.writeContract({
address: cfaForwarderAddress[mainnet.id],
abi: cfaForwarderAbi,
functionName: "setFlowrate",
args: ["0x...", "0x...", 1000n]
})
Advanced Pattern: Direct Host Interaction
// Complex and error-prone - avoid unless necessary
import { hostAbi } from "@sfpro/sdk/abi/core"
// @noErrors
const encodedCall = "0x..." // Complex encoding required
const walletClient = {} as any
// ---cut---
// Must encode agreement call data first
await walletClient.writeContract({
address: "0x...", // Host address
abi: hostAbi,
functionName: "callAgreement",
args: ["0x...", encodedCall, "0x"] // Agreement, encoded data, context
})
Best Practices
-
Always use forwarders when possible:
- CFA Forwarder for flows
- GDA Forwarder for distributions
- Only use Host/agreements for advanced cases
-
Choose the right import path:
- ABIs for direct viem usage
- Actions for server/non-React
- Hooks for React apps
-
Use specific imports:
// Good import { cfaForwarderAbi } from "@sfpro/sdk/abi" // Avoid import * as sdk from "@sfpro/sdk"
-
Leverage type safety:
- Let TypeScript guide your implementation
- Use autocomplete for function names
- Trust the type errors
Next Steps
- Review the glossary for terminology
- Start building with use-case guides
- Explore the API reference