Skip to main content

Create a Lockup Linear Stream

Linear streams are streams with a linear streaming function. In this guide, we will show you how to create a Lockup Linear stream using Solidity.

This guide assumes that you have already gone through the Protocol Concepts section.

caution

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

Import the relevant symbols from @sablier/lockup:

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ISablierLockup } from "@sablier/lockup/src/interfaces/ISablierLockup.sol";
import { Lockup } from "@sablier/lockup/src/types/Lockup.sol";
import { LockupLinear } from "@sablier/lockup/src/types/LockupLinear.sol";

Create a contract called LockupLinearStreamCreator, and declare a constant DAI of type IERC20 and a constant LOCKUP of type ISablierLockup:

contract LockupLinearStreamCreator {
IERC20 public constant DAI = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F);
ISablierLockup public constant LOCKUP = ISablierLockup(0xcF8ce57fa442ba50aCbC57147a62aD03873FfA73);
}

In the code above, the contract addresses are hard-coded for demonstration purposes. However, in production, you would likely use input parameters to allow flexibility in changing the addresses.

Also, these addresses are deployed on Ethereum Sepolia. If you need to work with a different chain, Lockup addresses can be obtained from the Lockup Deployments page.

There are two create functions in the Lockup contract that can be used to create Linear streams:

  • createWithDurationsLL: takes duration and calculates the start and end timestamps based on the provided durations.
  • createWithTimestampsLL: takes start and end timestamps.

Which one you choose depends upon your use case. In this guide, we will use createWithDurationsLL.

Function definition

Define a function called createStream which takes a single parameter depositAmount, and which returns the id of the created stream:

function createStream(uint128 depositAmount) public returns (uint256 streamId) {
// ...
}

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 approve the Lockup contract to pull the tokens 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), depositAmount);

// Approve the Sablier contract to spend DAI
DAI.approve(address(LOCKUP), depositAmount);

For more guidance on how to approve and transfer ERC-20 tokens, see this article on the Ethereum website.

Parameters

The struct associated with createWithDurationsLL are Lockup.CreateWithDurations (a shared struct across all the lockup streams), LockupLinear.Durations and LockupLinear.UnlockAmounts.

Lockup.CreateWithDurations memory params;
LockupLinear.UnlockAmounts memory unlockAmounts;
LockupLinear.Durations memory durations;

Let's review each parameter in detail.

Sender

The address streaming the tokens, with the ability to cancel the stream:

params.sender = msg.sender;

Recipient

The address receiving the tokens:

params.recipient = address(0xCAFE);

Deposit amount

The deposit amount of ERC-20 tokens to be paid, denoted in units of the token's decimals.

params.depositAmount = depositAmount;

Token

The contract address of the ERC-20 token used for streaming. In this example, we will stream DAI:

params.token = DAI;

Cancelable

Boolean that indicates whether the stream will be cancelable or not.

params.cancelable = true;

Transferable

Boolean that indicates whether the stream will be transferable or not.

params.transferable = true;

Unlock Amounts

Struct containing details on unlock amounts at start time and at cliff time.

unlockAmounts = LockupLinear.UnlockAmounts({ start: 0, cliff: 0 });

Durations

Struct containing (i) cliff duration and (ii) total stream duration, both denoted in seconds.

durations = LockupLinear.Durations({
cliff: 0,
total: 52 weeks
});

Invoke the create function

With all parameters set, we can now call the createWithDurationsLL function, and assign the id of the newly created stream to a variable:

streamId = LOCKUP.createWithDurationsLL(params, unlockAmounts, durations);

Full code

Below you can see the full code. You can also access the code on GitHub through this link.

Lockup Linear Stream Creator
loading...