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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@sanctumso/sanctum-router

v0.0.1-dev-8

Published

Typescript + WASM SDK for the SPL stake pool program.

Readme

@sanctumso/sanctum-router

Typescript + WASM SDK for the SPL stake pool program.

Example Usage

import {
  createSolanaRpc,
  getBase64Encoder,
  type Address,
  type IInstruction,
  type Rpc,
  type SolanaRpcApi,
} from "@solana/kit";
import {
  accountsToUpdate,
  init,
  newSanctumRouter,
  prefundSwapViaStakeIx,
  quotePrefundSwapViaStake,
  update,
  type InitData,
  type SplPoolAccounts,
} from "@sanctumso/sanctum-router";
import initSdk from "@sanctumso/sanctum-router";

// The SDK needs to be initialized once globally before it can be used (idempotent).
// For nodejs environments, use
// `import { initSyncEmbed } from "@sanctumso/sanctum-router"; initSyncEmbed();`
// instead
await initSdk();

// SPL stake pools (all 3 deploys) must have the following data known beforehand
// and explicitly passed in at initialization time
const PICOSOL_INIT_DATA: InitData = {
  pool: "spl",
  stakePoolAddr: "8Dv3hNYcEWEaa4qVx9BTN1Wfvtha1z8cWDUXb7KVACVe",
  stakePoolProgramAddr: "SP12tWFxD9oJsVWNavTTBZvMbA6gkAmxtVgxdqvyvhY",
  validatorListAddr: "46A5KjX8J6FAUTXwcE8iJkmM7igK3v8vy1MD74cZNWVE",
  reserveStakeAddr: "2ArodFTZhNqVWJT92qEGDxigAvouSo1kfgfEcC3KEWUK",
};

const PICOSOL_MINT = "picobAEvs6w7QEknPce34wAE4gknZA9v5tTonnmHYdX";
const MSOL_MINT = "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So";

async function fetchAccountMap(
  rpc: Rpc<SolanaRpcApi>,
  accounts: string[]
): Promise<AccountMap> {
  const map = new Map<string, Account>();
  await Promise.all(
    accounts.map(async (account) => {
      const accountInfo = await rpc
        .getAccountInfo(account as Address, {
          encoding: "base64",
        })
        .send();
      const acc = accountInfo.value!;
      map.set(account, {
        data: new Uint8Array(getBase64Encoder().encode(acc.data[0])),
        owner: acc.owner,
      });
    })
  );
  return map;
}

const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");

// init
const sanctumRouter = newSanctumRouter();
init(sanctumRouter, [
  {
    mint: PICOSOL_MINT,
    init: PICOSOL_INIT_DATA,
  },
  {
    mint: MSOL_MINT,
  },
]);

// update
const swapMints = [
  {
    swap: "prefundSwapViaStake",
    inp: PICOSOL_MINT,
    out: MSOL_MINT,
  }
];
const accs = accountsToUpdate(sanctumRouter, swapMints);
const accountsToUpdateMap = await fetchAccountMap(rpc, accs);
update(sanctumRouter, swapMints, accountsToUpdateMap);

// quote
const amt = 1_000_000_000n;
const {
  prefundFee,
  quote: {
    routerFee,
    quote: {
      inp,
      out,
      inpFee,
      outFee,
      bridge,
    },
  },
} = quotePrefundSwapViaStake(sanctumRouter, {
  amt,
  inp: PICOSOL_MINT,
  out: MSOL_MINT,
});

// create transaction instruction

// user-provided pubkeys
const signer = ...;
const inpTokenAcc = ...;
const outTokenAcc = ...;

// For PrefundSwapViaStakes and PrefundWithdrawStakes,
// the user must find a u32 bridge stake seed
// that is unused (the bridge stake PDA it creates using
// `findBridgeStakeAccPda()` does not exist as an account onchain)
const bridgeStakedSeed = ...;

const ixUncasted = prefundSwapViaStakeIx(sanctumRouter, {
  amt,
  inp: PICOSOL_MINT,
  out: MSOL_MINT,
  signerInp: inpTokenAcc,
  signerOut: outTokenAcc,
  signer,
  bridgeStakeSeed,

  // optional, this fn runs faster if provided with the
  // bridge stake account's delegated voter that was found beforehand
  bridgeVote: bridge.vote,
});
// return type is compatible with kit,
// but needs to be casted explicitly
const ix = ixUncasted as unknown as IInstruction;

Cloudflare Workers

In Cloudflare Workers and other restricted environments, the default export async init function fails without any args due to path issues of the wasm file, while initSyncEmbed() fails due to security restrictions disallowing generation of untrusted wasm code at runtime. The workaround is to copy out the .wasm file included in this package into somewhere accessible by these restricted environments, and import it as a module.

import { initSync } from "@sanctumso/sanctum-router-sdk";
import wasm from "../libs/sanctum_router_sdk_index_bg.wasm";

initSync({ module: wasm });
// or use the package's default export async init function
// instead of `initSync()`

Build

Prerequisites