Skip to main content

Distribution Pools

In this page we will explain Distribution Pools and show you the most relevant ways to interact with them through the Super Token interface. To do this, we will go through some key concepts, and show you how to leverage Superfluid's SuperTokenV1Library.sol for your Distribution Pools smart contracts.

About SuperTokenV1Library.sol

The SuperTokenV1Library.sol is a comprehensive library that enables interactions with all of the Superfluid components (including Pools) through the SuperToken interface.

About the General Distributions Agreement - GDA

At times, we use "Distribution Pools" or the "General Distributions Agreement (GDA)" interchangeably due to "GDA" being the name of the implementation in our codebase.

What is a Pool?

A pool is a smart contract that facilitates the distribution of tokens to multiple members, managed by a pool admin. Members hold units within the pool that determine their proportion of the distribution.

A visualization of units in a pool

note

The Superfluid pool implements basic ERC20 functionality, allowing it to interact seamlessly with ERC20 standards. This allows you to interact with the pool units as if they were ERC20 tokens, including transferring them to other addresses, if it is allowed by the pool configuration. Check the next section for more information on pool configurations.

About Member Units

How is a member's share of the pool determined?

A pool member's units determine their share of the pool's distributions. In the background, the calculation of each member's share is calculated following these two steps:

  1. Calculating the flow rate per unit: We calculate the flow rate or amount of tokens to be distributed per unit like so:
Superfluid with people

  1. Calculating the flow rate for each member: We multiply the flow rate per unit by the number of units each member has to get the flow rate for each member, as follows:
Superfluid with people

One of the limitations of Solidity is its incapacity to handle floating point numbers. This makes it so that the flow rate per unit is calculated as an integer. If the result of the division is not an integer, the result is rounded down.

Examples

The examples below show how the flow rate per unit is calculated in different scenarios where Distributions reach their limitations

  1. Example 1: Let's take a pool that has 100 wei/second as total flow rate and 3 members, each member has 1 unit.
    • The flow rate per unit is 100 / 3 = 33.33
    • However, since Solidity can't handle floating point numbers, the flow rate per unit is 33
    • The pool distributes 33 tokens to each unit
    • 1 token is left undistributed
  2. Example 2: Let's take a pool that has 100 wei/second as total flow rate and 200 members, each member has 1 units.
    • The flow rate per unit is 100 / 200 = 0.5
    • However, since Solidity can't handle floating point numbers, the flow rate per unit is 0
    • The pool distributes 0 tokens to each unit
    • 200 tokens are left undistributed

These examples are extreme and almost never happen in practice. However, it is important to be aware of these limitations when designing your pools.

How to design your pools?

The best way to design your pools is to make sure that the total flow rate or the tokens distributed are always orders of magnitude higher than the number of total units in the pool. This way, you can be sure that the flow rate per unit will always be significantly higher than 0 and that all members will receive a share of the distribution.

About Pool Connections and Claiming

What is the difference between connecting to a pool and claiming tokens?

After creating a pool and assigning units to pool members, they need to connect to the pool or claim their Super Tokens in order for it to show on their balance. Simply assigning units (shares) to a member does not automatically reflect in their balance. The accumulated tokens NEED to be claimed by the member (or a different address), or the member needs to connect to the pool to start receiving their share of the Super Token Distributions.

How can members collect their Distributions from the pool?

There are two ways for members to get their streamed or transfered Super Tokens from a pool:

  • Connecting to the Pool (Recommended): Members should connect to the pool to start receiving their share of the Super Token Distributions in real time to their balance. This includes both Instant Distributions and Streaming Distributions. In order to connect to the pool, the member should call the connectPool function from the SuperTokenV1Library or GDAv1Forwarder. The address calling the function should be the address of the member. Other addresses will not be able to connect a member to the pool.

  • Claiming the Tokens: Members can claim their share of the Super Token Distributions accumulated from the pool at any time, even if they are not connected to the pool. As a matter of fact, anyone can claim the tokens on behalf of the member. To do so, the function claimAll from the SuperTokenV1Library or GDAv1Forwarder should be called with the address of the member as the argument.

Connecting to the pool includes claiming

When a member connects to the pool, they automatically claim the accumulated tokens and start receiving the distributions in real time.

Reminder

We use the SuperTokenV1Library to interact with the Superfluid protocol on-chain (from your smart contracts), while we use the forwarders (eg. GDAv1Forwarder) to interact with the Superfluid protocol off-chain (from your web3 frontend applications).

Recommendation

It is recommended to prompt users to connect to the pool as soon as possible to start receiving the distributions in real time. Depending on your use case, periodic claiming may also offer the best UX, however pool connections usually offer the best UX for real-time distributions.

How can members disconnect from the pool?

Members can always disconnect from the pool to stop receiving distributions in real time by calling the function disconnectPool from the SuperTokenV1Library or GDAv1Forwarder.

Example

  • Jake creates a pool and assigns 100 units to Alice, 200 units to Bob, and 200 units to Charlie.
  • Alice connects to the pool before any Distribution is made. Thus, she's able to receive her share of the Distributions in real time when they start.
  • Jake starts a stream of 100 tokens/second to the pool.
  • Alice receives 33 tokens/second directly into her balance, Bob and Charlie each accumulate 66 tokens/second in the pool.
  • After 100 seconds, Alice can already see 3300 tokens on her balance. Bob and Charlie are each eligible to get 6600 tokens, but they cannot see them on their balance just yet.
  • Bob chooses to claim every 100 seconds, while Charlie chooses to connect to the pool.
  • Bob receives periodically 6600 tokens every 100 seconds.
  • By connecting to the pool, Charlie automatically claims the accumulated tokens, but also starts receiving tokens in real time.

Important Functions

Here are some of the most important functions provided by SuperTokenV1Library.sol for interacting with Superfluid pools:

Reminder

These functions are meant to be called from contracts that import SuperTokenV1Library.sol and are not directly accessible as external calls on the blockchain.

createPool

function createPool(ISuperToken token, address admin, PoolConfig memory poolConfig)

Creates a new pool with the specified admin, configuration and poolConfig.

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

updateMemberUnits

function updateMemberUnits(ISuperToken token, ISuperfluidPool pool, address memberAddress, uint128 newUnits)

Updates the number of units a member has within a pool, effectively changing their share of future distributions.

Important

Keep in mind that the total amount of units in the pool needs to be significantly lower than the total flow rate or the total tokens distributed of the pool. To understand more why this is the case, please refer to the Member Units section.

claimAll

function claimAll(ISuperToken token, ISuperfluidPool pool, address memberAddress)

Allows a member to claim their share of the tokens from all previous distributions.

connectPool

function connectPool(ISuperToken token, ISuperfluidPool pool)

Connects a pool member to a pool.

About pool connections

The pool member needs to connect to a pool before the distribution balance is reflected in their net balance. If the distribution starts before the user is connected to the pool, the user will still receive the tokens when they connect to the pool eventually.

disconnectPool

function disconnectPool(ISuperToken token, ISuperfluidPool pool)

Disconnects a pool member from a pool.

distributeToPool

function distributeToPool(ISuperToken token, address from, ISuperfluidPool pool, uint256 requestedAmount)

Distributes a specified amount of tokens to the pool, to be shared among members according to their units.

Example Usage

Here's how you might use these functions within a smart contract to set up and manage a pool:

// Assume ISuperToken and SuperfluidPool interfaces are imported and available.

contract MyPool {
Using SuperTokenV1Library for ISuperToken;
ISuperToken private superToken;
ISuperfluidPool private pool;
PoolConfig private poolConfig = PoolConfig({
transferabilityForUnitsOwner: true,
distributionFromAnyAddress: true
});

constructor(ISuperToken _superToken) {
superToken = _superToken;
pool = superToken.createPool(address(this), poolConfig);
}

// Use updateMemberUnits to assign units to a member
function updateMemberUnits(address member, uint128 units) public {
superToken.updateMemberUnits(pool, member, units);
}

function distribute(uint256 amount) public {
superToken.distributeToPool(address(this), pool, amount);
}

function distributeFlow(int96 flowRate) public {
superToken.distributeFlow(address(this), pool, flowRate);
}
}

In this example, MyPool creates a pool, adds a member, and makes an Instant Distribution (discreet transfer - through distribute) and a Streaming Distribution (continuous flow - through distributeFlow) using the functions from SuperTokenV1Library.sol.

Learn more about the SuperTokenV1Library

For more detailed information on the implementation and usage of SuperTokenV1Library.sol, refer to the Technical Reference.