Skip to main content
Javascript SDK

Interact with the protocol to create streams and vesting contracts

Updated over 3 months ago

This package allows you to create, createMultiple, withdraw, cancel, topup, transfer, update a token stream. You can also getOne stream and get multiple streams.

Installation

npm i -s @streamflow/stream

or

yarn add @streamflow/stream


Documentation

API Documentation available here: docs site โ†’

Import SDK

Most common imports:

Copy

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.

Solana

import {
StreamflowSolana,
Types,
} from "@streamflow/stream";

const solanaClient = new StreamflowSolana.SolanaStreamClient(
"https://api.mainnet-beta.solana.com"
);

Aptos

import {
StreamflowAptos,
Types,
} from "@streamflow/stream";

const aptosClient = new StreamflowAptos.AptosStreamClient(
"https://fullnode.mainnet.aptoslabs.com/v1"
);

Ethereum

import {
StreamflowEVM,
Types,
} from "@streamflow/stream";

const ethereumClient = new StreamflowEVM.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";

const polygonClient = new StreamflowEVM.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";

const bnbClient = new StreamflowEVM.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.

Copy

import { GenericStreamClient, Types } from "@streamflow/stream";

const client =
new GenericStreamClient<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.

Copy

const createStreamParams: 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: new BN(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).
};

const solanaParams = {
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
};

const aptosParams = {
senderWallet: wallet, // AptosWalletAdapter Wallet of sender
};

const ethereumParams = 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

const recipients = [
{
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
},
];
const createStreamParams: 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).
};

const solanaParams = {
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
};

const aptosParams = {
senderWallet: wallet, // AptosWalletAdapter Wallet of sender
};

const ethereumParams = undefined;

try {
const { txs } = await client.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

Copy

interface ICreateResult {
ixs: (TransactionInstruction | Types.TransactionPayload)[];
txId: string;
metadataId: MetadataId;
}

metadataId is the id of the created stream.


Interacting with existing streams

Withdraw from stream

const withdrawStreamParams: 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.
};

const solanaParams = {
invoker: wallet, // SignerWalletAdapter or Keypair signing the transaction
};

const aptosParams = {
senderWallet: wallet, // AptosWalletAdapter Wallet of wallet signing the transaction
tokenId: "0x1::aptos_coin::AptosCoin", // Aptos Coin type
};

const ethereumParams = undefined;

try {
const { ixs, tx } = await client.withdraw(withdrawStreamParams, solanaParams);
} catch (exception) {
// handle exception
}

Topup stream

Topping up a stream allows you to add funds to an existing contract and extend the duration of the stream/vesting.

const topupStreamParams: Types.ITopUpData = {
id: "AAAAyotqTZZMAAAAmsD1JAgksT8NVAAAASfrGB5RAAAA", // Identifier of a stream to be topped up.
amount: getBN(100, 9), // Specified amount to topup (increases deposited amount).
};

const solanaParams = {
invoker: wallet, // SignerWalletAdapter or Keypair signing the transaction
isNative: // [ONLY FOR wSOL STREAMS] [optional] Wether topup is with Native Solanas
};

const aptosParams = {
senderWallet: wallet, // AptosWalletAdapter Wallet of wallet signing the transaction
tokenId: "0x1::aptos_coin::AptosCoin", // Aptos Coin type
};

const ethereumParams = undefined;

try {
const { ixs, tx } = await client.topup(topupStreamParams, solanaParams);
} catch (exception) {
// handle exception
}

Transfer stream

Transfer stream to another recipient

const data: Types.ITransferData = {
id: "AAAAyotqTZZMAAAAmsD1JAgksT8NVAAAASfrGB5RAAAA",
newRecipient: "99h00075bKjVg000000tLdk4w42NyG3Mv0000dc0M99", // Identifier of a stream to be transferred.
};

const solanaParams = {
invoker: wallet, // SignerWalletAdapter or Keypair signing the transaction
};

const aptosParams = {
senderWallet: wallet, // AptosWalletAdapter Wallet of wallet signing the transaction
tokenId: "0x1::aptos_coin::AptosCoin", // Aptos Coin type
};

const ethereumParams = undefined;

try {
const { tx } = await client.transfer(data, solanaParams);
} catch (exception) {
// handle exception
}

Cancel stream

const cancelStreamParams: Types.ICancelData = {
id: "AAAAyotqTZZMAAAAmsD1JAgksT8NVAAAASfrGB5RAAAA", // Identifier of a stream to be canceled.
};

const solanaParams = {
invoker: wallet, // SignerWalletAdapter or Keypair signing the transaction
};

const aptosParams = {
senderWallet: wallet, // AptosWalletAdapter Wallet of wallet signing the transaction
tokenId: "0x1::aptos_coin::AptosCoin", // Aptos Coin type
};

const ethereumParams = undefined;

try {
const { ixs, tx } = await StreamClient.cancel(cancelStreamParams, solanaParams);
} catch (exception) {
// handle exception
}

Get one stream by its ID

const data: Types.IGetOneData = {
id: "AAAAyotqTZZMAAAAmsD1JAgksT8NVAAAASfrGB5RAAAA", // Identifier of a stream
};

try {
const stream = await client.getOne(data);
} catch (exception) {
// handle exception
}

Get multiple streams for a specific wallet address

const data: Types.IGetAllData = {
address: "99h00075bKjVg000000tLdk4w42NyG3Mv0000dc0M99",
type: Types.StreamType.All,
direction: Types.StreamDirection.All,
};

try {
const streams = client.get(data);
} catch (exception) {
// handle exception
}

Fetching unlocked amount

const stream = await client.getOne({
id: "AAAAyotqTZZMAAAAmsD1JAgksT8NVAAAASfrGB5RAAAA",
});

const unlocked = stream.unlocked(tsInSeconds); // bn amount unlocked at the tsInSeconds
console.log(getNumberFromBN(unlocked, 9));
  • Note: unlocked amount is determined based on configuration set on creation, no dynamic data is involved.


Reading withdrawn amount and remaining funds

const stream = await client.getOne({
id: "AAAAyotqTZZMAAAAmsD1JAgksT8NVAAAASfrGB5RAAAA",
});
const withdrawn = stream.withdrawnAmount; // bn amount withdrawn already
console.log(getNumberFromBN(wihtdrawn, 9));
const remaining = stream.remaining(9); // amount of remaining funds
console.log(remaining);

Please note that transaction fees for the scheduled transfers are paid upfront by the stream creator (sender).

To see some examples of what you can build with Streamflow, check out: https://streamflow.finance/integrations.

See also:


Something we didn't cover?

We've tried to cover as much as possible in this guide, but there is always room for improvement. If we missed something, or you'd like to simply share your ideas, love, and support, email us at [email protected]

Someone will be in touch with you in no time. โœŒ๏ธ

Did this answer your question?