Skip to main content

Calculate Rate per Second

This guide explains how to calculate the rate per second when creating a Flow stream. It is the most important step in setting up a stream since the rate per second is a key parameter in the stream's configuration.

We assume that you have already gone through the Protocol Concepts and the Flow Overview sections.

caution

The code in this guide is not production-ready, and is implemented in a simplistic manner for the purpose of learning.

The rate per second is the amount of tokens streamed in one second. It is represented as a fixed-point number with 18 decimals, specifically as a UD21x18 type from the PRBMath library. The underlying native Solidity type associated with UD21x18 is uint128.

Depending on how you receive payments, you have to calculate the rate per second and scale its value to 18 decimals format as below:

  1. Based on a duration, e.g., 3 months
  2. Between two points in time, e.g., January 1, 2025 to April, 1 2025

The calculation method is the same in either case.

Set up a library

Declare the Solidity version used to compile the library:

pragma solidity >=0.8.22;

Import the relevant symbols:

import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { ud21x18, UD21x18 } from "@prb/math/src/UD21x18.sol";

Declare a library that can be used in other contracts:

library FlowUtilities {}

Calculate the rate per second on a duration

Define a function called ratePerSecondWithDuration that takes the following parameters and the returned value:

function ratePerSecondWithDuration(
address token,
uint128 amount,
uint40 duration
)
internal
view
returns (UD21x18 ratePerSecond)
{
// ...
}

First, retrieve the token's decimals. Note that not all ERC-20 tokens use the 18-decimal standard.

uint8 decimals = IERC20Metadata(token).decimals();

If the token uses 18 decimals, simply divide the amount by the duration:

if (decimals == 18) {
return ud21x18(amount / duration);
}

If the token has less than 18 decimals, calculate the scale factor from the token's decimals:

uint128 scaleFactor = uint128(10 ** (18 - decimals));

Then, multiply the amount by the scale factor and divide it by the duration:

return ud21x18((amount * scaleFactor) / duration);

Calculate the rate per second on timestamps

Here, there are two time parameters, a start and an end time, instead of a duration. Let's define the function:

function ratePerSecondForTimestamps(
address token,
uint128 amount,
uint40 start,
uint40 end
)
internal
view
returns (UD21x18 ratePerSecond)
{
// ...
}

The first step is to calculate the duration between the two timestamps:

uint40 duration = end - start;

The remaining logic is identical to the duration-based calculation:

uint8 decimals = IERC20Metadata(token).decimals();

if (decimals == 18) {
return ud21x18(amount / duration);
}

uint128 scaleFactor = uint128(10 ** (18 - decimals));

ratePerSecond = ud21x18((scaleFactor * amount) / duration);

Additional utilities

To calculate earnings for specific durations from an existing stream, you can use the following functions:

function calculateAmountStreamedPerWeek(UD21x18 ratePerSecond) internal pure returns (uint128 amountPerWeek) {
amountPerWeek = ratePerSecond.unwrap() * 1 weeks;
}

function calculateAmountStreamedPerMonth(UD21x18 ratePerSecond) internal pure returns (uint128 amountPerMonth) {
amountPerMonth = ratePerSecond.unwrap() * 30 days;
}

function calculateAmountStreamedPerYear(UD21x18 ratePerSecond) internal pure returns (uint128 amountPerYear) {
amountPerYear = ratePerSecond.unwrap() * 365 days;
}

Full code

Below you can see the complete FlowUtilities library:

Flow Utilities library
loading...