Create a Batch of Lockup Tranched Streams
In this guide, we will show you how to programmatically batch create tranched streams via the Sablier's Batch contract.
This guide assumes that you have already gone through the Protocol Concepts section.
This guide interacts with the Periphery contract.
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;
Now, import the relevant symbols from @sablier/v2-core
and @sablier/v2-periphery
:
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ud60x18 } from "@prb/math/src/UD60x18.sol";
import { ISablierV2LockupTranched } from "@sablier/v2-core/src/interfaces/ISablierV2LockupTranched.sol";
import { Broker, LockupTranched } from "@sablier/v2-core/src/types/DataTypes.sol";
import { ISablierV2BatchLockup } from "@sablier/v2-periphery/src/interfaces/ISablierV2BatchLockup.sol";
import { BatchLockup } from "@sablier/v2-periphery/src/types/DataTypes.sol";
Create a contract called BatchLTStreamCreator
, and declare a constant DAI
of type IERC20
, a constant
LOCKUP_TRANCHED
of type ISablierV2LockupTranched
, and a constant BATCH
of type ISablierV2BatchLockup
:
contract BatchLTStreamCreator {
IERC20 public constant DAI = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F);
ISablierV2LockupTranched public constant LOCKUP_TRANCHED =
ISablierV2LockupTranched(0x7CC7e125d83A581ff438608490Cc0f7bDff79127);
ISablierV2BatchLockup public constant BATCH = ISablierV2BatchLockup(0xEa07DdBBeA804E7fe66b958329F8Fa5cDA95Bd55);
}
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 Mainnet. If you need to work with a different chain, the Sablier addresses can be obtained from the Deployment Addresses page.
Batch create functions
There are two batch create functions for the Lockup Tranched contract:
Which one you choose depends upon your use case. In this guide, we will use createWithTimestampsLT
.
Function definition
Define a function called batchCreateStreams
that takes a parameter perStreamAmount
and returns an array of ids for
the created streams:
function batchCreateStreams(uint128 perStreamAmount) public returns (uint256[] memory streamIds) {
// ...
}
Batch size
Next, declare a batch size, which is needed to calculate the transfer amount:
// Create a batch of two streams
uint256 batchSize = 2;
// Calculate the combined amount of DAI assets to transfer to this contract
uint256 transferAmount = perStreamAmount * batchSize;
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 Batch
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), transferAmount);
// Approve the Batch contract to spend DAI
DAI.approve(address(BATCH_LOCKUP), transferAmount);
For more guidance on how to approve and transfer ERC-20 assets, see this article on the Ethereum website.
Stream Parameters
Given that we declared a batchSize
of two, we need to define two
BatchLockup.CreateWithTimestampsLT
structs:
// Declare the first stream in the batch
BatchLockup.CreateWithTimestampsLT memory stream0;
stream0.sender = address(0xABCD); // The sender to stream the assets, he will be able to cancel the stream
stream0.recipient = address(0xCAFE); // The recipient of the streamed assets
stream0.totalAmount = perStreamAmount; // The total amount of each stream, inclusive of all fees
stream0.cancelable = true; // Whether the stream will be cancelable or not
stream0.transferable = false; // Whether the recipient can transfer the NFT or not
stream0.startTime = uint40(block.timestamp); // Set the start time to block timestamp
// Declare some dummy tranches
stream0.tranches = new LockupTranched.Tranche[](2);
stream0.tranches[0] = LockupTranched.Tranche({
amount: uint128(perStreamAmount / 2),
timestamp: uint40(block.timestamp + 1 weeks)
});
stream0.tranches[1] = LockupTranched.Tranche({
amount: uint128(perStreamAmount - stream0.tranches[0].amount),
timestamp: uint40(block.timestamp + 24 weeks)
});
stream0.broker = Broker(address(0), ud60x18(0)); // Optional parameter left undefined
To add some variety, we will change the parameters of the second stream:
BatchLockup.CreateWithTimestampsLT memory stream1;
stream1.sender = address(0xABCD); // The sender to stream the assets, he will be able to cancel the stream
stream1.recipient = address(0xBEEF); // The recipient of the streamed assets
stream1.totalAmount = uint128(perStreamAmount); // The total amount of each stream, inclusive of all fees
stream1.cancelable = false; // Whether the stream will be cancelable or not
stream0.transferable = false; // Whether the recipient can transfer the NFT or not
stream0.startTime = uint40(block.timestamp); // Set the start time to block timestamp
// Declare some dummy tranches
stream1.tranches = new LockupTranched.Tranche[](2);
stream1.tranches[0] = LockupTranched.Tranche({
amount: uint128(perStreamAmount / 4),
timestamp: uint40(block.timestamp + 4 weeks)
});
stream1.tranches[1] = LockupTranched.Tranche({
amount: uint128(perStreamAmount - stream1.tranches[0].amount),
timestamp: uint40(block.timestamp + 24 weeks)
});
stream1.broker = Broker(address(0), ud60x18(0)); // Optional parameter left undefined
Once both structs are declared, the batch array has to be filled:
// Fill the batch array
BatchLockup.CreateWithTimestampsLT[] memory batch = new BatchLockup.CreateWithTimestampsLT[](batchSize);
batch[0] = stream0;
batch[1] = stream1;
Invoke the batch create function
With all parameters set, we can now call the createWithTimestampsLT
function, and assign the ids of the newly created
streams to the array:
streamIds = BATCH.createWithTimestampsLT(LOCKUP_TRANCHED, DAI, batch);
The complete Batch Lockup Tranched stream creator contract
Below you can see the complete functioning code: a contract that batch creates Lockup Tranched streams using Sablier's
Batch
that start at block.timestamp
. You can access the code on GitHub through this
link.
loading...