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

@anywalletkit/protocol-staking-native-solana

v0.1.4

Published

Native Solana staking for @anywalletkit/wallet-solana accounts: delegate SOL straight to the validators your app lists, through the Stake program. Seed-derived stake accounts (only the wallet signs, the position rebuilds from the wallet), exact activation

Readme

@anywalletkit/protocol-staking-native-solana

Native SOL staking for @anywalletkit/wallet-solana accounts: SOL delegated straight to the validators your app lists, through Solana's Stake program. No pool, no token, no third-party program. Each position is a stake account owned by the wallet.

npm install @anywalletkit/protocol-staking-native-solana @anywalletkit/wallet-solana

Usage

import { Wallet } from '@anywalletkit/kit'
import { WalletManagerSolana } from '@anywalletkit/wallet-solana'
import { NativeStakingProtocolSolana } from '@anywalletkit/protocol-staking-native-solana'

const wallet = new Wallet(seedPhrase)
wallet.registerWallet('solana', WalletManagerSolana, { provider: SOLANA_RPC })
wallet.registerProtocol('sol-staking', NativeStakingProtocolSolana, {
  chain: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
  config: {
    validators: [{ voteAccount: VOTE_A, name: 'Our validator' }, VOTE_B], // required
    maxCommission: 10,
  },
})
const staking = await wallet.getProtocol<NativeStakingProtocolSolana>('sol-staking')

const validators = await staking.listValidators()          // commission, delinquent, apr, eligible, refusals
await staking.quoteStake({ amount: 2_000_000_000n })       // fee, stake account, rent, readyEpoch; nothing signed
await staking.stake({ amount: 2_000_000_000n, validator: VOTE_A })

await staking.getStakeAccounts()                           // per account: status, amounts, validator, readyAt
await staking.getStakedBalance()                           // { balance, total, active, activating, deactivating, claimable }
await staking.requestWithdrawal({ amount: 1_000_000_000n }) // deactivate (split first when partial)
const q = await staking.getWithdrawalRequests()
if (q.claimableIds.length) await staking.claimWithdrawals({ ids: q.claimableIds })

Amounts are lamports (bigint). Without provider in the config, reads go to the account's own RPC.

Config

| Option | Default | | |---|---|---| | validators | — (required) | Vote accounts (strings or { voteAccount, name }), or 'any' to let users pick from the whole cluster. No list, no module. | | defaultValidator | first eligible of the list | Used when stake / delegate name none. Must be in the list. No default in 'any' mode. | | maxCommission | 10 | Percent. A validator above it is refused at delegation time (commission can change after you list it). | | allowDelinquent | false | Delinquent validators earn their stake nothing. | | provider | the account's RPC | URL, list of URLs (failover), @solana/rpc client or { request(method, params) }. | | discover | false | Also list stake accounts other wallets created for the address (getProgramAccounts; the RPC must serve it). Only those the wallet is the withdraw authority of (owned) count in the position and can be unstaked, delegated or merged. | | seedPrefix / maxAccounts | stake: / 32 | Stake accounts live at create_with_seed(wallet, "<prefix><i>", Stake), i < maxAccounts. | | feeReserve | 0.005 SOL | Kept on the wallet by stake, so the user can still pay to unstake and claim. | | computeUnitLimit / computeUnitPrice | wallet decides | Explicit compute budget; otherwise the wallet sets it from simulation and recent fees. | | enrich | — | (voteAccounts) => ({ [vote]: { apr, name, … } }): an explorer's APR (with MEV), names, scores. Decoration only. | | commitment / timeoutMs / fetch | confirmed / 15 s / global | Reads. |

How it works

  • Stake is one transaction: System CreateAccountWithSeed (amount + rent, base = the wallet), Stake Initialize (staker = withdrawer = the wallet, no lockup), DelegateStake. Only the wallet signs. It becomes active at the next epoch boundary (~2 days). The minimum is the Stake program's minimum delegation (1 SOL) plus about 0.0017 SOL of rent, which returns on withdrawal.
  • Statuses come from the StakeHistory sysvar with the program's own integer warm-up / cool-down math (9 % of the cluster per epoch), so inactive means the program will let every lamport out. Each account reports effective, activating, deactivating, withdrawable, and while it changes, readyEpoch / readyAt.
  • Unstake deactivates whole accounts and splits at most one: an exact match first, else the plan with the fewest steps where the split part and what stays behind both keep the minimum delegation. The split part goes to a new seed account (prefunded with rent) and is deactivated. A stake deactivated in the epoch it was made is free at once.
  • Claim withdraws fully inactive accounts to the wallet (the accounts close), up to 10 per transaction: with more ids or more ready accounts, remaining says how many are left for the next call.
  • Delegate re-delegates an inactive account, or, in the epoch an account was deactivated, puts it back on its validator (undoes the unstake; the validator must still pass the policy). An account still activating moves only to a validator named in the call. Merge joins two inactive accounts, two fully active ones on the same validator, or two activated this epoch on the same validator.
  • APR: getApr() / ValidatorInfo.apr is validator inflation × supply ÷ staked SOL × (1 − commission). It leaves out MEV and block-reward sharing; pass enrich for a fuller figure. getRewards({ epochs }) lists the inflation rewards the wallet's accounts actually received.

Safety

  • Fail-closed before anything is signed: unlisted, unknown, delinquent or over-commission validators; amounts under the minimum; a wallet that would drop under feeReserve; accounts the wallet is not the authority of; a lockup in force; merges the program would reject.
  • Accounts the module creates have the wallet as staker and withdrawer and no lockup. It never sets a custodian, never changes an authority, and never acts on an account whose SOL another address withdraws (a discovered account the wallet only manages).
  • Seed slots: someone can send dust to a stake:<i> address before the wallet uses it. Empty slots are used first. When only pre-funded ones are left, one is taken over with Transfer + AllocateWithSeed + Initialize; wallet-solana signs that by default because the same transaction makes the wallet the account's staker and withdrawer (a wallet that refuses it gets an error that says so; maxAccounts, up to 100, opens new slots). Every write the module builds is tested against wallet-solana's signing checks with the default config.
  • StakeHistory from an RPC node that has not reached the current epoch is refused, so statuses are never computed from a stale sysvar.
  • With a Solana allowlist policy, the kit checks each Stake instruction by whom it pays or empowers: allow the wallet's own address, the stake accounts (getStakeAccountAddress(i)) and the vote accounts of the validators you list. Allowlisting the Stake program itself opens nothing.

Testing

  • pnpm test: codecs byte for byte against mainnet transactions, the activation math against hand-computed program cases, every operation over an in-memory node, conformance with recorded mainnet activity.
  • pnpm verify:live [address] [rpcUrl]: reads on mainnet, then every write planned for a real wallet and simulated by the wallet (simulateTransaction, signatures off). Nothing is signed.