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/staking

v7.1.0-alpha.2

Published

JavaScript SDK to interact with Streamflow Staking protocol.

Downloads

1,146

Readme

Streamflow Staking

JS SDK to interact with Streamflow Staking protocol.

This package allows you to

  • create staking pools and rewards pools;
  • claim rewards;
  • stake;
  • unstake;
  • fund rewards pools;

with the Streamflow Staking protocol.

This protocol is the complex of several programs that ensure flexibility and accountability for stakers and respective incentives for them.

aforementioned programs are:

  • Stake Pools Program
  • Reward Pools Program
  • Fee Management Program (for streamflow usage, non-required and omitted from further docs)

API Reference

API Documentation available here: docs site →

The Stake Pool Program entities:

  1. Stake Pool
  2. Stake Entry (PDA which stores info about current stakes, durations and rewards structure)

The Reward Pool Program entities:

  1. Reward Pool (must has a back-reference to a stake pool)
  2. Reward Entry (PDA stores claims information and time-bound params)

1 Stake Pool can have N Reward Pools.

[!NOTE] There is a limitation of 255 Reward Pools per a single token mint for a stake pool.

Installation

Install the sdk with npm

  npm install @streamflow/staking
  yarn install @streamflow/staking
  pnpm add @streamflow/staking

Usage/Examples

Create a client

const client = new SolanaStakingClient({
  clusterUrl: "https://api.mainnet-beta.solana.com",
  cluster: ICluster.Mainnet
});

[!WARNING] All operations expect ATAs to be created at the moment of execution and don't add these instructions.

  • Stake - staker's ATAs for stake mint and stake mint (see deriveStakeMintPDA fn)
  • Withdraw/Unstake - staker's ATAs for stake mint and stake mint (see deriveStakeMintPDA fn)
  • Claim rewards - staker's ATAs for reward mint
  • Fund Reward Pool - signer creates Streamflow Treasury's ATA for holding fee if defined

Read operations


await client.searchStakePools({ mint, creator }) // returns results of lookup, `mint` and `creator` both optional. Omit the argument to get all pools

await client.searchStakeEntries({ payer, stakePool }) // returns all stake entries. Omit the argument to get all.

await client.searchRewardPools({ stakePool, mint })

await client.searchRewardEntries({ stakeEntry, rewardPool })

Create a staking pool

const client = new SolanaStakingClient({
  clusterUrl: "https://api.mainnet-beta.solana.com",
  cluster: ICluster.Mainnet
});
/*
  Rewards Multiplier powered by 10^9.  
  Example: if multiplier is 2_000_000_000 than stakes for maxDuration will have 2x more rewards than stakes for minDuration
*/
const multiplier = new BN(1_000_000_000);
/*
  30 days - Unix time in seconds
*/
const maxDuration = new BN(2592000);
/*
 1 day - Unix time in seconds
*/
const maxDuration = new BN(86400);
/*
 Limits signers that can create/assign reward pools to this stake pool. True - anyone can
*/
const permissionless = false;
/*
  [0;256) derive stake pool PDA account address. 
  If stake pool with the same mint and creator/authority already exists, it is required to pick a vacant nonce 
*/
const nonce = 0;

const { metadataId: stakePoolPda } = await client.createStakePool({
    maxWeight: multiplier,
    maxDuration,
    minDuration,
    mint: MINT_ADDRESS,
    permissionless,
    nonce: 
})

Create a rewardPool pool

import { calculateRewardAmountFromRate } from "@streamflow/staking";

/*
  [0;256) derive reward pool PDA account address.  
  If reward pool with the same mint already exists, it is required to pick a vacant nonce 
*/
const nonce = 0;
/*
 Amount of rewarding tokens stakers get in return for staking exactly 1 token to the staking pool
*/
const rewardAmount = new BN(100);
/*
  Alternatively you may want to calculate the correct reward amount from desired reward rate taking into account stake pool and reward pools tokes decimals
*/
const rewardRate = 0.0025;
const stakeTokenDecimals = 9;
const rewardTokenDecimals = 6;
// For every effectively Staked 1 WHOLE token 0.0025 of Reward Token will be distributed
const rewardAmount = calculateRewardAmountFromRate(rewardRate, stakeTokenDecimals, rewardTokenDecimals);
/*
 1 day - Unix time in seconds. Period for rewarding stakers. Period starts counting from the moment of staking
*/
const rewardPeriod = new BN(86400);
const rewardMint = REWARD_MINT_ADDRESS; // rewarding token
/*
 Whether to allow anyone to fund this reward pool. If true anyone can fund, otherwise only the creator can
*/
const permissionless = true;

client.createRewardPool({
      nonce,
      rewardAmount,
      rewardPeriod,
      rewardMint,
      permissionless = false,
      stakePool: stakePoolPda,
      stakePoolMint: MINT_ADDRESS,
    })

Reward Amount configuration (in-depth)

rewardAmount represents a 10^9 fraction of a raw token distributed for every effective staked raw token - it's important to account for both reward and stake token decimals when creating staking pool because of that.

Example with only raw tokens: if rewardAmount is configured to be 1_000 and user staked 1_000_000_000 Raw Tokens with a weight of 2 (in the actual protocol this number will be represented as 2_000_000_000), it means that the effective number of raw tokens staked is 2_000_000_000 and on every reward distribution user will get 2_000_000_000 * 1_000 / 10^9 = 200 Raw Tokens;

Examples with decimals:

RT - Reward Token ST - Stake Pool Token P - fixed rewardAmount precision of 9

User wants to set reward amount of 0.003 for every effective staked whole token, depending on number of decimals RT and ST have configuration may look different:

  1. RT with 6 decimals, ST with 6 decimals.
    • 0.003 of RT is 3_000 raw tokens;
    • ST has 6 decimals while P is 9, therefore 9 - 6 = 3;
    • We need to add 3 decimals to the rewardAmount for proper distribution making it 3_000_000;
  2. RT with 12 decimals, ST with 12 decimals.
    • 0.003 of RT is 3_000_000_000 raw tokens;
    • ST has 12 decimals while P is 9, therefore 9 - 12 = -3;
    • We need to remove decimals from the raw token to be distributed making rewardAmount = 3_000_000;
  3. RT with 5 decimals, ST with 7 decimals.
    • 0.003 of RT is 300 raw tokens;
    • ST has 7 decimals while P is 9, therefore 9 - 7 = 2;
    • We need to add 2 decimals making rewardAmount = 30_000;
  4. RT with 9 decimals, ST with 3 decimals.
    • 0.003 of RT is 3_000_000 raw tokens;
    • the difference between RT and ST decimals is 9 - 3 = 6;
    • ST has 3 decimals while P is 9, therefore 9 - 3 = 6;
    • We need to add 6 decimals making rewardAmount = 3_000_000_000_000;

We recommend to use the calculateRewardAmountFromRate function exposed by the sdk for the correct reward amount configuration.

Also, some configurations where there is big difference between Stake Pool and Reward Pool token decimals may be unsupported, in this case the function will return 0, so be aware.

Deposit/Stake to a stake pool

/*
  [0;256) derive stake entry PDA account address.  
  If stake entry with the same nonce already exists, it is required to pick a vacant one
*/
const nonce = 0; 
const amount = new BN(1000); // tokens to stake
const duration = new BN(86400 * 2) // 2 days, must be in the range of stakePool's min and max durations
await client.stake({ nonce, amount, duration, stakePool, stakePoolMint });

Unstake/Withdraw to a stake pool

/*
  Usually to achieve this the app already loaded available stakeEntries.   
  Stake Entry holds used `nonce`, so `nonce` below could be taken from the stake entry
*/

/*
  [0;256) derived stake entry PDA account address.  
  If stake entry with the same nonce already exists, it is required to pick a vacant one
 */ 
const nonce = 0; // 
await client.unstake({ stakePool, stakePoolMint, nonce });

Claim a reward

Since each stake entry can produce multiple rewards (single claim per each reward pool linked to the staking pool) this operation can be triggered for every reward pool separately.

await client.claimRewards({
  rewardPoolNonce,
  depositNonce,
  stakePool,
  rewardMint,
});

[!Note] All operations have accompanying APIs for manual transaction building. Consult with API docs to find respective calls.
For instance, prepareClaimRewardsInstructions.
These APIs allow to aggregate multiple operations in a single transaction according to the app needs.

Appendix

Streamflow Staking protocol program IDs

| Solana | | | ------- | -------------------------------------------- | | Staking Pools Mainnet | STAKEvGqQTtzJZH6BWDcbpzXXn2BBerPAgQ3EGLN2GH | | Reward Pools Mainnet | RWRDdfRbi3339VgKxTAXg4cjyniF7cbhNbMxZWiSKmj | | ---- | --- | | Staking Pools Devnet | STAKEvGqQTtzJZH6BWDcbpzXXn2BBerPAgQ3EGLN2GH | | Reward Pools Devnet | RWRDdfRbi3339VgKxTAXg4cjyniF7cbhNbMxZWiSKmj |

IDLs

For further details you can consult with IDLs of protocols available at: @streamflow/staking/dist/esm/solana/descriptor