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.
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:
- Based on a duration, e.g., 3 months
- 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:
loading...