Interact with the protocol to create streams and vesting contracts
This package allows you to create, createMultiple, withdraw, cancel, topup, transfer, update a token stream. You can also getOne stream and get multiple streams.
import { BN } from "bn.js";
import { Types, GenericStreamClient, getBN, getNumberFromBN } from "@streamflow/stream";
Check the SDK for other types and utility functions.
Create StreamClient instance
Before creating and manipulating streams, a chain-specific or generic StreamClient instance must be created. All stream functions are methods in this instance.
import { StreamflowEVM, Types,} from"@streamflow/stream";constethereumClient=newStreamflowEVM.EvmStreamClient("YOUR_ETHEREUM_NODE_URL",Types.IChain.Ethereum, signer // will be sender in a stream and authority for all stream related transactions);
Polygon
import { StreamflowEVM, Types,} from"@streamflow/stream";constpolygonClient=newStreamflowEVM.EvmStreamClient("YOUR_POLYGON_NODE_URL",Types.IChain.Polygon, signer // will be sender in a stream and authority for all stream related transactions);
BNB Smart Chain
import { StreamflowEVM, Types,} from"@streamflow/stream";constbnbClient=newStreamflowEVM.EvmStreamClient("https://bsc-dataseed1.binance.org/",Types.IChain.BNB, signer // will be sender in a stream and authority for all stream related transactions);
Generic Stream Client
GenericStreamClient provides an isomorphic interface to work with streams agnostic of the chain.
import { GenericStreamClient, Types } from"@streamflow/stream";constclient=newGenericStreamClient<Types.IChain.Solana>({ chain:Types.IChain.Solana,// Blockchain clusterUrl:"https://api.mainnet-beta.solana.com",// RPC cluster URL cluster:Types.ICluster.Mainnet,// (optional) (default: Mainnet)// ...rest chain specific params e.g. commitment for Solana });
Create stream
Creating a stream requires a wallet with tokens for gas fees.
constcreateStreamParams:Types.ICreateStreamData= { recipient:"4ih00075bKjVg000000tLdk4w42NyG3Mv0000dc0M00",// Recipient address. tokenId:"DNw99999M7e24g99999999WJirKeZ5fQc6KY999999gK",// Token mint address. start:1643363040,// Timestamp (in seconds) when the stream/token vesting starts. amount:getBN(100,9),// depositing 100 tokens with 9 decimals mint. period:1,// Time step (period) in seconds per which the unlocking occurs. cliff:1643363160,// Vesting contract "cliff" timestamp in seconds. cliffAmount:newBN(10),// Amount unlocked at the "cliff" timestamp. amountPerPeriod:getBN(5,9),// Release rate: how many tokens are unlocked per each period. name:"Transfer to Jane Doe.",// The stream name or subject. canTopup:false,// setting to FALSE will effectively create a vesting contract. cancelableBySender:true,// Whether or not sender can cancel the stream. cancelableByRecipient:false,// Whether or not recipient can cancel the stream. transferableBySender:true,// Whether or not sender can transfer the stream. transferableByRecipient:false,// Whether or not recipient can transfer the stream. automaticWithdrawal: true, // Whether or not a 3rd party (e.g. cron job, "cranker") can initiate a token withdraw/transfer.
withdrawalFrequency: 10, // Relevant when automatic withdrawal is enabled. If greater than 0 our withdrawor will take care of withdrawals. If equal to 0 our withdrawor will skip, but everyone else can initiate withdrawals.
partner:null,// (optional) Partner's wallet address (string | null).};constsolanaParams= { sender: wallet,// SignerWalletAdapter or Keypair of Sender account isNative: // [optional] [WILL CREATE A wSOL STREAM] Wether Stream or Vesting should be paid with Solana native token or not
};constaptosParams= { senderWallet: wallet,// AptosWalletAdapter Wallet of sender};constethereumParams=undefined;try { const { ixs, tx, metadata } = await client.create(createStreamParams, solanaParams); // second argument differ depending on a chain
} catch (exception) {// handle exception}
Protocol
a program that lives on chain, an implementation of Scheduled Token Transfer
Stream
an entity that is created by the Protocol, contains information about Token Transfer
Contract
a synonym for a Stream. In the code there is no consistency how we name it, in the Protocol we often use Contract referring to a Stream.
Sender
an account that creates a Scheduled Token Transfer
Recipient
an account that is the receiver of Tokens
Referral
an account that will be used to calculate streamflow and referral fees when creating a Stream
Partner
a synonym for a Referral
Treasury
a Streamflow account that receives fees as a reward
Withdrawor
a Streamflow account that processes automated Token Transfers to the Recipient
Protocol
a program that lives on chain, an implementation of Scheduled Token Transfer
Stream
an entity that is created by the Protocol, contains information about Token Transfer
Create multiple streams at once
constrecipients= [ { recipient:"4ih00075bKjVg000000tLdk4w42NyG3Mv0000dc0M00",// Solana recipient address. amount:getBN(100,9),// depositing 100 tokens with 9 decimals mint. name:"January Payroll",// The stream name/subject. cliffAmount:getBN(10,9),// amount released on cliff for this recipient amountPerPeriod:getBN(1,9),//amount released every specified period epoch },];constcreateStreamParams:Types.ICreateMultipleStreamData= { recipients: recipients,// Solana recipient address. tokenId:"DNw99999M7e24g99999999WJirKeZ5fQc6KY999999gK",// SPL Token mint. start:1643363040,// Timestamp (in seconds) when the stream/token vesting starts. period:1,// Time step (period) in seconds per which the unlocking occurs. cliff:1643363160,// Vesting contract "cliff" timestamp in seconds. canTopup:false,// setting to FALSE will effectively create a vesting contract. cancelableBySender:true,// Whether or not sender can cancel the stream. cancelableByRecipient:false,// Whether or not recipient can cancel the stream. transferableBySender:true,// Whether or not sender can transfer the stream. transferableByRecipient:false,// Whether or not recipient can transfer the stream. automaticWithdrawal: true, // Whether or not a 3rd party (e.g. cron job, "cranker") can initiate a token withdraw/transfer.
withdrawalFrequency: 10, // Relevant when automatic withdrawal is enabled. If greater than 0 our withdrawor will take care of withdrawals. If equal to 0 our withdrawor will skip, but everyone else can initiate withdrawals.
partner:null,// (optional) Partner's wallet address (string | null).};constsolanaParams= { sender: wallet,// SignerWalletAdapter or Keypair of Sender account isNative: // [optional] [WILL CREATE A wSOL STREAM] Wether Stream or Vesting should be paid with Solana native token or not
};constaptosParams= { senderWallet: wallet,// AptosWalletAdapter Wallet of sender};constethereumParams=undefined;try {const { txs } =awaitclient.createMultiple(createMultiStreamsParams, solanaParams);} catch (exception) {// handle exception}
Identifying created contracts (streams or vesting)
All Stream Clients return Types.ICreateResult object (createdMultiple returns an Array) that has the following structure
constwithdrawStreamParams:Types.IWithdrawData= { id:"AAAAyotqTZZMAAAAmsD1JAgksT8NVAAAASfrGB5RAAAA",// Identifier of a stream to be withdrawn from. amount:getBN(100,9),// Requested amount to withdraw. If stream is completed, the whole amount will be withdrawn.};constsolanaParams= { invoker: wallet,// SignerWalletAdapter or Keypair signing the transaction};constaptosParams= { senderWallet: wallet,// AptosWalletAdapter Wallet of wallet signing the transaction tokenId:"0x1::aptos_coin::AptosCoin",// Aptos Coin type};constethereumParams=undefined;try {const { ixs,tx } =awaitclient.withdraw(withdrawStreamParams, solanaParams);} catch (exception) {// handle exception}
Topping up a stream allows you to add funds to an existing contract and extend the duration of the stream/vesting.
consttopupStreamParams:Types.ITopUpData= { id:"AAAAyotqTZZMAAAAmsD1JAgksT8NVAAAASfrGB5RAAAA",// Identifier of a stream to be topped up. amount:getBN(100,9),// Specified amount to topup (increases deposited amount).};constsolanaParams= { invoker: wallet,// SignerWalletAdapter or Keypair signing the transaction isNative:// [ONLY FOR wSOL STREAMS] [optional] Wether topup is with Native Solanas};constaptosParams= { senderWallet: wallet,// AptosWalletAdapter Wallet of wallet signing the transaction tokenId:"0x1::aptos_coin::AptosCoin",// Aptos Coin type};constethereumParams=undefined;try {const { ixs,tx } =awaitclient.topup(topupStreamParams, solanaParams);} catch (exception) {// handle exception}
Transfer stream to another recipient
constdata:Types.ITransferData= { id:"AAAAyotqTZZMAAAAmsD1JAgksT8NVAAAASfrGB5RAAAA", newRecipient:"99h00075bKjVg000000tLdk4w42NyG3Mv0000dc0M99",// Identifier of a stream to be transferred.};constsolanaParams= { invoker: wallet,// SignerWalletAdapter or Keypair signing the transaction};constaptosParams= { senderWallet: wallet,// AptosWalletAdapter Wallet of wallet signing the transaction tokenId:"0x1::aptos_coin::AptosCoin",// Aptos Coin type};constethereumParams=undefined;try {const { tx } =awaitclient.transfer(data, solanaParams);} catch (exception) {// handle exception}
constcancelStreamParams:Types.ICancelData= { id:"AAAAyotqTZZMAAAAmsD1JAgksT8NVAAAASfrGB5RAAAA",// Identifier of a stream to be canceled.};constsolanaParams= { invoker: wallet,// SignerWalletAdapter or Keypair signing the transaction};constaptosParams= { senderWallet: wallet,// AptosWalletAdapter Wallet of wallet signing the transaction tokenId:"0x1::aptos_coin::AptosCoin",// Aptos Coin type};constethereumParams=undefined;try {const { ixs,tx } =awaitStreamClient.cancel(cancelStreamParams, solanaParams);} catch (exception) {// handle exception}
Get one stream by its ID
constdata:Types.IGetOneData= { id:"AAAAyotqTZZMAAAAmsD1JAgksT8NVAAAASfrGB5RAAAA",// Identifier of a stream};try {conststream=awaitclient.getOne(data);} catch (exception) {// handle exception}
Get multiple streams for a specific wallet address
conststream=awaitclient.getOne({ id:"AAAAyotqTZZMAAAAmsD1JAgksT8NVAAAASfrGB5RAAAA",});constunlocked=stream.unlocked(tsInSeconds); // bn amount unlocked at the tsInSecondsconsole.log(getNumberFromBN(unlocked,9));
Note: unlocked amount is determined based on configuration set on creation, no dynamic data is involved.