Create a Lockup Linear stream
Lockup Linear are streams with a strictly linear streaming function. In this guide, we will show you how to create a Lockup Linear stream programmatically.
This guide assumes that you have already gone through the Protocol Concepts section.
The code in this guide is not production-ready, and is implemented in a simplistic manner for the purpose of learning.
Set up a contract
Declare the Solidity version used to compile the contract:
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.19;
Import the relevant symbols from @sablier/v2-core
:
import { ISablierV2LockupLinear } from "@sablier/v2-core/interfaces/ISablierV2LockupLinear.sol";
import { Broker, LockupLinear } from "@sablier/v2-core/types/DataTypes.sol";
import { ud60x18 } from "@sablier/v2-core/types/Math.sol";
import { IERC20 } from "@sablier/v2-core/types/Tokens.sol";
Create a contract called LockupLinearStreamCreator
, and declare a constant DAI
of type IERC20
and an immutable
variable sablier
of type ISablierV2LockupLinear
:
contract LockupLinearStreamCreator {
IERC20 public constant DAI = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F);
ISablierV2LockupLinear public immutable sablier;
}
In the code above, the address of the DAI stablecoin is hard-coded. However, in production, you would likely use an input parameter to allow the contract to change the assets it interacts with on a per transaction basis.
Initialization
To initialize the Sablier contract, you first need to grab its address from the Deployment Addresses page. Once you have obtained it, pass it to the constructor of the creator contract:
constructor(ISablierV2LockupLinear sablier_) {
sablier = sablier_;
}
Create functions
There are two create functions in the Lockup Linear contract:
createWithDurations
: sets the start time toblock.timestamp
, and calculates the end time based on the provided durationscreateWithRange
: uses specific start and end times
Which one you choose depends upon your use case. In this guide, we will use createWithDurations
.
ERC-20 steps
To create a stream, the caller must approve the creator contract to pull the tokens from the calling address's account. Then, we have to also approve the Sablier contract to pull the assets that the creator contract will be in possession of after they are transferred from the calling address (you):
// Transfer the provided amount of DAI tokens to this contract
DAI.transferFrom(msg.sender, address(this), totalAmount);
// Approve the Sablier contract to spend DAI
DAI.approve(address(sablier), totalAmount);
For more guidance on how to approve and transfer ERC-20 assets, see this article on the Ethereum website.
Function definition
Define a function called createLockupLinearStream
which takes a single parameter totalAmount
, and which returns the
id of the created stream:
function createLockupLinearStream(uint256 totalAmount) external returns (uint256 streamId) {
// ...
}
Parameters
Sablier uses structs to encode the parameters of its create functions. The struct associated with createWithDurations
is LockupLinear.CreateWithDurations
, and it can be
initialized like this:
LockupLinear.CreateWithDurations memory params;
Let's review each parameter in detail.
Sender
The address streaming the assets, with the ability to cancel the stream:
params.sender = msg.sender;
Recipient
The address receiving the assets:
params.recipient = recipient;
Total amount
The total amount of ERC-20 assets to be paid, including the stream deposit and any potential fees, all denoted in units of the asset's decimals.
params.totalAmount = totalAmount;
Asset
The contract address of the ERC-20 asset used for streaming. In this example, we will stream DAI:
params.asset = DAI;
Cancelable
Boolean that indicates whether the stream will be cancelable or not.
params.cancelable = true;
Broker
An optional parameter that can be set in order to charge a fee as a percentage of totalAmount
.
In the following example, we will leave this parameter uninitialized (i.e. set to zero), because it doesn't make sense to charge yourself a fee. In practice, this parameter will mostly be used by front-end applications.
params.broker = Broker(address(0), ud60x18(0));
Wondering what's up with that ud60x18
function? It's a casting function that wraps a basic integer to the UD60x18
value type. This type is part of the math library PRBMath, which is used in
Sablier for fixed-point calculations.
Durations
Struct that encapsulates (i) the start time of the stream, (ii) the cliff time of the stream, and (iii) the end time of the stream, all as Unix timestamps.
params.durations = LockupLinear.Durations({
cliff: 4 weeks,
total: 52 weeks
});
Invoke the create function
With all parameters set, we can now call the createWithDurations
function, and assign the id of the newly created
stream to a variable:
streamId = sablier.createWithDurations(params);
The complete Lockup Linear stream creator contract
Below you can see the complete functioning code: a contract that creates Lockup Linear streams that start at
block.timestamp
. You can access the code on GitHub through
this link.
loading...