npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@streamflow/stream

v7.1.0-alpha.2

Published

JavaScript SDK to interact with Streamflow protocol.

Downloads

7,968

Readme

JS SDK to interact with Streamflow protocol.

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:

import { BN } from "bn.js";
import { GenericStreamClient, getBN, getNumberFromBN } from "@streamflow/stream";

Check the SDK for other types and utility functions.

Create StreamClient instance

Before creating and manipulating streams chain specific or generic StreamClient instance must be created. All streams functions are methods on this instance.

Solana

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

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

Aptos

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

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

Ethereum

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

const ethereumClient = new StreamflowEVM.EvmStreamClient(
  "YOUR_ETHEREUM_NODE_URL",
  IChain.Ethereum,
  signer // will be sender in a stream and authority for all stream related transactions
);

Polygon

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

const polygonClient = new StreamflowEVM.EvmStreamClient(
  "YOUR_POLYGON_NODE_URL",
  IChain.Polygon,
  signer // will be sender in a stream and authority for all stream related transactions
);

BNB

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

const bnbClient = new StreamflowEVM.EvmStreamClient(
  "https://bsc-dataseed1.binance.org/",
  IChain.BNB,
  signer // will be sender in a stream and authority for all stream related transactions
);

Sui

import { StreamflowSui } from "@streamflow/stream";

const suiClient = new StreamflowSui.SuiStreamClient(
  "https://fullnode.testnet.sui.io:443"
);

Generic Stream Client

GenericStreamClient provides isomorphic interface to work with streams agnostic of chain.

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

const client =
  new GenericStreamClient<Types.IChain.Solana>({
    chain: IChain.Solana, // Blockchain
    clusterUrl: "https://api.mainnet-beta.solana.com", // RPC cluster URL
    cluster: ICluster.Mainnet, // (optional) (default: Mainnet)
    // ...rest chain specific params e.g. commitment for Solana
  });

All the examples below will contain generic method options descriptions and chain specific params.

NOTE: All timestamp parameters are in seconds.

Create stream

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, // Whether additional tokens can be deposited after creation, setting to FALSE will effectively create a vesting contract.
  canUpdateRate: false, // settings to TRUE allows sender to update amountPerPeriod
  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: undefined, //  (optional) Partner's wallet address (string | undefined).
};

const solanaParams = {
    sender: wallet, // SignerWalletAdapter or Keypair of Sender account
    isNative: false // [optional] [WILL CREATE A wSOL STREAM] Whether Stream or Vesting should be paid with Solana native token or not
};

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

const suiParams = {
    senderWallet: wallet, // WalletContextState | Keypair
};

const ethereumParams = undefined;

try {
  const { ixs, tx, metadata } = await client.create(createStreamParams, solanaParams); // second argument differ depending on a chain
} catch (exception) {
  // handle exception
}

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 createMultiStreamsParams: 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: undefined, //  (optional) Partner's wallet address (string | undefined).
};

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 suiParams = {
    senderWallet: wallet, // WalletContextState | Keypair
};

const ethereumParams = undefined;

try {
  const { txs } = await client.createMultiple(createMultiStreamsParams, solanaParams);
} catch (exception) {
  // handle exception
}

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

Identifying created contracts (streams or vesting)

All Stream Clients return ICreateResult object (createMultiple returns an Array) that has the following structure

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

metadataId is the id of the created stream.

Withdraw from stream

const withdrawStreamParams: Types.IWithdrawData = {
  id: "AAAAyotqTZZMAAAAmsD1JAgksT8NVAAAASfrGB5RAAAA", // Identifier (address) 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 suiParams = {
    senderWallet: wallet, // WalletContextState | Keypair
    tokenId: "0x2::sui::SUI"
};

const ethereumParams = undefined;

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

Topup stream

const topupStreamParams: ITopUpData = {
  id: "AAAAyotqTZZMAAAAmsD1JAgksT8NVAAAASfrGB5RAAAA", // Identifier (address) 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: true // [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 suiParams = {
    senderWallet: wallet, // WalletContextState | Keypair
    tokenId: "0x2::sui::SUI"
};

const ethereumParams = undefined;

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

Transfer stream to another recipient

const data: ITransferData = {
  id: "AAAAyotqTZZMAAAAmsD1JAgksT8NVAAAASfrGB5RAAAA", // Identifier (address) of the stream to be transferred
  newRecipient: "99h00075bKjVg000000tLdk4w42NyG3Mv0000dc0M99", // Identifier (address) 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 suiParams = {
    senderWallet: wallet, // WalletContextState | Keypair
    tokenId: "0x2::sui::SUI"
};

const ethereumParams = undefined;

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

Cancel stream

const cancelStreamParams: 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 suiParams = {
    senderWallet: wallet, // WalletContextState | Keypair
    tokenId: "0x2::sui::SUI"
};

const ethereumParams = undefined;

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

Update a stream

const updateStreamParams: IUpdateData = {
  id: "AAAAyotqTZZMAAAAmsD1JAgksT8NVAAAASfrGB5RAAAA", // Identifier of a stream to update.
  enableAutomaticWithdrawal: true,  // [optional], allows to enable AW if it wasn't, disable is not possible
  withdrawFrequency: 60,  // [optional], allows to update withdrawal frequency, may result in additional AW fees
  amountPerPeriod: getBN(10, 9),  // [optional], allows to update release amount effective on next unlock
}

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

const aptosParams = {
  senderWallet: wallet, // AptosWalletAdapter Wallet of wallet signing the transaction
};

const suiParams = {
  senderWallet: wallet, // WalletContextState | Keypair
};

const ethereumParams = undefined;

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

Get one stream by its ID

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

try {
  const stream = await client.getOne(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);

Get multiple streams for a specific wallet address

const data: IGetAllData = {
  address: "99h00075bKjVg000000tLdk4w42NyG3Mv0000dc0M99",
  type: StreamType.All, // StreamType.Vesting, StreamType.Lock, StreamType.Payment
  direction: StreamDirection.All, // StreamDirection.Outgoing, StreamDirection.Incoming
};

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

Search Solana Streams

Solana RPC is pretty rich in what data it can allow to filter by, so we expose a separate searchStreams method on SolanaStreamClient:

// All parameters are optional, so in theory you can just fetch all Streams
const params = {
  mint: "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263",
  sender: "AKp8CxGbhsrsEsCFUtx7e3MWyW7SWi1uuSqv6N4BEohJ",
  recipient: "9mqcpDjCHCPmttJp2t477oJ71NdAvJeSus8BcCrrvwy5",
}
// nativeStreamClient is exposed on a GenericStreamClient, you can also use SolanaStreamClient directly
// Return an Array of objects {publicKey: PublicKey, account: Stream}
const streams = await client.nativeStreamClient.searchStreams(params);

Handling errors

GenericStreamClient wraps all errors when making on-chain calls with ContractError error class:

  • this class inherits original traceback
  • error may optionally contain contractErrorCode property that can be further mapped to a specific Contract error
  • for createMultiple method errors are wrapped individually for every recipient address
  • please check documentation for common enums ContractErrorCode and SolanaContractErrorCode to see short description for each error

A public map of protocol errors is available here.

Additional notes

Streamflow protocol program IDs

| Solana | | | ------- | -------------------------------------------- | | Devet | HqDGZjaVRXJ9MGRQEw7qDc2rAr6iH1n1kAQdCZaCMfMZ | | Mainnet | strmRqUCoQUgGUan5YhzUZa6KqdzwX5L6FpUxfmKg5m |

| EVM | Ethereum(Goerli on Tesnet),Polygon,BNB | | ------- | ------------------------------------------ | | Testnet | 0x5Db7a43D20De64E3a3BC765334a477026FD13E7d | | Mainnet | 0x94d4646Bd307Bf91CB1893BC64d976BF9E60D9B2 |

| Aptos | | | ------- | ------------------------------------------------------------------ | | Testnet | 0xc6737de143d91b2f99a7e490d4f8348fdfa3bdd1eb8737a27d0455f8a3625688 | | Mainnet | 0x9009d93d52576bf9ac6dc6cf10b870610bcb316342fef6eff80662fbbfce51b0 |

| Sui | | | ------- | ------------------------------------------------------------------ | | Testnet | 0xf1916c119a6c917d4b36f96ffc0443930745789f3126a716e05a62223c48993a | | Mainnet | 0xa283fd6b45f1103176e7ae27e870c89df7c8783b15345e2b13faa81ec25c4fa6 |

All BN amounts are denominated in their smallest units.

E.g, if the amount is 1 SOL than this amount in lamports is 1000 \* 10^9 = 1_000_000_000.

And new BN(1_000_000_000) is used.

Use getBN and getNumberFromBN utility functions for conversions between BN and Number types.

getBN(1, 9) is equal to new BN(1_000_000_000)

getNumberFromBN(new BN(1_000_000_000), 9) will return 1