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...