# Table of Contents - [Superfluid | Stream Money Every Second | Superfluid | Stream Money Every Second](#superfluid-stream-money-every-second-superfluid-stream-money-every-second) - [What is Superfluid? | Superfluid | Stream Money Every Second](#what-is-superfluid-superfluid-stream-money-every-second) - [Quickstart | Superfluid | Stream Money Every Second](#quickstart-superfluid-stream-money-every-second) - [Quickstart | Superfluid | Stream Money Every Second](#quickstart-superfluid-stream-money-every-second) - [Governance Overview | Superfluid | Stream Money Every Second](#governance-overview-superfluid-stream-money-every-second) - [Protocol Architecture | Superfluid | Stream Money Every Second](#protocol-architecture-superfluid-stream-money-every-second) - [Superfluid | Stream Money Every Second](#superfluid-stream-money-every-second) - [Super Tokens | Superfluid | Stream Money Every Second](#super-tokens-superfluid-stream-money-every-second) - [Deploy a Super Token | Superfluid | Stream Money Every Second](#deploy-a-super-token-superfluid-stream-money-every-second) - [CFAv1Forwarder | Superfluid | Stream Money Every Second](#cfav1forwarder-superfluid-stream-money-every-second) - [Superfluid | Stream Money Every Second](#superfluid-stream-money-every-second) - [Superfluid | Stream Money Every Second](#superfluid-stream-money-every-second) - [Money Streaming | Superfluid | Stream Money Every Second](#money-streaming-superfluid-stream-money-every-second) - [Superfluid | Stream Money Every Second](#superfluid-stream-money-every-second) - [Use Cases | Superfluid | Stream Money Every Second](#use-cases-superfluid-stream-money-every-second) - [Advanced Topics | Superfluid | Stream Money Every Second](#advanced-topics-superfluid-stream-money-every-second) - [Glossary of Terms | Superfluid | Stream Money Every Second](#glossary-of-terms-superfluid-stream-money-every-second) - [Money Streaming | Superfluid | Stream Money Every Second](#money-streaming-superfluid-stream-money-every-second) - [Money Streaming in Superfluid | Superfluid | Stream Money Every Second](#money-streaming-in-superfluid-superfluid-stream-money-every-second) - [Super Tokens | Superfluid | Stream Money Every Second](#super-tokens-superfluid-stream-money-every-second) - [Super Tokens | Superfluid | Stream Money Every Second](#super-tokens-superfluid-stream-money-every-second) - [Distribution Pools | Superfluid | Stream Money Every Second](#distribution-pools-superfluid-stream-money-every-second) - [Money Streaming | Superfluid | Stream Money Every Second](#money-streaming-superfluid-stream-money-every-second) - [Examples | Superfluid | Stream Money Every Second](#examples-superfluid-stream-money-every-second) - [Advanced Topics | Superfluid | Stream Money Every Second](#advanced-topics-superfluid-stream-money-every-second) - [Advanced Topics | Superfluid | Stream Money Every Second](#advanced-topics-superfluid-stream-money-every-second) - [Distribution Pools | Superfluid | Stream Money Every Second](#distribution-pools-superfluid-stream-money-every-second) - [Examples | Superfluid | Stream Money Every Second](#examples-superfluid-stream-money-every-second) - [Contribute | Superfluid | Stream Money Every Second](#contribute-superfluid-stream-money-every-second) - [Contract Addresses | Superfluid | Stream Money Every Second](#contract-addresses-superfluid-stream-money-every-second) - [Overview of Super Tokens | Superfluid | Stream Money Every Second](#overview-of-super-tokens-superfluid-stream-money-every-second) - [GDAv1Forwarder | Superfluid | Stream Money Every Second](#gdav1forwarder-superfluid-stream-money-every-second) - [Using the SuperTokenV1Library | Superfluid | Stream Money Every Second](#using-the-supertokenv1library-superfluid-stream-money-every-second) - [SuperTokenV1Library | Superfluid | Stream Money Every Second](#supertokenv1library-superfluid-stream-money-every-second) - [Subgraph Endpoints | Superfluid | Stream Money Every Second](#subgraph-endpoints-superfluid-stream-money-every-second) - [ISuperfluidPool | Superfluid | Stream Money Every Second](#isuperfluidpool-superfluid-stream-money-every-second) - [Distribution Pools Explained | Superfluid | Stream Money Every Second](#distribution-pools-explained-superfluid-stream-money-every-second) - [ISETH | Superfluid | Stream Money Every Second](#iseth-superfluid-stream-money-every-second) - [ISuperToken | Superfluid | Stream Money Every Second](#isupertoken-superfluid-stream-money-every-second) - [Guides | Superfluid | Stream Money Every Second](#guides-superfluid-stream-money-every-second) - [Guides | Superfluid | Stream Money Every Second](#guides-superfluid-stream-money-every-second) - [Guides | Superfluid | Stream Money Every Second](#guides-superfluid-stream-money-every-second) - [Examples | Superfluid | Stream Money Every Second](#examples-superfluid-stream-money-every-second) - [Testing | Superfluid | Stream Money Every Second](#testing-superfluid-stream-money-every-second) - [Create, Update and Connect your Pools | Superfluid | Stream Money Every Second](#create-update-and-connect-your-pools-superfluid-stream-money-every-second) - [Testing | Superfluid | Stream Money Every Second](#testing-superfluid-stream-money-every-second) - [Manage Access Control and User Data | Superfluid | Stream Money Every Second](#manage-access-control-and-user-data-superfluid-stream-money-every-second) - [Manage Access Control and User Data | Superfluid | Stream Money Every Second](#manage-access-control-and-user-data-superfluid-stream-money-every-second) - [Create, Update, and Delete Flows | Superfluid | Stream Money Every Second](#create-update-and-delete-flows-superfluid-stream-money-every-second) - [Liquidations & TOGA | Superfluid | Stream Money Every Second](#liquidations-toga-superfluid-stream-money-every-second) - [Running a Sentinel | Superfluid | Stream Money Every Second](#running-a-sentinel-superfluid-stream-money-every-second) - [Token-Cost-Averaging | Superfluid | Stream Money Every Second](#token-cost-averaging-superfluid-stream-money-every-second) - [Super Apps | Superfluid | Stream Money Every Second](#super-apps-superfluid-stream-money-every-second) - [Social & Community | Superfluid | Stream Money Every Second](#social-community-superfluid-stream-money-every-second) - [Superfluid Host | Superfluid | Stream Money Every Second](#superfluid-host-superfluid-stream-money-every-second) - [Wrap and Unwrap Super Tokens | Superfluid | Stream Money Every Second](#wrap-and-unwrap-super-tokens-superfluid-stream-money-every-second) - [Tracking Super Token Balances | Superfluid | Stream Money Every Second](#tracking-super-token-balances-superfluid-stream-money-every-second) - [How to make your balance dance? | Superfluid | Stream Money Every Second](#how-to-make-your-balance-dance-superfluid-stream-money-every-second) - [Subgraph | Superfluid | Stream Money Every Second](#subgraph-superfluid-stream-money-every-second) - [FlowSplitter Smart Contract | Superfluid | Stream Money Every Second](#flowsplitter-smart-contract-superfluid-stream-money-every-second) - [Super Apps | Superfluid | Stream Money Every Second](#super-apps-superfluid-stream-money-every-second) - [Create and Manage Distribution Pools | Superfluid | Stream Money Every Second](#create-and-manage-distribution-pools-superfluid-stream-money-every-second) - [Automations | Superfluid | Stream Money Every Second](#automations-superfluid-stream-money-every-second) - [Advertisement Auction DApp | Superfluid | Stream Money Every Second](#advertisement-auction-dapp-superfluid-stream-money-every-second) - [Solvency | Superfluid | Stream Money Every Second](#solvency-superfluid-stream-money-every-second) - [Batch transactions with Macros | Superfluid | Stream Money Every Second](#batch-transactions-with-macros-superfluid-stream-money-every-second) - [Connecting and Claiming from the Pools | Superfluid | Stream Money Every Second](#connecting-and-claiming-from-the-pools-superfluid-stream-money-every-second) - [Staking Platform | Superfluid | Stream Money Every Second](#staking-platform-superfluid-stream-money-every-second) - [Rewards Distribution Using Macros | Superfluid | Stream Money Every Second](#rewards-distribution-using-macros-superfluid-stream-money-every-second) - [Bounty Program | Superfluid | Stream Money Every Second](#bounty-program-superfluid-stream-money-every-second) - [Batch Calls with Host Contract | Superfluid | Stream Money Every Second](#batch-calls-with-host-contract-superfluid-stream-money-every-second) - [Subgraph | Superfluid | Stream Money Every Second](#subgraph-superfluid-stream-money-every-second) - [Security & Bug Bounties | Superfluid | Stream Money Every Second](#security-bug-bounties-superfluid-stream-money-every-second) - [Solvency Dashboard | Superfluid | Stream Money Every Second](#solvency-dashboard-superfluid-stream-money-every-second) - [Super Apps in Depth | Superfluid | Stream Money Every Second](#super-apps-in-depth-superfluid-stream-money-every-second) - [Token Explorer Submission | Superfluid | Stream Money Every Second](#token-explorer-submission-superfluid-stream-money-every-second) - [Quickstart | Superfluid | Stream Money Every Second](#quickstart-superfluid-stream-money-every-second) - [Callbacks | Superfluid | Stream Money Every Second](#callbacks-superfluid-stream-money-every-second) - [Registering Super Apps | Superfluid | Stream Money Every Second](#registering-super-apps-superfluid-stream-money-every-second) - [Stream Scheduler | Superfluid | Stream Money Every Second](#stream-scheduler-superfluid-stream-money-every-second) - [Auto-Wrap | Superfluid | Stream Money Every Second](#auto-wrap-superfluid-stream-money-every-second) - [Vesting Scheduler | Superfluid | Stream Money Every Second](#vesting-scheduler-superfluid-stream-money-every-second) - [Stream Accounting API | Superfluid | Stream Money Every Second](#stream-accounting-api-superfluid-stream-money-every-second) --- # Superfluid | Stream Money Every Second | Superfluid | Stream Money Every Second [Skip to main content](https://docs.superfluid.org/#__docusaurus_skipToContent_fallback) Technical DocumentationThe Most Advanced Money Streaming Protocol [### What is Superfluid?\ \ Learn about the core concepts of the Superfluid Protocol.](https://docs.superfluid.org/docs/concepts/superfluid) [### Get Started\ \ Start building very quickly with Superfluid.](https://docs.superfluid.org/docs/protocol/quickstart) [### Contracts\ \ Learn about the core concepts of the Superfluid Protocol, and how to build your smart contracts.](https://docs.superfluid.org/docs/protocol/quickstart) [### SDK\ \ Learn about how to interact with Superfluid to build your client-side SDK.](https://docs.superfluid.org/docs/sdk/quickstart) [### Governance\ \ Learn about the Superfluid DAO governance and tokenomics.](https://docs.superfluid.org/docs/governance) [### Technical Reference\ \ A comprehensive reference for the most relevant Superfluid contracts.](https://docs.superfluid.org/docs/technical-reference/CFAv1Forwarder) Learn about Superfluid ---------------------- [### What is Superfluid?\ \ Learn about the core concepts of Superfluid](https://docs.superfluid.org/docs/concepts/superfluid) [### What are Super Tokens?\ \ Understand the powerful Super Token standard](https://docs.superfluid.org/docs/concepts/overview/super-tokens) [### What are Distribution Pools?\ \ Understand the power of Money Streaming](https://docs.superfluid.org/docs/concepts/overview/distributions) [### Deploy your Super Token (no-code)\ \ Deploy your Wrapped or Pure Super Token](https://docs.superfluid.org/docs/category/deploy-a-super-token) Integrate with Superfluid ------------------------- [### Smart Contracts Quick Start\ \ Quickly integrate Superfluid in your contracts](https://docs.superfluid.org/docs/protocol/quickstart) [### SDK Quick Start\ \ Quickly build your Superfluid SDK](https://docs.superfluid.org/docs/sdk/quickstart) [### Integrate Streams in your contract\ \ Learn how to create, update and delete flows from your contracts](https://docs.superfluid.org/docs/protocol/money-streaming/guides/create-update-delete-flow) [### Integrate Distribution Pools in your contracts\ \ Learn how to create and manage Pools from your contracts](https://docs.superfluid.org/docs/protocol/distributions/guides/pools) --- # What is Superfluid? | Superfluid | Stream Money Every Second [Skip to main content](https://docs.superfluid.org/docs/concepts/superfluid#__docusaurus_skipToContent_fallback) On this page Introduction[​](https://docs.superfluid.org/docs/concepts/superfluid#introduction "Direct link to Introduction") ----------------------------------------------------------------------------------------------------------------- Superfluid is a revolutionary asset [streaming](https://docs.superfluid.org/docs/concepts/overview/money-streaming) and [distribution](https://docs.superfluid.org/docs/concepts/overview/distributions) protocol bringing subscriptions, salaries, vesting, and rewards to DAOs and crypto-native businesses worldwide. This is made possible by the protocol’s smart contract framework which introduces the [Super Token](https://docs.superfluid.org/docs/concepts/overview/super-tokens) - an extension to the [ERC-20](https://eips.ethereum.org/EIPS/eip-20) standard enabling the transfer of value in completely novel ways. Super Tokens[​](https://docs.superfluid.org/docs/concepts/superfluid#super-tokens "Direct link to Super Tokens") ----------------------------------------------------------------------------------------------------------------- The Superfluid protocol is designed to be a "token-centric" protocol, in that all of its functionalities revolve around the concept of [Super Tokens](https://docs.superfluid.org/docs/concepts/overview/super-tokens) . The framework & Super Token standard can be used to add dynamic balances to tokens on chain, describing cash flows and executing them automatically over time in a non-interactive way. Any token can be transferred in Superfluid streams or distributions, which are programmable, composable, and modular. No capital is locked up, and all inflows and outflows are netted in real-time at every block without consuming any gas. The code is fully open source, while the protocol is non-custodial and permissionless. ![Superfluid with people](https://docs.superfluid.org/assets/Superfluid-main-GIF.gif) _A visualization of the Superfluid Protocol_ **The Superfluid Protocol has currently two main pillars that define its interactions with Super Tokens. These pillars (formerly called Agreements) are the following:** * [_**Money Streaming**_](https://docs.superfluid.org/docs/concepts/overview/money-streaming) - A set of features that enable the creation of money streams between two parties. * [_**Distributions**_](https://docs.superfluid.org/docs/concepts/overview/distributions) - A set of features that enables the creation of a pool of funds that can be distributed to multiple recipients. We go in further details about these two pillars in the next sections. Money Streaming[​](https://docs.superfluid.org/docs/concepts/superfluid#money-streaming "Direct link to Money Streaming") -------------------------------------------------------------------------------------------------------------------------- ### Definition[​](https://docs.superfluid.org/docs/concepts/superfluid#definition "Direct link to Definition") Money Streaming is a continuous transfer of tokens from a sender to a receiver at a defined per-second rate, resulting in a "stream". This stream is perpetual and persists until it's canceled by either the sender or the receiver, or until the sender's Super Token balance is depleted. ### Explanation[​](https://docs.superfluid.org/docs/concepts/superfluid#explanation "Direct link to Explanation") Money Streaming is a novel approach to token transfers, offering a dynamic way of sending funds. Instead of one-time transactions, tokens flow from the sender to the receiver continuously, creating a stream. This method provides real-time financial transactions, enabling a more fluid movement of assets over time, reflecting real-world economic activities more closely. ### Example[​](https://docs.superfluid.org/docs/concepts/superfluid#example "Direct link to Example") ![Superfluid with people](https://docs.superfluid.org/assets/Superfluid-GIF.gif) _A visualization of money streaming from the [Superfluid dashboard](https://app.superfluid.finance/) _ Consider Alice wants to pay Bob a salary of 1200 USDCx per year using Money Streaming. She sets up a stream with a flow rate of 0.038 USDCx per second. Bob's balance starts increasing every second, and Alice's decreases, ensuring a steady transfer of salary. Distributions[​](https://docs.superfluid.org/docs/concepts/superfluid#distributions "Direct link to Distributions") -------------------------------------------------------------------------------------------------------------------- ### Definition[​](https://docs.superfluid.org/docs/concepts/superfluid#definition-1 "Direct link to Definition") Distributions in Superfluid refer to a scalable one-to-many fund transfer method. It involves creating pools with a pool admin managing units for members, who can receive funds instantly or through continuous streaming. ### Explanation[​](https://docs.superfluid.org/docs/concepts/superfluid#explanation-1 "Direct link to Explanation") Distributions are a significant advancement in decentralized finance, enabling efficient and scalable fund transfers among multiple recipients. This method is especially useful for scenarios where funds need to be distributed among many parties, like dividends or rewards, ensuring equitable and automated distribution based on predefined units. ### Example[​](https://docs.superfluid.org/docs/concepts/superfluid#example-1 "Direct link to Example") Imagine a DeFi project creating a reward pool for liquidity providers. The project sets up a distribution pool with a total of 1000 units. If a liquidity provider has 100 units, they receive 10% of the total funds distributed through the pool, either instantly or as a continuous stream, depending on the distribution method. * [Introduction](https://docs.superfluid.org/docs/concepts/superfluid#introduction) * [Super Tokens](https://docs.superfluid.org/docs/concepts/superfluid#super-tokens) * [Money Streaming](https://docs.superfluid.org/docs/concepts/superfluid#money-streaming) * [Definition](https://docs.superfluid.org/docs/concepts/superfluid#definition) * [Explanation](https://docs.superfluid.org/docs/concepts/superfluid#explanation) * [Example](https://docs.superfluid.org/docs/concepts/superfluid#example) * [Distributions](https://docs.superfluid.org/docs/concepts/superfluid#distributions) * [Definition](https://docs.superfluid.org/docs/concepts/superfluid#definition-1) * [Explanation](https://docs.superfluid.org/docs/concepts/superfluid#explanation-1) * [Example](https://docs.superfluid.org/docs/concepts/superfluid#example-1) --- # Quickstart | Superfluid | Stream Money Every Second [Skip to main content](https://docs.superfluid.org/docs/sdk/quickstart#__docusaurus_skipToContent_fallback) On this page This guide will help you get started with the Superfluid protocol by creating a simple React app that interacts with the protocol. You'll learn how to connect your wallet, create streams, and create pools using the Superfluid protocol. How to Interact with the Superfluid Protocol[​](https://docs.superfluid.org/docs/sdk/quickstart#how-to-interact-with-the-superfluid-protocol "Direct link to How to Interact with the Superfluid Protocol") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ When interacting with the Superfluid protocol from a client application, you'll use one of two contracts depending on the functionality you need: 1. For Money Streaming: Use the [`CFAv1Forwarder`](https://docs.superfluid.org/docs/technical-reference/CFAv1Forwarder) contract 2. For Distribution Pools: Use the [`GDAv1Forwarder`](https://docs.superfluid.org/docs/technical-reference/GDAv1Forwarder) contract We use these forwarder contracts instead of building an SDK because: * It simplifies the integration process * It reduces the need for frequent updates to the SDK * It allows for more flexibility and direct interaction with the protocol Contract Addresses and ABIs[​](https://docs.superfluid.org/docs/sdk/quickstart#contract-addresses-and-abis "Direct link to Contract Addresses and ABIs") --------------------------------------------------------------------------------------------------------------------------------------------------------- Here are the addresses for each contract across all Superfluid-supported chains: * `CFAv1Forwarder`: `0xcfA132E353cB4E398080B9700609bb008eceB125` * `GDAv1Forwarder`: `0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08` You can find the full ABIs for these contracts in the following technical references: * [CFAv1Forwarder ABI](https://docs.superfluid.org/docs/technical-reference/CFAv1Forwarder) * [GDAv1Forwarder ABI](https://docs.superfluid.org/docs/technical-reference/GDAv1Forwarder) Creating a React App (Next.js)[​](https://docs.superfluid.org/docs/sdk/quickstart#creating-a-react-app-nextjs "Direct link to Creating a React App (Next.js)") --------------------------------------------------------------------------------------------------------------------------------------------------------------- To create a new Next.js app, follow these steps: 1. Open your terminal and run: npx create-next-app@latest my-superfluid-app 2. Navigate to your new app directory: cd my-superfluid-app 3. Install necessary dependencies: npm install ethers@5.7.2 Superfluid Interaction Component[​](https://docs.superfluid.org/docs/sdk/quickstart#superfluid-interaction-component "Direct link to Superfluid Interaction Component") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ In this section, we will provide a React component that allows you to interact with the Superfluid protocol. This component will allow you to: * Connect your wallet (eg. Metamask) * Create a stream through the `CFAv1Forwarder` contract (for [Money Streaming](https://docs.superfluid.org/docs/sdk/docs/concepts/overview/money-streaming) ) * Create a pool through the `GDAv1Forwarder` contract (for [Distribution Pools](https://docs.superfluid.org/docs/sdk/docs/concepts/overview/distributions) ) Here's a React component that allows you to create a stream and create a pool. You can copy and paste this into a new file in your Next.js app's `pages` directory (e.g., `pages/superfluid-demo.js`): note For a full list of available functions and events, refer to the [CFAv1Forwarder technical reference](https://docs.superfluid.org/docs/technical-reference/CFAv1Forwarder) and [GDAv1Forwarder technical reference](https://docs.superfluid.org/docs/technical-reference/GDAv1Forwarder) . Live Editor // Don't forget imports //import React, { useState } from 'react'; //import { ethers } from 'ethers'; function SuperfluidDemo() { const \[provider, setProvider\] \= useState(null); const \[account, setAccount\] \= useState(''); const \[tokenAddress, setTokenAddress\] \= useState(''); const \[receiverAddress, setReceiverAddress\] \= useState(''); const \[flowRate, setFlowRate\] \= useState(''); const \[adminAddress, setAdminAddress\] \= useState(''); const \[message, setMessage\] \= useState(''); const CFAv1ForwarderAddress \= '0xcfA132E353cB4E398080B9700609bb008eceB125'; const GDAv1ForwarderAddress \= '0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08'; // Simplified ABIs with only the functions we need const CFAv1ForwarderABI \= \[ "function createFlow(address token, address sender, address receiver, int96 flowRate, bytes memory userData) external returns (bool)" \]; const GDAv1ForwarderABI \= \[ "function createPool(address token, address admin, (uint32 transferabilityForUnitsOwner, bool distributionFromAnyAddress) memory poolConfig) external returns (bool, address)" \]; const connectWallet \= async () \=> { if (typeof window.ethereum !== 'undefined') { try { await window.ethereum.request({ method: 'eth\_requestAccounts' }); const provider \= new ethers.providers.Web3Provider(window.ethereum); setProvider(provider); const signer \= provider.getSigner(); const address \= await signer.getAddress(); setAccount(address); setMessage(\`Connected to ${address}\`); } catch (error) { console.error('Failed to connect wallet:', error); setMessage('Failed to connect wallet. Please try again.'); } } else { setMessage('Please install Metamask to use this feature.'); } }; const createStream \= async () \=> { if (!provider) { setMessage('Please connect your wallet first.'); return; } const signer \= provider.getSigner(); const contract \= new ethers.Contract(CFAv1ForwarderAddress, CFAv1ForwarderABI, signer); try { const tx \= await contract.createFlow( tokenAddress, account, receiverAddress, flowRate, "0x" ); await tx.wait(); setMessage('The stream has been created successfully.'); } catch (error) { console.error('Error creating stream:', error); setMessage('Failed to create stream. Please try again.'); } }; const createPool \= async () \=> { if (!provider) { setMessage('Please connect your wallet first.'); return; } const signer \= provider.getSigner(); const contract \= new ethers.Contract(GDAv1ForwarderAddress, GDAv1ForwarderABI, signer); try { const poolConfig \= { transferabilityForUnitsOwner: 0, distributionFromAnyAddress: false }; const tx \= await contract.createPool(tokenAddress, adminAddress, poolConfig); const receipt \= await tx.wait(); const \[success, poolAddress\] \= receipt.events.find(e \=> e.event \=== 'PoolCreated').args; setMessage(\`Pool created successfully at ${poolAddress}\`); } catch (error) { console.error('Error creating pool:', error); setMessage('Failed to create pool. Please try again.'); } }; return (

Superfluid Demo {!account ? ( {error &&

{error}

} {realTimeBalance !== null && (

Real-Time Balance from Subgraph: {realTimeBalance} fake DAIx

)} {blockchainBalance !== null && (

Balance from Blockchain: {blockchainBalance} fake DAIx

)}

);}; Furthermore, you can use the live code block below to see the `NetBalance` component in action: * Enter your `liveAddress` in the code editor. * Click "Fetch Balance" to compare your real-time balance from the subgraph with the blockchain balance. Live Editor function UserBalance() { const yourAddress\="0x5e48a37d34d93778807ef19d74e06128252bab45"; return ( ); } Result Loading... About this example Please keep in mind that in the example above we make the assumption that the user is only using Money Streaming and Distributions in the form of the GDA, but not Distributions in the form of the IDA. If you are using IDA, you will need to add a new query to get the data related to each transfer a user is distributing. * [Compatibility with ERC20](https://docs.superfluid.org/docs/sdk/super-tokens/super-token-balances#compatibility-with-erc20) * [Key Points](https://docs.superfluid.org/docs/sdk/super-tokens/super-token-balances#key-points) * [Balance Tracking Considerations](https://docs.superfluid.org/docs/sdk/super-tokens/super-token-balances#balance-tracking-considerations) * [Challenges](https://docs.superfluid.org/docs/sdk/super-tokens/super-token-balances#challenges) * [Solution 1 (recommended): Using `balanceOf`](https://docs.superfluid.org/docs/sdk/super-tokens/super-token-balances#solution-1-recommended-using-balanceof) * [Solution 2: Using queries from the Subgraph](https://docs.superfluid.org/docs/sdk/super-tokens/super-token-balances#solution-2-using-queries-from-the-subgraph) --- # How to make your balance dance? | Superfluid | Stream Money Every Second [Skip to main content](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#__docusaurus_skipToContent_fallback) On this page Have you ever been to the [Superfluid Dashboard](https://app.superfluid.finance/) and seen the balance of a user dancing like in the GIF below? This is because the balance of Super Tokens is constantly being updated, with each block. ![Dancing Balance](https://docs.superfluid.org/assets/images/flowing-balance-6bd8122aa356aaae24b173d227980aa9.gif) _GIF of a "Flowing Balance" from the [Superfluid Dashboard](https://app.superfluid.finance/) _ We call this the `FlowingBalance` component and it's a great way to show the balance of a user in a dynamic and visually appealing way. In this guide, we will show you how to make your balance dance. Let's get started! Overview[​](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#overview "Direct link to Overview") ---------------------------------------------------------------------------------------------------------------- The `FlowingBalance` component is designed to dynamically display a Super Token's balance that updates over time based on a specified flow rate, a starting balance and a starting date. This guide breaks down the component into its core functionalities, including utility functions, custom hooks, and the component itself. `FlowingBalance` leverages React's hooks to animate balance changes over time, simulating a continuous flow of currency. It's particularly useful in applications that need to show real-time updates to a user's balance of Super Tokens, providing a visually appealing and responsive user interface. Click here to show `FlowingBalance` Component code import React, { useEffect, useState, useMemo, memo } from 'react';import { formatEther } from 'viem';// Constantsexport const ANIMATION_MINIMUM_STEP_TIME = 40;// Utility functionsexport const absoluteValue = (n: bigint) => { return n >= BigInt(0) ? n : -n;};export function toFixedUsingString(numStr: string, decimalPlaces: number): string { const [wholePart, decimalPart] = numStr.split('.'); if (!decimalPart || decimalPart.length <= decimalPlaces) { return numStr.padEnd(wholePart.length + 1 + decimalPlaces, '0'); } const decimalPartBigInt = BigInt(`${decimalPart.slice(0, decimalPlaces)}${decimalPart[decimalPlaces] >= '5' ? '1' : '0'}`); return `${wholePart}.${decimalPartBigInt.toString().padStart(decimalPlaces, '0')}`;}// Hooksexport const useSignificantFlowingDecimal = ( flowRate: bigint, animationStepTimeInMs: number,): number | undefined => useMemo(() => { if (flowRate === BigInt(0)) { return undefined; } const ticksPerSecond = 1000 / animationStepTimeInMs; const flowRatePerTick = flowRate / BigInt(ticksPerSecond); const [beforeEtherDecimal, afterEtherDecimal] = formatEther(flowRatePerTick).split('.'); const isFlowingInWholeNumbers = absoluteValue(BigInt(beforeEtherDecimal)) > BigInt(0); if (isFlowingInWholeNumbers) { return 0; // Flowing in whole numbers per tick. } const numberAfterDecimalWithoutLeadingZeroes = BigInt(afterEtherDecimal); const lengthToFirstSignificantDecimal = afterEtherDecimal .toString() .replace(numberAfterDecimalWithoutLeadingZeroes.toString(), '').length; // We're basically counting the zeroes. return Math.min(lengthToFirstSignificantDecimal + 2, 18); // Don't go over 18.}, [flowRate, animationStepTimeInMs]);const useFlowingBalance = ( startingBalance: bigint, startingBalanceDate: Date, flowRate: bigint) => { const [flowingBalance, setFlowingBalance] = useState(startingBalance); const startingBalanceTime = startingBalanceDate.getTime(); useEffect(() => { if (flowRate === BigInt(0)) return; let lastAnimationTimestamp = 0; const animationStep = (currentAnimationTimestamp: number) => { const animationFrameId = window.requestAnimationFrame(animationStep); if ( currentAnimationTimestamp - lastAnimationTimestamp > ANIMATION_MINIMUM_STEP_TIME ) { const elapsedTimeInMilliseconds = BigInt( Date.now() - startingBalanceTime ); const flowingBalance_ = startingBalance + (flowRate * elapsedTimeInMilliseconds) / BigInt(1000); setFlowingBalance(flowingBalance_); lastAnimationTimestamp = currentAnimationTimestamp; } return () => window.cancelAnimationFrame(animationFrameId); }; let animationFrameId = window.requestAnimationFrame(animationStep); return () => window.cancelAnimationFrame(animationFrameId); }, [startingBalance, startingBalanceTime, flowRate]); return flowingBalance;};// FlowingBalance Componentconst FlowingBalance: React.FC<{ startingBalance: bigint; startingBalanceDate: Date; flowRate: bigint;}> = memo(({ startingBalance, startingBalanceDate, flowRate }) => { const flowingBalance = useFlowingBalance( startingBalance, startingBalanceDate, flowRate ); const decimalPlaces = useSignificantFlowingDecimal( flowRate, ANIMATION_MINIMUM_STEP_TIME ); return (
{decimalPlaces !== undefined ? toFixedUsingString(formatEther(flowingBalance), decimalPlaces) : formatEther(flowingBalance)}
);});export default FlowingBalance; The component explicited in the code above is composed of the following parts: * **Constants**: This section defines the minimum time interval between animation updates. * **Utility Functions**: These functions are used to calculate the absolute value of a number and format a number to a specified number of decimal places. * **Hooks**: These custom hooks are used to calculate the number of significant decimal places to display and update the flowing balance over time. * **FlowingBalance Component**: This functional component uses the hooks and utility functions to render the flowing balance, taking `startingBalance`, `startingBalanceDate`, and `flowRate` as props. Constants[​](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#constants "Direct link to Constants") ------------------------------------------------------------------------------------------------------------------- export const ANIMATION_MINIMUM_STEP_TIME = 40; This constant defines the minimum time interval (in milliseconds) between animation updates. It's used to throttle the animation and ensure that updates occur no more frequently than every 40 milliseconds. Utility Functions[​](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#utility-functions "Direct link to Utility Functions") ------------------------------------------------------------------------------------------------------------------------------------------- ### `absoluteValue`[​](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#absolutevalue "Direct link to absolutevalue") export const absoluteValue = (n: bigint) => { return n >= BigInt(0) ? n : -n;}; Converts a `bigint` to its absolute value. This function is crucial for calculations that require the non-negative form of a number. ### `toFixedUsingString`[​](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#tofixedusingstring "Direct link to tofixedusingstring") export function toFixedUsingString(numStr: string, decimalPlaces: number): string { // Implementation details} Formats a number (expressed as a string) to a specified number of decimal places. This function is essential for displaying the balance in a user-friendly format, ensuring that the balance is rounded and displayed with a consistent number of decimal places. Hooks[​](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#hooks "Direct link to Hooks") ------------------------------------------------------------------------------------------------------- ### `useSignificantFlowingDecimal`[​](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#usesignificantflowingdecimal "Direct link to usesignificantflowingdecimal") export const useSignificantFlowingDecimal = (flowRate: bigint, animationStepTimeInMs: number): number | undefined => { // Hook logic}; Determines the number of significant decimal places to display based on the flow rate and animation step time. This custom hook helps adjust the precision of the balance display dynamically, based on how quickly the balance is changing. ### `useFlowingBalance`[​](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#useflowingbalance "Direct link to useflowingbalance") const useFlowingBalance = (startingBalance: bigint, startingBalanceDate: Date, flowRate: bigint) => { // Hook logic}; Calculates and updates the flowing balance over time. This hook is the core of the component, using the `requestAnimationFrame` API to smoothly update the balance display at a rate that's throttled by `ANIMATION_MINIMUM_STEP_TIME`. FlowingBalance Component[​](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#flowingbalance-component "Direct link to FlowingBalance Component") ---------------------------------------------------------------------------------------------------------------------------------------------------------------- const FlowingBalance: React.FC<{startingBalance: bigint; startingBalanceDate: Date; flowRate: bigint;}> = memo(({ startingBalance, startingBalanceDate, flowRate }) => { // Component logic}); This functional component uses the above hooks and utility functions to render the flowing balance. It takes `startingBalance`, `startingBalanceDate`, and `flowRate` as props, calculating the current balance based on these inputs and displaying it in a formatted manner. ### Usage Example[​](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#usage-example "Direct link to Usage Example") Below is an example of how to use the `FlowingBalance` component within your application. This component exemplifies how to combine React's capabilities with the performance of the Web APIs to create dynamic and responsive UIs. By breaking down the component into its constituent parts, developers can gain insights into its functionality and customize it according to their needs. My component is being jumpy, what can I do? Sometimes, especially if you center your component using `justifyContent: "center"`, the component may have a jumpy behaviour like below: ❌ 10000000 If you run into this issue, you can try to set a fixed width to the component like such:
This should fix the jumpy behaviour and make the component flow smoothly like the example below: ✅ 10000000 Best practices[​](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#best-practices "Direct link to Best practices") ---------------------------------------------------------------------------------------------------------------------------------- * **Throttle the animation**: Ensure that the animation updates occur at a reasonable interval, such as every 40 milliseconds. This helps prevent excessive CPU usage and ensures a smooth user experience. * **Use fixed width**: If the component is jumpy, consider setting a fixed width to the component to ensure a smooth flow of the balance. * **Time conversion**: When showing the flow rate and converting the blockchain value to a human-readable value (eg. wei/s to ETH/month), ensure that the time conversion is accurate and consistent with the rest of Superfluid's time-based calculations: * 1 year = 365 days * 1 month = 1 year/12 * 1 day = 24 hours * 1 hour = 60 minutes * 1 minute = 60 seconds * 1 second = 1000 milliseconds * **Current timestamp**: Following Superfluid's implementation, it is recommended to use `Date.now()` to get the current timestamp in milliseconds instead of using `(await ethers.provider.getBlock('latest')).timestamp` for example. * [Overview](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#overview) * [Constants](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#constants) * [Utility Functions](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#utility-functions) * [`absoluteValue`](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#absolutevalue) * [`toFixedUsingString`](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#tofixedusingstring) * [Hooks](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#hooks) * [`useSignificantFlowingDecimal`](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#usesignificantflowingdecimal) * [`useFlowingBalance`](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#useflowingbalance) * [FlowingBalance Component](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#flowingbalance-component) * [Usage Example](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#usage-example) * [Best practices](https://docs.superfluid.org/docs/sdk/super-tokens/balance-dance#best-practices) --- # Subgraph | Superfluid | Stream Money Every Second [Skip to main content](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#__docusaurus_skipToContent_fallback) On this page The Graph is the indexing layer of the blockchain industry, providing a queryable platform for the vast data produced by blockchain networks. The Graph can be used for querying data in the Superfluid ecosystem and other on-chain data. Experiment with queries using the [GraphQL Playground](https://thegraph.com/hosted-service/) . New to GraphQL? Before diving into subgraph queries, familiarize yourself with GraphQL basics: [Learn GraphQL](https://graphql.org/learn/) Querying Different Networks[​](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#querying-different-networks "Direct link to Querying Different Networks") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### Superfluid Explorer[​](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#superfluid-explorer "Direct link to Superfluid Explorer") The Superfluid Explorer is an interactive interface for exploring the Superfluid Protocol and interacting with its Subgraph. It provides an intuitive way to query on-chain data, get contract addresses, and manage your Superfluid finances. The console supports various blockchain networks, allowing you to seamlessly switch between them and access specific data sets. Whether you're analyzing streams, checking balances, or staying up to date with the new deployments. The Superfluid Explorer makes these tasks accessible and straightforward. Explore Superfluid data across various networks using the Superfluid Explorer. Select a network to start querying: * Popular * Other [Ethereum](https://console.superfluid.finance/subgraph?_network=ethereum) [Polygon](https://console.superfluid.finance/subgraph?_network=matic) [Avalanche](https://console.superfluid.finance/subgraph?_network=avalanche) [Optimism](https://console.superfluid.finance/subgraph?_network=optimism) [Arbitrum](https://console.superfluid.finance/subgraph?_network=arbitrum) [Binance Smart Chain](https://console.superfluid.finance/subgraph?_network=binance-smart-chain) For other networks, use the Superfluid Explorer: [Superfluid Explorer](https://console.superfluid.finance/) ### Subgraph Networks[​](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#subgraph-networks "Direct link to Subgraph Networks") You can have the full list of available subgraph endpoints in the [Subgraph Endpoints](https://docs.superfluid.org/docs/technical-reference/subgraph) page. Resources[​](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#resources "Direct link to Resources") ----------------------------------------------------------------------------------------------------------------- * **Subgraph Queries**: [Guide on Querying the Graph](https://thegraph.com/docs/en/developer/query-the-graph/) * **Deploy a Subgraph**: [Creating a Subgraph](https://thegraph.com/docs/en/developer/create-subgraph-hosted/) * **GraphQL Schema**: [Superfluid Schema](https://github.com/superfluid-finance/protocol-monorepo/blob/dev/packages/subgraph/schema.graphql) * **Our Subgraph Endpoints**: [Subgraph Endpoints](https://docs.superfluid.org/docs/technical-reference/subgraph) Helpful Tips[​](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#helpful-tips "Direct link to Helpful Tips") -------------------------------------------------------------------------------------------------------------------------- * All addresses in the subgraph (`id`, `underlyingAddress`, etc.) are lowercase. * Convert addresses to lowercase before querying. ### Notable Breaking Changes[​](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#notable-breaking-changes "Direct link to Notable Breaking Changes") Migrating From Legacy Subgraph to V1 Significant changes were made in October 2021: * `totalSubscriptions` is now `totalSubscriptionsWithUnits`. * `Subscriber` entity changed to `Subscription`. * `createdAt` and `updatedAt` fields are now `createdAtTimestamp` and `updatedAtTimestamp`. Schema Overview[​](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#schema-overview "Direct link to Schema Overview") ----------------------------------------------------------------------------------------------------------------------------------- The Superfluid Subgraph includes various entities for querying. Think of entities as analogous to database tables. Here's a brief overview: ### Event Entities[​](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#event-entities "Direct link to Event Entities") Event entities correspond to contract events, often with added data. Each event entity is immutable and created once. * **Event ID Format**: `eventName-transactionHash-logIndex`. * **Naming Convention**: For V1, event names end with 'Event'. ### Higher Order Level Entities (HOL)[​](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#higher-order-level-entities-hol "Direct link to Higher Order Level Entities (HOL)") HOL entities represent entities over their lifetime and may be updated. * **`Account`**: Represents any address interacting with Superfluid. * **`Token`**: Represents valid SuperTokens. * **`Pool`**, **`PoolMember`**, **`Stream`**, **`StreamPeriod`**: Related to Superfluid streams and [pools](https://docs.superfluid.org/docs/protocol/distributions/guides/pools) . ### Aggregate Entities[​](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#aggregate-entities "Direct link to Aggregate Entities") Aggregate entities store cumulative data at both account-token and global token levels: * **`TokenStatistic`**: Aggregates data for a single Token type. * **`AccountTokenSnapshot`**: Aggregates data on an account's interaction with a token. Query Examples[​](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#query-examples "Direct link to Query Examples") -------------------------------------------------------------------------------------------------------------------------------- Here are examples to help you get started with Superfluid subgraphs: ### Super Token Data Query[​](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#super-token-data-query "Direct link to Super Token Data Query") { tokens(first: 100) { id symbol name underlyingAddress }} ### Get All Streams for a Given Account[​](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#get-all-streams-for-a-given-account "Direct link to Get All Streams for a Given Account") To list all streams that an account is currently receiving (swap 'receiver' for 'sender' to see streams being sent): query MyQuery { streams(where: {receiver: "YOUR_ADDRESS_HERE"}) { currentFlowRate token { symbol } sender { id } receiver { id } }} ### Getting Stream Data Between 2 Parties[​](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#getting-stream-data-between-2-parties "Direct link to Getting Stream Data Between 2 Parties") Query active streams between two parties, such as Alice ("0x658...") and Bob ("0xd66..."): { streams(where:{ sender: "0x658e1b019f2f30c8089a9ae3ae5820f335bd9ce4" receiver: "0xd66e40b0c30595bec72153b502ac1e0c4785991b" }) { token { id symbol } createdAtTimestamp updatedAtTimestamp currentFlowRate streamedUntilUpdatedAt }} note To calculate the current total amount streamed, use: _**streamedUntilUpdatedAt + ((current time in seconds) - updatedAtTimestamp) \* currentFlowRate**_. ### Get The Most Recently Updated Flows[​](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#get-the-most-recently-updated-flows "Direct link to Get The Most Recently Updated Flows") Query the 10 most recently updated flows using the `FlowUpdatedEvent` type: { flowUpdatedEvents(first: 10, orderBy: timestamp, orderDirection: desc) { oldFlowRate flowRate userData stream { token { symbol } sender { id } receiver { id } } }} info Understand the difference between a Flow and a Stream. A new stream is created each time a stream is terminated and restarted. ### Get Aggregate Flow Data For a Given Token[​](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#get-aggregate-flow-data-for-a-given-token "Direct link to Get Aggregate Flow Data For a Given Token") Query aggregate data for a specific token, such as Super DAI on Polygon: { tokenStatistics(where: { id: "0x1305f6b6df9dc47159d12eb7ac2804d4a33173c2" // DAIx address on Matic }) { totalNumberOfActiveStreams totalNumberOfActiveIndexes totalAmountStreamedUntilUpdatedAt totalOutflowRate totalAmountDistributedUntilUpdatedAt }} ### Get Data On a Specific Account[​](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#get-data-on-a-specific-account "Direct link to Get Data On a Specific Account") Query data on a specific account using both the `Account` and `AccountTokenSnapshot` entities: { accounts(where: { id: "0x..." // Enter an address below }) { isSuperApp inflows { currentFlowRate token { symbol } sender { id } } outflows { currentFlowRate token { symbol } receiver { id } } accountTokenSnapshots { token { id } totalNumberOfActiveStreams totalNetFlowRate } }} tip Use `AccountTokenSnapshot` to get activity data for a specific token associated with an account. Explore more queries[​](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#explore-more-queries "Direct link to Explore more queries") -------------------------------------------------------------------------------------------------------------------------------------------------- Explore more queries using the [Superfluid Subgraph Playground](https://console.superfluid.finance/subgraph) . * [Querying Different Networks](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#querying-different-networks) * [Superfluid Explorer](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#superfluid-explorer) * [Subgraph Networks](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#subgraph-networks) * [Resources](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#resources) * [Helpful Tips](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#helpful-tips) * [Notable Breaking Changes](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#notable-breaking-changes) * [Schema Overview](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#schema-overview) * [Event Entities](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#event-entities) * [Higher Order Level Entities (HOL)](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#higher-order-level-entities-hol) * [Aggregate Entities](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#aggregate-entities) * [Query Examples](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#query-examples) * [Super Token Data Query](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#super-token-data-query) * [Get All Streams for a Given Account](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#get-all-streams-for-a-given-account) * [Getting Stream Data Between 2 Parties](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#getting-stream-data-between-2-parties) * [Get The Most Recently Updated Flows](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#get-the-most-recently-updated-flows) * [Get Aggregate Flow Data For a Given Token](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#get-aggregate-flow-data-for-a-given-token) * [Get Data On a Specific Account](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#get-data-on-a-specific-account) * [Explore more queries](https://docs.superfluid.org/docs/sdk/money-streaming/subgraph#explore-more-queries) --- # FlowSplitter Smart Contract | Superfluid | Stream Money Every Second [Skip to main content](https://docs.superfluid.org/docs/protocol/money-streaming/examples/example1#__docusaurus_skipToContent_fallback) On this page This guide provides an overview and usage instructions for the `FlowSplitter` smart contract, which leverages the Superfluid protocol to route incoming streams of Super Tokens to two different recipients based on predefined proportions. Introduction[​](https://docs.superfluid.org/docs/protocol/money-streaming/examples/example1#introduction "Direct link to Introduction") ---------------------------------------------------------------------------------------------------------------------------------------- The `FlowSplitter` contract is designed to automatically split incoming Super Token streams to a main and a side receiver. This splitting is determined by the `sideReceiverPortion` parameter, which defines the percentage of the incoming flow to be routed to the side receiver, with the remainder going to the main receiver. Contract Overview[​](https://docs.superfluid.org/docs/protocol/money-streaming/examples/example1#contract-overview "Direct link to Contract Overview") ------------------------------------------------------------------------------------------------------------------------------------------------------- ![FlowSplitter Diagram](https://docs.superfluid.org/assets/diagram.png) The above diagram illustrates how the `FlowSplitter` works. For example, if the `sideReceiverPortion` is set to 30%, then 30% of all incoming Super Token streams will be routed to the side receiver, and the remaining 70% will go to the main receiver. Click here to show `FlowSender` contract // SPDX-License-Identifier: UNLICENSEDpragma solidity 0.8.18;// Uncomment this line to use console.log// import "hardhat/console.sol";import {SuperTokenV1Library} from "@superfluid-finance/ethereum-contracts/contracts/apps/SuperTokenV1Library.sol";import {SuperAppBaseFlow} from "@superfluid-finance/ethereum-contracts/contracts/apps/SuperAppBaseFlow.sol";import { ISuperfluid, ISuperToken} from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol";/// @title FlowSplitter/// @author Superfluid | Modified by @0xdavinchee/// @dev A negative sideReceiverPortion portion is not allowed/// A portion > 1000 is fine though because the protocol will/// revert when trying to create a flow with a negative flow rate/// A flowRate which is less than 1000 will be rounded down to 0 and will revert/// Also an inflow which does not contain a whole number will be rounded down,/// this will also lead to a revert.contract FlowSplitter is SuperAppBaseFlow { using SuperTokenV1Library for ISuperToken; /// @dev Account that ought to be routed the majority of the inflows address public immutable MAIN_RECEIVER; /// @dev Account that ought to be routed the minority of the inflows address public immutable SIDE_RECEIVER; /// @dev Account that deployed the contract address public immutable CREATOR; /// @dev Super Token that the FlowSplitter will accept streams of ISuperToken public immutable ACCEPTED_SUPER_TOKEN; /// @dev number out of 1000 representing portion of inflows to be redirected to SIDE_RECEIVER /// Ex: 300 would represent 30% int96 public sideReceiverPortion; error INVALID_PORTION(); error SAME_RECEIVERS_NOT_ALLOWED(); error NO_SELF_FLOW(); error NOT_CREATOR(); /// @dev emitted when the split of the outflow to MAIN_RECEIVER and SIDE_RECEIVER is updated event SplitUpdated(int96 mainReceiverPortion, int96 newSideReceiverPortion); constructor( ISuperfluid host_, ISuperToken acceptedSuperToken_, address creator_, address mainReceiver_, address sideReceiver_, int96 sideReceiverPortion_ ) SuperAppBaseFlow(host_, true, true, true) { if (sideReceiverPortion_ <= 0 || sideReceiverPortion_ == 1000) revert INVALID_PORTION(); if (mainReceiver_ == sideReceiver_) revert SAME_RECEIVERS_NOT_ALLOWED(); if (mainReceiver_ == address(this) || sideReceiver_ == address(this)) revert NO_SELF_FLOW(); ACCEPTED_SUPER_TOKEN = acceptedSuperToken_; CREATOR = creator_; MAIN_RECEIVER = mainReceiver_; SIDE_RECEIVER = sideReceiver_; sideReceiverPortion = sideReceiverPortion_; } /// @dev checks that only the acceptedToken is used when sending streams into this contract /// @param superToken_ the token being streamed into the contract function isAcceptedSuperToken(ISuperToken superToken_) public view override returns (bool) { return superToken_ == ACCEPTED_SUPER_TOKEN; } /// @notice Returns the outflow rates to main and side receiver given flowRate_ and an arbitrary /// sideReceiverPortion_ /// @dev If either returns 0, it will revert when trying to create a flow /// because the protocol does not allow creating flows with a flow rate of 0 /// Also, if the sum of the two outflows is not equal to the inflow, it means the app will /// receive a residual flow. /// @param flowRate_ the inflow rate /// @param sideReceiverPortion_ the portion of the inflow to be redirected to SIDE_RECEIVER /// @return mainFlowRate the outflow rate to MAIN_RECEIVER /// @return sideFlowRate the outflow rate to SIDE_RECEIVER /// @return residualFlowRate the residual flow rate function getMainAndSideReceiverFlowRates(int96 flowRate_, int96 sideReceiverPortion_) external pure returns (int96 mainFlowRate, int96 sideFlowRate, int96 residualFlowRate) { mainFlowRate = (flowRate_ * (1000 - sideReceiverPortion_)) / 1000; sideFlowRate = (flowRate_ * sideReceiverPortion_) / 1000; residualFlowRate = flowRate_ - (mainFlowRate + sideFlowRate); } /// @notice Updates the split of the outflow to MAIN_RECEIVER and SIDE_RECEIVER /// @dev Only the creator should be able to call update split. /// @param newSideReceiverPortion_ the new portion of inflows to be redirected to SIDE_RECEIVER function updateSplit(int96 newSideReceiverPortion_) external { if (newSideReceiverPortion_ <= 0 || newSideReceiverPortion_ >= 1000) revert INVALID_PORTION(); if (msg.sender != CREATOR) revert NOT_CREATOR(); sideReceiverPortion = newSideReceiverPortion_; // get current outflow rate int96 totalOutflowRate = ACCEPTED_SUPER_TOKEN.getFlowRate(address(this), MAIN_RECEIVER) + ACCEPTED_SUPER_TOKEN.getFlowRate(address(this), SIDE_RECEIVER); int96 mainReceiverPortion = 1000 - newSideReceiverPortion_; // update outflows // @note there is a peculiar bug here where you can't change the outflow in any way ACCEPTED_SUPER_TOKEN.updateFlow(MAIN_RECEIVER, (totalOutflowRate * mainReceiverPortion) / 1000); ACCEPTED_SUPER_TOKEN.updateFlow(SIDE_RECEIVER, (totalOutflowRate * newSideReceiverPortion_) / 1000); emit SplitUpdated(mainReceiverPortion, newSideReceiverPortion_); } // --------------------------------------------------------------------------------------------- // CALLBACK LOGIC function onFlowCreated(ISuperToken superToken_, address sender_, bytes calldata ctx_) internal override returns (bytes memory newCtx) { newCtx = ctx_; // get inflow rate from sender_ int96 inflowRate = superToken_.getFlowRate(sender_, address(this)); // if there's no outflow already, create outflows if (superToken_.getFlowRate(address(this), MAIN_RECEIVER) == 0) { newCtx = superToken_.createFlowWithCtx(MAIN_RECEIVER, (inflowRate * (1000 - sideReceiverPortion)) / 1000, newCtx); newCtx = superToken_.createFlowWithCtx(SIDE_RECEIVER, (inflowRate * sideReceiverPortion) / 1000, newCtx); } // otherwise, there's already outflows which should be increased else { newCtx = superToken_.updateFlowWithCtx( MAIN_RECEIVER, ACCEPTED_SUPER_TOKEN.getFlowRate(address(this), MAIN_RECEIVER) + (inflowRate * (1000 - sideReceiverPortion)) / 1000, newCtx ); newCtx = superToken_.updateFlowWithCtx( SIDE_RECEIVER, ACCEPTED_SUPER_TOKEN.getFlowRate(address(this), SIDE_RECEIVER) + (inflowRate * sideReceiverPortion) / 1000, newCtx ); } } function onFlowUpdated( ISuperToken superToken_, address sender_, int96 previousFlowRate_, uint256, /*lastUpdated*/ bytes calldata ctx_ ) internal override returns (bytes memory newCtx) { newCtx = ctx_; // get inflow rate change from sender_ int96 inflowChange = superToken_.getFlowRate(sender_, address(this)) - previousFlowRate_; // update outflows newCtx = superToken_.updateFlowWithCtx( MAIN_RECEIVER, ACCEPTED_SUPER_TOKEN.getFlowRate(address(this), MAIN_RECEIVER) + (inflowChange * (1000 - sideReceiverPortion)) / 1000, newCtx ); newCtx = superToken_.updateFlowWithCtx( SIDE_RECEIVER, ACCEPTED_SUPER_TOKEN.getFlowRate(address(this), SIDE_RECEIVER) + (inflowChange * sideReceiverPortion) / 1000, newCtx ); } function onFlowDeleted( ISuperToken superToken_, address, /*sender_*/ address receiver_, int96 previousFlowRate_, uint256, /*lastUpdated*/ bytes calldata ctx_ ) internal override returns (bytes memory newCtx) { newCtx = ctx_; // remaining inflow is equal to total outflow less the inflow that just got deleted int96 remainingInflow = ( ACCEPTED_SUPER_TOKEN.getFlowRate(address(this), MAIN_RECEIVER) + ACCEPTED_SUPER_TOKEN.getFlowRate(address(this), SIDE_RECEIVER) ) - previousFlowRate_; // handle "rogue recipients" with sticky stream - see readme if (receiver_ == MAIN_RECEIVER || receiver_ == SIDE_RECEIVER) { newCtx = superToken_.createFlowWithCtx(receiver_, previousFlowRate_, newCtx); } // if there is no more inflow, outflows should be deleted if (remainingInflow <= 0) { newCtx = superToken_.deleteFlowWithCtx(address(this), MAIN_RECEIVER, newCtx); newCtx = superToken_.deleteFlowWithCtx(address(this), SIDE_RECEIVER, newCtx); } // otherwise, there's still inflow left and outflows must be updated else { newCtx = superToken_.updateFlowWithCtx( MAIN_RECEIVER, (remainingInflow * (1000 - sideReceiverPortion)) / 1000, newCtx ); newCtx = superToken_.updateFlowWithCtx(SIDE_RECEIVER, (remainingInflow * sideReceiverPortion) / 1000, newCtx); } }} Key Components[​](https://docs.superfluid.org/docs/protocol/money-streaming/examples/example1#key-components "Direct link to Key Components") ---------------------------------------------------------------------------------------------------------------------------------------------- * **`MAIN_RECEIVER`:** The primary account that receives the majority of the inflows. * **`SIDE_RECEIVER`:** The secondary account that receives a smaller, specified portion of the inflows. * **`ACCEPTED_SUPER_TOKEN`:** The specific Super Token that the `FlowSplitter` will accept for streaming. * **`sideReceiverPortion`:** A numerical value representing the portion (out of 1000) of inflows redirected to the `SIDE_RECEIVER`. Usage[​](https://docs.superfluid.org/docs/protocol/money-streaming/examples/example1#usage "Direct link to Usage") ------------------------------------------------------------------------------------------------------------------- ### Deploying the Contract[​](https://docs.superfluid.org/docs/protocol/money-streaming/examples/example1#deploying-the-contract "Direct link to Deploying the Contract") To deploy the `FlowSplitter`, you must specify the following parameters: * `host_`: The Superfluid host contract. * `acceptedSuperToken_`: The Super Token to be accepted by the contract. * `creator_`: The address of the account deploying the contract. * `mainReceiver_`: The address of the main receiver. * `sideReceiver_`: The address of the side receiver. * `sideReceiverPortion_`: The initial portion of the inflow to be directed to the side receiver. ### Updating the Flow Split[​](https://docs.superfluid.org/docs/protocol/money-streaming/examples/example1#updating-the-flow-split "Direct link to Updating the Flow Split") The creator of the contract can update the flow split by calling the `updateSplit` function with a new `sideReceiverPortion_`. This adjusts the outflow rates to both receivers accordingly. function updateSplit(int96 newSideReceiverPortion_) external; ### Calculating Flow Rates[​](https://docs.superfluid.org/docs/protocol/money-streaming/examples/example1#calculating-flow-rates "Direct link to Calculating Flow Rates") To calculate the exact outflow rates for the main and side receivers based on any inflow rate and `sideReceiverPortion`, use the `getMainAndSideReceiverFlowRates` function: function getMainAndSideReceiverFlowRates( int96 flowRate_, int96 sideReceiverPortion_) external pure returns ( int96 mainFlowRate, int96 sideFlowRate, int96 residualFlowRate); ### Handling Streams[​](https://docs.superfluid.org/docs/protocol/money-streaming/examples/example1#handling-streams "Direct link to Handling Streams") The contract includes several internal callback functions that handle the creation, updating, and deletion of streams: * `onFlowCreated`: Called when a new inflow to the `FlowSplitter` is created. * `onFlowUpdated`: Called when an existing inflow to the `FlowSplitter` is updated. * `onFlowDeleted`: Called when an inflow to the `FlowSplitter` is deleted. Conclusion[​](https://docs.superfluid.org/docs/protocol/money-streaming/examples/example1#conclusion "Direct link to Conclusion") ---------------------------------------------------------------------------------------------------------------------------------- The `FlowSplitter` smart contract offers a robust solution for automatically splitting incoming Super Token streams. By setting the `sideReceiverPortion`, users can determine the flow rates to different parties, enabling a fair and transparent distribution of funds. * [Introduction](https://docs.superfluid.org/docs/protocol/money-streaming/examples/example1#introduction) * [Contract Overview](https://docs.superfluid.org/docs/protocol/money-streaming/examples/example1#contract-overview) * [Key Components](https://docs.superfluid.org/docs/protocol/money-streaming/examples/example1#key-components) * [Usage](https://docs.superfluid.org/docs/protocol/money-streaming/examples/example1#usage) * [Deploying the Contract](https://docs.superfluid.org/docs/protocol/money-streaming/examples/example1#deploying-the-contract) * [Updating the Flow Split](https://docs.superfluid.org/docs/protocol/money-streaming/examples/example1#updating-the-flow-split) * [Calculating Flow Rates](https://docs.superfluid.org/docs/protocol/money-streaming/examples/example1#calculating-flow-rates) * [Handling Streams](https://docs.superfluid.org/docs/protocol/money-streaming/examples/example1#handling-streams) * [Conclusion](https://docs.superfluid.org/docs/protocol/money-streaming/examples/example1#conclusion) --- # Super Apps | Superfluid | Stream Money Every Second [Skip to main content](https://docs.superfluid.org/docs/category/super-apps#__docusaurus_skipToContent_fallback) [📄️ Quickstart\ --------------\ \ Inroduction](https://docs.superfluid.org/docs/protocol/advanced-topics/super-apps/deploy-a-super-app) [📄️ Super Apps in Depth\ -----------------------\ \ What is a Super App?](https://docs.superfluid.org/docs/protocol/advanced-topics/super-apps/understand-super-apps) [📄️ Callbacks\ -------------\ \ Super App callbacks play a pivotal role in how Super Apps interact with the Superfluid Protocol. These callbacks are invoked in response to specific events related to Super Agreements.](https://docs.superfluid.org/docs/protocol/advanced-topics/super-apps/callbacks) [📄️ Registering Super Apps\ --------------------------\ \ Overview](https://docs.superfluid.org/docs/protocol/advanced-topics/super-apps/register) --- # Create and Manage Distribution Pools | Superfluid | Stream Money Every Second [Skip to main content](https://docs.superfluid.org/docs/sdk/distributions/create-manage-pools#__docusaurus_skipToContent_fallback) On this page This guide explains how to create and manage [Distribution Pools](https://docs.superfluid.org/docs/protocol/distributions/overview) in Superfluid using the `GDAv1Forwarder` contract. Distribution pools are a key feature of Superfluid that enable scalable one-to-many and many-to-many transfers and streaming of tokens. What are Distribution Pools? Distribution pools are a mechanism for distributing tokens among multiple recipients. They are managed by a pool admin who controls the pool's configuration and member units. Pool members receive distributions based on their units in the pool. To learn more about distribution pools, refer to the [Distributions Overview](https://docs.superfluid.org/docs/protocol/distributions/overview) . Interacting with Distribution Pools from Client Applications[​](https://docs.superfluid.org/docs/sdk/distributions/create-manage-pools#interacting-with-distribution-pools-from-client-applications "Direct link to Interacting with Distribution Pools from Client Applications") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- To interact with Superfluid's distribution pools from client applications, you'll use the [`GDAv1Forwarder`](https://docs.superfluid.org/docs/technical-reference/GDAv1Forwarder) contract. Here's how to set it up: ### Contract ABI and Address[​](https://docs.superfluid.org/docs/sdk/distributions/create-manage-pools#contract-abi-and-address "Direct link to Contract ABI and Address") The `GDAv1Forwarder` contract address is the same on all Superfluid chains: 0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08 You can find the full ABI of the `GDAv1Forwarder` contract in the [GDAv1Forwarder technical reference](https://docs.superfluid.org/docs/technical-reference/GDAv1Forwarder) . ### Setting up with ethers.js[​](https://docs.superfluid.org/docs/sdk/distributions/create-manage-pools#setting-up-with-ethersjs "Direct link to Setting up with ethers.js") Here's how to initiate interaction with the `GDAv1Forwarder` contract using ethers.js: import { ethers } from 'ethers';// Assuming you have a provider set up (e.g., using MetaMask)const provider = new ethers.providers.Web3Provider(window.ethereum);// The address of the GDAv1Forwarder contractconst forwarderAddress = '0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08';// The ABI of the GDAv1Forwarder contract (import this from the technical reference)const forwarderABI = [...]; // Insert the ABI here// Create a contract instanceconst forwarderContract = new ethers.Contract(forwarderAddress, forwarderABI, provider.getSigner()); Understanding Distribution Pools[​](https://docs.superfluid.org/docs/sdk/distributions/create-manage-pools#understanding-distribution-pools "Direct link to Understanding Distribution Pools") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Distributions is a Superfluid primitive that allows scalable one-to-many or many-to-many transfer of value, in the form of discrete transfers or Money Streaming. Superfluid's implementation of this concept allows for the creation of **Pools** with a designated **pool admin** who manages **units** for **pool members**. Key concepts: * **Pool**: A mechanism for distributing tokens among multiple recipients. * **Pool Admin**: The address that has control over the pool's configuration and member units. * **Units**: A measure of a member's share in the pool's distributions. * **Pool Members**: Addresses that receive distributions from the pool based on their units. Interacting with the GDAv1Forwarder Contract[​](https://docs.superfluid.org/docs/sdk/distributions/create-manage-pools#interacting-with-the-gdav1forwarder-contract "Direct link to Interacting with the GDAv1Forwarder Contract") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Let's look at how to use the `GDAv1Forwarder` contract to create and manage distribution pools. ### Creating a Pool[​](https://docs.superfluid.org/docs/sdk/distributions/create-manage-pools#creating-a-pool "Direct link to Creating a Pool") To create a new Superfluid Pool, use the `createPool` function: function createPool( ISuperfluidToken token, address admin, PoolConfig memory config) external returns (bool success, ISuperfluidPool pool) #### Parameters[​](https://docs.superfluid.org/docs/sdk/distributions/create-manage-pools#parameters "Direct link to Parameters") * `token`: The Super Token address. * `admin`: The pool admin address. * `config`: The pool configuration (see below). The `PoolConfig` struct is defined as follows: struct PoolConfig { bool transferabilityForUnitsOwner; bool distributionFromAnyAddress;} * `transferabilityForUnitsOwner`: If true, the pool members can transfer their owned units, else, only the pool admin can manipulate the units for pool members * `distributionFromAnyAddress`: If true, anyone can execute distributions via the pool, else, only the pool admin can execute distributions via the pool Strong recommendation We don't recommend setting `transferabilityForUnitsOwner` to `true` unless you have a specific use case that absolutely requires it. This can sometimes lead to unexpected behavior and security risks. #### Usage Example[​](https://docs.superfluid.org/docs/sdk/distributions/create-manage-pools#usage-example "Direct link to Usage Example") const createPool = async (tokenAddress, adminAddress, config) => { try { const tx = await forwarderContract.createPool(tokenAddress, adminAddress, config); const receipt = await tx.wait(); const [success, poolAddress] = receipt.events.find(e => e.event === 'PoolCreated').args; console.log("Pool created successfully:", poolAddress); return poolAddress; } catch (error) { console.error("Error creating pool:", error); }}; ### Updating Member Units[​](https://docs.superfluid.org/docs/sdk/distributions/create-manage-pools#updating-member-units "Direct link to Updating Member Units") To update the units of a pool member, use the `updateMemberUnits` function: function updateMemberUnits( ISuperfluidPool pool, address memberAddress, uint128 newUnits, bytes memory userData) external #### Parameters[​](https://docs.superfluid.org/docs/sdk/distributions/create-manage-pools#parameters-1 "Direct link to Parameters") * `pool`: The Superfluid Pool to update. * `memberAddress`: The address of the member to update. * `newUnits`: The new units of the member. * `userData`: User-specific data. #### Usage Example[​](https://docs.superfluid.org/docs/sdk/distributions/create-manage-pools#usage-example-1 "Direct link to Usage Example") const updateMemberUnits = async (poolAddress, memberAddress, newUnits, userData) => { try { const tx = await forwarderContract.updateMemberUnits(poolAddress, memberAddress, newUnits, userData); await tx.wait(); console.log("Member units updated successfully!"); } catch (error) { console.error("Error updating member units:", error); }}; Live UI Example for Distribution Pool Management[​](https://docs.superfluid.org/docs/sdk/distributions/create-manage-pools#live-ui-example-for-distribution-pool-management "Direct link to Live UI Example for Distribution Pool Management") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Here's an example of a UI component for creating and managing distribution pools: Live Editor function DistributionPoolManager() { const \[tokenAddress, setTokenAddress\] \= useState(''); const \[adminAddress, setAdminAddress\] \= useState(''); const \[poolAddress, setPoolAddress\] \= useState(''); const \[memberAddress, setMemberAddress\] \= useState(''); const \[newUnits, setNewUnits\] \= useState(''); const \[walletConnected, setWalletConnected\] \= useState(false); const \[account, setAccount\] \= useState(''); const toast \= useToast(); const forwarderAddress \= '0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08'; const forwarderABI \= GDAv1ForwarderABI; // You will need to import the ABI in your code. You can do that from: https://docs.superfluid.finance/docs/technical-reference/CFAv1Forwarder const connectWallet \= async () \=> { if (typeof window.ethereum !== 'undefined') { try { await window.ethereum.request({ method: 'eth\_requestAccounts' }); const provider \= new ethers.providers.Web3Provider(window.ethereum); const signer \= provider.getSigner(); const address \= await signer.getAddress(); setAccount(address); setWalletConnected(true); toast({ title: 'Wallet connected', description: \`Connected to ${address}\`, status: 'success', duration: 3000, isClosable: true, }); } catch (error) { console.error('Failed to connect wallet:', error); toast({ title: 'Connection failed', description: 'Failed to connect wallet. Please try again.', status: 'error', duration: 3000, isClosable: true, }); } } else { toast({ title: 'Metamask not detected', description: 'Please install Metamask to use this feature.', status: 'warning', duration: 3000, isClosable: true, }); } }; const createPool \= async () \=> { if (!walletConnected) { toast({ title: 'Wallet not connected', description: 'Please connect your wallet first.', status: 'warning', duration: 3000, isClosable: true, }); return; } const provider \= new ethers.providers.Web3Provider(window.ethereum); const signer \= provider.getSigner(); const contract \= new ethers.Contract(forwarderAddress, forwarderABI, signer); try { // For simplicity, we're using a basic pool configuration here const config \= { transferabilityForUnitsOwner: 0, // Non-transferable distributionFromAnyAddress: false }; const tx \= await contract.createPool(tokenAddress, adminAddress, config); const receipt \= await tx.wait(); const \[success, poolAddress\] \= receipt.events.find(e \=> e.event \=== 'PoolCreated').args; setPoolAddress(poolAddress); toast({ title: 'Pool created', description: \`Pool created successfully at ${poolAddress}\`, status: 'success', duration: 5000, isClosable: true, }); } catch (error) { console.error('Error creating pool:', error); toast({ title: 'Error', description: 'Failed to create pool. Please try again.', status: 'error', duration: 3000, isClosable: true, }); } }; const updateMemberUnits \= async () \=> { if (!walletConnected) { toast({ title: 'Wallet not connected', description: 'Please connect your wallet first.', status: 'warning', duration: 3000, isClosable: true, }); return; } const provider \= new ethers.providers.Web3Provider(window.ethereum); const signer \= provider.getSigner(); const contract \= new ethers.Contract(forwarderAddress, forwarderABI, signer); try { const tx \= await contract.updateMemberUnits(poolAddress, memberAddress, newUnits, "0x"); await tx.wait(); toast({ title: 'Units updated', description: 'Member units updated successfully', status: 'success', duration: 3000, isClosable: true, }); } catch (error) { console.error('Error updating member units:', error); toast({ title: 'Error', description: 'Failed to update member units. Please try again.', status: 'error', duration: 3000, isClosable: true, }); } }; return ( Distribution Pool Manager {!walletConnected ? ( )}
{walletAddress && ( <>
setSuperToken(e.target.value)} style={{ margin: "5px", padding: "5px" }} /> setReceivers(e.target.value)} style={{ margin: "5px", padding: "5px" }} />

{message}

)}
);}; The `MacroForwarderComponent` is a simple React component that allows you to connect your wallet and execute the macro using EthersJS. If you deployed your own `MultiFlowDeleteMacro` contract, you can use the `MacroForwarderComponent` to batch call the transactions by inputing the `MacroForwarder` and `MultiFlowDeleteMacro` contract addresses in the playground below. Live Editor function MacroComponentExample() { const macroForwarderAddress\="0xFD0268E33111565dE546af2675351A4b1587F89F"; const userMacroAddress\="0x997b37Fb47c489CF067421aEeAf7Be0543fA5362"; return ( ); } Result Loading... Next Steps - EIP-712 Support[​](https://docs.superfluid.org/docs/sdk/advanced-topics/batch-calls-macro#next-steps---eip-712-support "Direct link to Next Steps - EIP-712 Support") ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- We will provide a guide which laverages [EIP-712](https://eips.ethereum.org/EIPS/eip-712) for typed structured data hashing and signing, enhancing the security and usability of macro transactions. This will allow for the following features: * On-chain verifiable signatures. * Multilingual support for transaction signing. * Supports meta transactions, allowing for gas-less transactions. * And more... * [Background](https://docs.superfluid.org/docs/sdk/advanced-topics/batch-calls-macro#background) * [Macro Forwarder Contract Overview](https://docs.superfluid.org/docs/sdk/advanced-topics/batch-calls-macro#macro-forwarder-contract-overview) * [Macro Forwarder Contract Address](https://docs.superfluid.org/docs/sdk/advanced-topics/batch-calls-macro#macro-forwarder-contract-address) * [Macro Forwarder Contract ABI](https://docs.superfluid.org/docs/sdk/advanced-topics/batch-calls-macro#macro-forwarder-contract-abi) * [How to use the Macro Forwarder](https://docs.superfluid.org/docs/sdk/advanced-topics/batch-calls-macro#how-to-use-the-macro-forwarder) * [1\. Create your contract and inherit the User Defined Macro Interface](https://docs.superfluid.org/docs/sdk/advanced-topics/batch-calls-macro#1-create-your-contract-and-inherit-the-user-defined-macro-interface) * [2\. Implement your Macro Interface](https://docs.superfluid.org/docs/sdk/advanced-topics/batch-calls-macro#2-implement-your-macro-interface) * [3\. Use the Macro Forwarder to batch call the transactions](https://docs.superfluid.org/docs/sdk/advanced-topics/batch-calls-macro#3-use-the-macro-forwarder-to-batch-call-the-transactions) * [Next Steps - EIP-712 Support](https://docs.superfluid.org/docs/sdk/advanced-topics/batch-calls-macro#next-steps---eip-712-support) --- # Connecting and Claiming from the Pools | Superfluid | Stream Money Every Second [Skip to main content](https://docs.superfluid.org/docs/sdk/distributions/connect-claim-pool#__docusaurus_skipToContent_fallback) On this page This guide focuses on connecting and claiming from Superfluid [Distribution Pools](https://docs.superfluid.org/docs/concepts/overview/distributions) using the `GDAv1Forwarder` contract. You'll learn how to interact with Superfluid pools from client applications. We will specifically show how you can connect members to pools, and claim tokens from them. Interacting with the Superfluid Protocol[​](https://docs.superfluid.org/docs/sdk/distributions/connect-claim-pool#interacting-with-the-superfluid-protocol "Direct link to Interacting with the Superfluid Protocol") ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- To interact with Superfluid's distribution pools from client applications, you'll use the `GDAv1Forwarder` contract. Here's how to set it up: ### Contract ABI and Address[​](https://docs.superfluid.org/docs/sdk/distributions/connect-claim-pool#contract-abi-and-address "Direct link to Contract ABI and Address") The `GDAv1Forwarder` contract address is the same on all Superfluid chains: 0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08 You can find the full ABI of the `GDAv1Forwarder` contract in the [GDAv1Forwarder technical reference](https://docs.superfluid.org/docs/technical-reference/GDAv1Forwarder) . ### Setting up with ethers.js[​](https://docs.superfluid.org/docs/sdk/distributions/connect-claim-pool#setting-up-with-ethersjs "Direct link to Setting up with ethers.js") Here's how to initiate interaction with the `GDAv1Forwarder` contract using ethers.js: import { ethers } from 'ethers';// Assuming you have a provider set up (e.g., using MetaMask)const provider = new ethers.providers.Web3Provider(window.ethereum);// The address of the GDAv1Forwarder contractconst forwarderAddress = '0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08';// The ABI of the GDAv1Forwarder contract (import this from the technical reference)const forwarderABI = [...]; // Insert the ABI here// Create a contract instanceconst forwarderContract = new ethers.Contract(forwarderAddress, forwarderABI, provider.getSigner()); Understanding Connecting and Claiming[​](https://docs.superfluid.org/docs/sdk/distributions/connect-claim-pool#understanding-connecting-and-claiming "Direct link to Understanding Connecting and Claiming") ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- When interacting with Superfluid pools, it's important to understand the difference between connecting to a pool and claiming from it: 1. **Connecting to a Pool**: * When a member connects to a pool, they start receiving streams and transfers in real-time. * The member's balance will automatically reflect incoming tokens without any further action. * This is ideal for continuous, real-time token distribution. 2. **Claiming from a Pool**: * Claiming is the process of explicitly withdrawing accumulated tokens from the pool. * Members can claim periodically to move tokens from the pool to their personal balance. * This is useful for members who prefer to manually manage their token receipts or for specific accounting purposes. In essence, connecting provides a passive, continuous flow of tokens, while claiming is an active process to withdraw accumulated tokens. Interacting with the GDAv1Forwarder Contract[​](https://docs.superfluid.org/docs/sdk/distributions/connect-claim-pool#interacting-with-the-gdav1forwarder-contract "Direct link to Interacting with the GDAv1Forwarder Contract") ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Let's look at how to use the `GDAv1Forwarder` contract to connect, disconnect, and claim from pools. ### Connecting to a Pool[​](https://docs.superfluid.org/docs/sdk/distributions/connect-claim-pool#connecting-to-a-pool "Direct link to Connecting to a Pool") To connect a member to a pool, use the `connectPool` function: function connectPool( ISuperfluidPool pool, bytes memory userData) external returns (bool) #### Parameters[​](https://docs.superfluid.org/docs/sdk/distributions/connect-claim-pool#parameters "Direct link to Parameters") * `pool`: The Superfluid Pool to connect. * `userData`: User-specific data. #### Usage Example[​](https://docs.superfluid.org/docs/sdk/distributions/connect-claim-pool#usage-example "Direct link to Usage Example") const connectPool = async (poolAddress, userData = "0x") => { try { const tx = await forwarderContract.connectPool(poolAddress, userData); const receipt = await tx.wait(); console.log("Successfully connected to pool"); return receipt.status === 1; // 1 indicates success } catch (error) { console.error("Error connecting to pool:", error); return false; }}; Connecting triggers a claim When a member connects to a pool, the contract automatically claims all the previously available tokens for the member. ### Disconnecting from a Pool[​](https://docs.superfluid.org/docs/sdk/distributions/connect-claim-pool#disconnecting-from-a-pool "Direct link to Disconnecting from a Pool") To disconnect a member from a pool, use the `disconnectPool` function: function disconnectPool( ISuperfluidPool pool, bytes memory userData) external returns (bool) #### Parameters[​](https://docs.superfluid.org/docs/sdk/distributions/connect-claim-pool#parameters-1 "Direct link to Parameters") * `pool`: The Superfluid Pool to disconnect. * `userData`: User-specific data. #### Usage Example[​](https://docs.superfluid.org/docs/sdk/distributions/connect-claim-pool#usage-example-1 "Direct link to Usage Example") const disconnectPool = async (poolAddress, userData = "0x") => { try { const tx = await forwarderContract.disconnectPool(poolAddress, userData); const receipt = await tx.wait(); console.log("Successfully disconnected from pool"); return receipt.status === 1; // 1 indicates success } catch (error) { console.error("Error disconnecting from pool:", error); return false; }}; ### Claiming All Tokens from a Pool[​](https://docs.superfluid.org/docs/sdk/distributions/connect-claim-pool#claiming-all-tokens-from-a-pool "Direct link to Claiming All Tokens from a Pool") To claim all available tokens for a member from a pool, use the `claimAll` function: function claimAll( ISuperfluidPool pool, address memberAddress, bytes memory userData) external #### Parameters[​](https://docs.superfluid.org/docs/sdk/distributions/connect-claim-pool#parameters-2 "Direct link to Parameters") * `pool`: The Superfluid Pool to claim from. * `memberAddress`: The address of the member to claim for. * `userData`: User-specific data. #### Usage Example[​](https://docs.superfluid.org/docs/sdk/distributions/connect-claim-pool#usage-example-2 "Direct link to Usage Example") const claimAll = async (poolAddress, memberAddress, userData = "0x") => { try { const tx = await forwarderContract.claimAll(poolAddress, memberAddress, userData); await tx.wait(); console.log("Successfully claimed all tokens from pool"); return true; } catch (error) { console.error("Error claiming tokens from pool:", error); return false; }}; Live UI Example for Pool Interaction[​](https://docs.superfluid.org/docs/sdk/distributions/connect-claim-pool#live-ui-example-for-pool-interaction "Direct link to Live UI Example for Pool Interaction") ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Here's an example of a UI component for connecting, disconnecting, and claiming from Superfluid pools: Live Editor function PoolInteractionManager() { const \[poolAddress, setPoolAddress\] \= useState(''); const \[memberAddress, setMemberAddress\] \= useState(''); const \[walletConnected, setWalletConnected\] \= useState(false); const \[account, setAccount\] \= useState(''); const toast \= useToast(); const forwarderAddress \= '0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08'; const forwarderABI \= GDAv1ForwarderABI; // You will need to import the ABI in your code. You can do that from: https://docs.superfluid.finance/docs/technical-reference/CFAv1Forwarder const connectWallet \= async () \=> { if (typeof window.ethereum !== 'undefined') { try { await window.ethereum.request({ method: 'eth\_requestAccounts' }); const provider \= new ethers.providers.Web3Provider(window.ethereum); const signer \= provider.getSigner(); const address \= await signer.getAddress(); setAccount(address); setWalletConnected(true); toast({ title: 'Wallet connected', description: \`Connected to ${address}\`, status: 'success', duration: 3000, isClosable: true, }); } catch (error) { console.error('Failed to connect wallet:', error); toast({ title: 'Connection failed', description: 'Failed to connect wallet. Please try again.', status: 'error', duration: 3000, isClosable: true, }); } } else { toast({ title: 'Metamask not detected', description: 'Please install Metamask to use this feature.', status: 'warning', duration: 3000, isClosable: true, }); } }; const performAction \= async (action) \=> { if (!walletConnected) { toast({ title: 'Wallet not connected', description: 'Please connect your wallet first.', status: 'warning', duration: 3000, isClosable: true, }); return; } const provider \= new ethers.providers.Web3Provider(window.ethereum); const signer \= provider.getSigner(); const contract \= new ethers.Contract(forwarderAddress, forwarderABI, signer); try { let tx; switch (action) { case 'connect': tx \= await contract.connectPool(poolAddress, "0x"); break; case 'disconnect': tx \= await contract.disconnectPool(poolAddress, "0x"); break; case 'claim': tx \= await contract.claimAll(poolAddress, memberAddress || account, "0x"); break; } await tx.wait(); toast({ title: 'Action successful', description: \`Successfully ${action}ed ${action \=== 'claim' ? 'from' : 'to'} pool\`, status: 'success', duration: 3000, isClosable: true, }); } catch (error) { console.error(\`Error ${action}ing:\`, error); toast({ title: 'Action failed', description: \`Failed to ${action} ${action \=== 'claim' ? 'from' : 'to'} pool. Please try again.\`, status: 'error', duration: 3000, isClosable: true, }); } }; return ( Pool Interaction Manager {!walletConnected ? ( );} ### Using Ethers.js Directly[​](https://docs.superfluid.org/docs/sdk/advanced-topics/batch-calls-forwarder#using-ethersjs-directly "Direct link to Using Ethers.js Directly") For applications not using React hooks: import { ethers } from 'ethers';import { hostAbi, hostAddress, superTokenAbi, cfaForwarderAbi } from '@superfluid-finance/sdk-core';async function executeBatchCall(provider, signer) { const hostContract = new ethers.Contract( "0x109412E3C84f0539b43d39dB691B08c90f58dC7c", // Base Sepolia Host hostAbi, signer ); const operations = [ // Upgrade operation { operationType: 101, target: '0x...', // Super Token address data: ethers.utils.defaultAbiCoder.encode( ['uint256'], [ethers.utils.parseEther('100')] ) }, // Create flow operation { operationType: 201, target: '0x...', // CFA Forwarder address data: ethers.utils.defaultAbiCoder.encode( ['bytes', 'bytes'], [ ethers.utils.defaultAbiCoder.encode( ['address', 'address', 'address', 'int96', 'bytes'], ['0x...', signer.address, '0x...', '1000000000000000', '0x'] ), '0x' ] ) } ]; const tx = await hostContract.batchCall(operations); await tx.wait(); console.log('Batch call executed:', tx.hash);} Common Batch Call Patterns[​](https://docs.superfluid.org/docs/sdk/advanced-topics/batch-calls-forwarder#common-batch-call-patterns "Direct link to Common Batch Call Patterns") --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### 1\. Wrap and Stream Pattern[​](https://docs.superfluid.org/docs/sdk/advanced-topics/batch-calls-forwarder#1-wrap-and-stream-pattern "Direct link to 1. Wrap and Stream Pattern") Upgrade underlying tokens to Super Tokens and immediately start streaming: Approval Required The underlying token approval cannot be included in the batch call because `msg.sender` changes when operations go through the Superfluid Host. You must approve the underlying token separately before executing the batch. const wrapAndStreamOperations = [ // Upgrade tokens to Super Token { operationType: 101, // SUPERTOKEN_UPGRADE target: superTokenAddress, data: ethers.utils.defaultAbiCoder.encode( ['uint256'], [ethers.utils.parseEther('1000')] ) }, // Create flow { operationType: 201, // SUPERFLUID_CALL_AGREEMENT target: cfaForwarderAddress, data: ethers.utils.defaultAbiCoder.encode( ['bytes', 'bytes'], [ ethers.utils.defaultAbiCoder.encode( ['address', 'address', 'address', 'int96', 'bytes'], [superTokenAddress, senderAddress, receiverAddress, flowRate, '0x'] ), '0x' ] ) }]; ### 2\. Multi-Flow Management[​](https://docs.superfluid.org/docs/sdk/advanced-topics/batch-calls-forwarder#2-multi-flow-management "Direct link to 2. Multi-Flow Management") Update multiple flows in a single transaction: const receivers = [ { address: '0x123...', flowRate: '1000000000000000' }, { address: '0x456...', flowRate: '2000000000000000' }, { address: '0x789...', flowRate: '1500000000000000' }];const multiFlowOperations = receivers.map(receiver => ({ operationType: 201, // SUPERFLUID_CALL_AGREEMENT target: cfaForwarderAddress, data: ethers.utils.defaultAbiCoder.encode( ['bytes', 'bytes'], [ ethers.utils.defaultAbiCoder.encode( ['address', 'address', 'address', 'int96', 'bytes'], [superTokenAddress, senderAddress, receiver.address, receiver.flowRate, '0x'] ), '0x' ] )})); ### 3\. Pool Distribution Batch[​](https://docs.superfluid.org/docs/sdk/advanced-topics/batch-calls-forwarder#3-pool-distribution-batch "Direct link to 3. Pool Distribution Batch") Create a pool and distribute tokens: const poolOperations = [ // Create pool { operationType: 201, // SUPERFLUID_CALL_AGREEMENT target: gdaForwarderAddress, data: ethers.utils.defaultAbiCoder.encode( ['bytes', 'bytes'], [ ethers.utils.defaultAbiCoder.encode( ['address', 'address', 'tuple(bool,bool)'], [superTokenAddress, adminAddress, [true, false]] ), '0x' ] ) }, // Distribute to pool { operationType: 201, // SUPERFLUID_CALL_AGREEMENT target: gdaForwarderAddress, data: ethers.utils.defaultAbiCoder.encode( ['bytes', 'bytes'], [ ethers.utils.defaultAbiCoder.encode( ['address', 'address', 'address', 'uint256', 'bytes'], [superTokenAddress, senderAddress, poolAddress, distributionAmount, '0x'] ), '0x' ] ) }]; Complete Example: Batch Flow Manager[​](https://docs.superfluid.org/docs/sdk/advanced-topics/batch-calls-forwarder#complete-example-batch-flow-manager "Direct link to Complete Example: Batch Flow Manager") -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Here's a complete React component that demonstrates batch flow management: Live Editor function BatchFlowManager() { const \[tokenAddress, setTokenAddress\] \= useState(''); const \[receivers, setReceivers\] \= useState(''); const \[flowRates, setFlowRates\] \= useState(''); const \[walletConnected, setWalletConnected\] \= useState(false); const \[account, setAccount\] \= useState(''); const \[message, setMessage\] \= useState(''); const hostAddress \= '0x109412E3C84f0539b43d39dB691B08c90f58dC7c'; // Base Sepolia const cfaForwarderAddress \= '0xcfA132E353cB4E398080B9700609bb008eceB125'; // Base Sepolia const hostABI \= \[ { "inputs": \[ { "components": \[ { "internalType": "uint32", "name": "operationType", "type": "uint32" }, { "internalType": "address", "name": "target", "type": "address" }, { "internalType": "bytes", "name": "data", "type": "bytes" } \], "internalType": "struct ISuperfluid.Operation\[\]", "name": "operations", "type": "tuple\[\]" } \], "name": "batchCall", "outputs": \[\], "stateMutability": "nonpayable", "type": "function" } \]; const connectWallet \= async () \=> { if (typeof window.ethereum !== 'undefined') { try { await window.ethereum.request({ method: 'eth\_requestAccounts' }); const provider \= new ethers.providers.Web3Provider(window.ethereum); const signer \= provider.getSigner(); const address \= await signer.getAddress(); setAccount(address); setWalletConnected(true); setMessage(\`Connected to ${address}\`); } catch (error) { setMessage('Failed to connect wallet'); } } else { setMessage('Please install MetaMask'); } }; const executeBatchFlows \= async () \=> { if (!walletConnected) { setMessage('Please connect wallet first'); return; } try { const provider \= new ethers.providers.Web3Provider(window.ethereum); const signer \= provider.getSigner(); const hostContract \= new ethers.Contract(hostAddress, hostABI, signer); // Parse receivers and flow rates const receiverList \= receivers.split(',').map(r \=> r.trim()); const flowRateList \= flowRates.split(',').map(r \=> r.trim()); if (receiverList.length !== flowRateList.length) { setMessage('Number of receivers must match number of flow rates'); return; } // Create operations for each flow const operations \= receiverList.map((receiver, index) \=> ({ operationType: 201, // SUPERFLUID\_CALL\_AGREEMENT target: cfaForwarderAddress, data: ethers.utils.defaultAbiCoder.encode( \['bytes', 'bytes'\], \[ ethers.utils.defaultAbiCoder.encode( \['address', 'address', 'address', 'int96', 'bytes'\], \[tokenAddress, account, receiver, flowRateList\[index\], '0x'\] ), '0x' \] ) })); const tx \= await hostContract.batchCall(operations); await tx.wait(); setMessage(\`Batch flows created successfully! TX: ${tx.hash}\`); } catch (error) { setMessage(\`Error: ${error.message}\`); } }; return (
Batch Flow Manager {!walletConnected ? (