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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ultratestbro/wdk-protocol-staking-spl-stake-pool-solana

v0.1.0

Published

A simple package that lets @tetherto/wdk-wallet-solana wallet accounts stake through SPL stake pools (Jito by default): stake SOL → JitoSOL, exit instantly from the reserve or through a stake account, claim, read rates, APY and earnings.

Readme

@ultratestbro/wdk-protocol-staking-spl-stake-pool-solana

A simple package that lets @tetherto/wdk-wallet-solana wallet accounts stake through pools on the SPL Stake Pool program — Jito by default: stake SOL → JitoSOL, exit instantly from the reserve or through a stake account, claim, read rates, APY and earnings.

Built as the fourth implementation of the proposed StakingProtocol type for @tetherto/wdk-wallet — after Lido (ETH liquid staking), SSV (token staking with a cooldown) and Tonstakers (GRAM liquid staking) — and the second one off EVM. The base class in src/staking-protocol.js is the same file, byte-identical: the type is chain-agnostic, and Solana's two-shape exit (instant vs. stake account + epoch boundary) fits its request → queue → claim contract.

The mechanics are extracted from a production wallet (React Native/Hermes). Verification status (2026-09-07, mainnet): stake and instant exit ran with real funds from the wallet (four transactions, amounts matched the module's quotes to the lamport); the delayed exit (stake account + deactivate) is verified by simulateTransaction as a large holder, and the claim only by its instruction layout — a funded delayed → claim cycle needs a position of ≥ 1 SOL worth and is still to be run. scripts/verify-live.mjs re-checks every shape the account can afford, keys never involved.

What an SPL stake pool and JitoSOL are

An SPL stake pool holds stake accounts on many validators plus a reserve. The pool token (JitoSOL for Jito; bSOL and most validator LSTs use the same program) is the non-rebasing receipt whose SOL value is total_lamports / pool_token_supply, moved once per epoch (~2 days) when the pool's crank applies the epoch's rewards. Jito adds MEV tips on top of inflation rewards.

  • Stake is one DepositSol instruction: SOL goes to the reserve, tokens are minted at the rate (Jito: no deposit fee).
  • Instant exitWithdrawSol: burn tokens, SOL is paid from the reserve at once, minus the pool's SOL withdrawal fee (Jito: 0.1 %). Only while the reserve holds enough (typically ~1 000 SOL).
  • Delayed exitWithdrawStake: burn tokens, the pool splits a validator stake account to a fresh stake account owned by the wallet (Jito: 0.1 % fee); this module deactivates it in the same transaction. After the epoch boundary the account is inactive and claim sweeps the SOL (and the account's rent) back to the wallet. The stake program's minimum delegation (1 SOL + rent) is the floor for this path.

The wallet's stake accounts are derived with seeds (createWithSeed(wallet, "<pool>-unstake:<i>", StakeProgram), 8 slots), so the queue is recoverable from the wallet alone and no ephemeral keypair ever signs.

Usage

import WalletManagerSolana from '@tetherto/wdk-wallet-solana'
import SplStakePoolProtocolSolana from '@ultratestbro/wdk-protocol-staking-spl-stake-pool-solana'

const wallet = new WalletManagerSolana(seed, { provider: 'https://api.mainnet-beta.solana.com' })
const account = await wallet.getAccount(0)

const jito = new SplStakePoolProtocolSolana(account) // pool: 'jito' by default; reads ride the account's RPC

// Stake 1 SOL — JitoSOL lands at the pool rate (DepositSolWithSlippage, 0.5 % floor)
const { hash, fee } = await jito.stake({ amount: 10n ** 9n })
await jito.awaitConfirmation(hash)

// Exit: delayed (default — stake account, claim after the epoch boundary) or instant (reserve)
await jito.requestWithdrawal({ amount: 10n ** 9n })                    // ≥ 1 SOL worth
await jito.requestWithdrawal({ amount: 5n * 10n ** 7n, mode: 'instant' })

// The queue, then the claim
const { requests, claimableIds } = await jito.getWithdrawalRequests()
if (claimableIds.length) await jito.claimWithdrawals({ ids: claimableIds })

// Views
await jito.getStakedBalance()   // { balance: JitoSOL, rate: lamports per JitoSOL (1e9), total: lamports }
await jito.getPoolData()        // rate, previousRate, updated, instantLiquidity, fees, minimumStakeLamports…
await jito.getApr()             // percent — on-chain estimate, or your provider's figure via the `apr` hook
await jito.getRewards()         // { earned, entryRate, deposited, minted, firstStakeAt } from the account's own deposits

Configuration

new SplStakePoolProtocolSolana(account, {
  pool: 'jito',                        // or { name, pool, mint, symbol } for any pool on the program
  provider: [url1, url2],              // JSON-RPC URL(s), a @solana/rpc client, or { request(method, params) }
  commitment: 'confirmed',
  slippageBps: 50,                     // floor on quoted amounts (..WithSlippage instructions)
  computeUnitLimit: 300_000,
  computeUnitPrice: 50_000n,           // micro-lamports per unit — ≈ 0.000015 SOL priority fee
  unstakeSlots: 8,                     // delayed exits tracked per wallet
  apr: async () => fetchJitoApy()      // provider APY hook (Jito's stats include MEV); default: epoch-over-epoch estimate
})

A read-only account ({ getAddress }) is enough for every view; writes need an account with sendTransaction. The module hands the account a bare { version: 0, instructions } message — @tetherto/wdk-wallet-solana sets the blockhash lifetime and the fee-payer signer, signs and broadcasts; the key never enters the module.

Fail-closed rules

Checked before any transaction is built:

  • the configured mint must equal the on-chain pool's mint; the pool account must be owned by the SPL Stake Pool program;
  • the pool must be updated for the current epoch (last_update_epoch == epoch) — the program rejects every deposit and withdrawal otherwise;
  • a delayed exit must yield at least rent + minimum delegation and leave the split-from validator account the same minimum (checked against the live balance, not only the last-update list), else the stake program's Split fails;
  • an instant exit must fit the reserve minus its rent;
  • every amount goes out with a ..WithSlippage floor (default 0.5 %);
  • a pool that restricts SOL deposits or withdrawals to an authority is refused for that path rather than sent to fail.

Why the instructions are hand-encoded

@tetherto/wdk-wallet-solana is built on @solana/* 3.x. The published stake-pool client wants web3.js v1 and @solana-program/stake wants kit ≥ 5; either would put a second Solana stack into the consumer's bundle. The six instructions this module needs have stable, documented layouts (Stake Pool DepositSol 14 / WithdrawStake 10 / WithdrawSol 16 and their ..WithSlippage variants 25 / 24 / 26, System CreateAccountWithSeed 3, Stake Deactivate 5 / Withdraw 4), verified against the program sources and by simulation — src/spl-stake-pool-codec.js encodes them with @solana/addresses and @solana/instructions only.

Tests

npm test               # unit tests over mainnet fixtures (pool state, validator list, stake account)
npm run verify:live    # reads + simulateTransaction of every shape on mainnet, no keys

License

Apache-2.0