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

fema-pf-calc

v1.1.0

Published

Intelligent Solana priority fee estimation engine

Readme

Fema

Fema is a TypeScript SDK for Solana with two tools: estimateFee calculates the right priority fee based on what the network is actually paying right now, and safeSend handles the full transaction lifecycle including simulation, signing, submission, and confirmation.

Supports mainnet-beta and devnet.

The Problem

Every Solana transaction can include a priority fee, a tip paid to validators to land the transaction faster. Set it too low and your transaction gets stuck or dropped. Set it too high and you overpay.

The fee you need also depends on what kind of transaction you are sending. A Jupiter swap competes with other Jupiter swaps. An NFT mint competes with other NFT mints. They are not in the same queue, so they should not use the same fee.

Fema solves this by scanning recent blocks, building a real fee distribution, and giving you a number you can use directly.

How It Works

  1. Fema connects to Solana via a built-in Helius-backed RPC proxy — no API key or RPC setup required
  2. For each transaction in the last 30 blocks it extracts the fee paid in microLamports per compute unit
  3. It sorts these into a distribution and computes percentiles (p25, p50, p75)
  4. If you specify a protocol or pass your transaction, it filters the data to only transactions that used the same programs as yours
  5. It returns the fee at the percentile matching your chosen speed and strategy

Results are cached for 7 seconds to avoid hammering the RPC on every call.

Installation

npm install fema-pf-calc

estimateFee Quick Start

import { init, estimateFee } from "fema-pf-calc";
import { ComputeBudgetProgram } from "@solana/web3.js";

// Configure once at app startup
init({ cluster: "mainnet-beta" }); // no RPC setup needed

// Get the recommended fee
const { fee } = await estimateFee({ speed: "fast", strategy: "balanced" });

// Apply it to your transaction
const priorityIx = ComputeBudgetProgram.setComputeUnitPrice({
  microLamports: fee,
});

That is all a developer needs to do. No RPC key, no math, no guessing.

estimateFee Options

const result = await estimateFee({
  speed: "fast",             // "slow" | "medium" | "fast"
  strategy: "balanced",      // "cheap" | "balanced" | "aggressive"
  protocol: "jupiter",       // see supported protocols below
  transaction: myTransaction, // pass your actual tx for automatic protocol detection
  maxFee: 500_000,           // optional cap in microLamports
  includeStats: true,        // include full distribution in response
});

Speed

| Speed | Percentile | What it means | | -------- | ---------- | --------------------------------------------------- | | slow | p25 | Cheaper. May take a few blocks to land. | | medium | p50 | Balanced. Lands within a couple of blocks. | | fast | p75 | More expensive. Designed to land in the next block. |

Strategy

| Strategy | Adjustment | What it means | | ------------ | --------------------- | ------------------------------------------------------------------------- | | cheap | −10 percentile points | Slightly undercut the target. Risk: might not land if the network spikes. | | balanced | none | Hit the target exactly. Safe default for most use cases. | | aggressive | +15 percentile points | Slightly overpay to guarantee landing. |

Protocol-Aware Estimation

The most powerful feature of Fema. When you specify a protocol, Fema filters the fee data to only transactions that used the same programs — giving you a fee based on your actual competition, not the whole network.

// Jupiter swap
const { fee: swapFee } = await estimateFee({
  speed: "fast",
  protocol: "jupiter",
});

// NFT mint
const { fee: nftFee } = await estimateFee({ speed: "fast", protocol: "nft" });

// Pump.fun trade
const { fee: pumpFee } = await estimateFee({
  speed: "fast",
  protocol: "pumpfun",
});

Alternatively, pass your actual transaction and Fema will detect the protocol automatically:

const { fee } = await estimateFee({
  speed: "fast",
  transaction: mySwapTransaction,
});

Supported Protocols

| Protocol | Programs Included | | ---------- | --------------------------------------------------- | | jupiter | Jupiter V4, Jupiter V6 | | raydium | Raydium AMM V4, AMM V5, CLMM | | orca | Orca Whirlpool, Orca V1 | | nft | Token Metadata, Candy Machine V2/V3, Auction House | | pumpfun | Pump.fun | | openbook | OpenBook V1, OpenBook V2 | | system | System Program (SOL transfers) | | token | Token Program, Token 2022, Associated Token Program |

estimateFee Response

{
  fee: 253637,           // microLamports per CU — pass directly to setComputeUnitPrice
  congestion: "high",    // "low" | "medium" | "high"
  percentileUsed: 75,    // which percentile was used
  sampleSize: 1203,      // number of transactions analyzed
  programFiltered: true, // true = fee is based on your protocol's txs specifically

  // only included when includeStats: true
  stats: {
    avgFee: 180000,
    medianFee: 28844,
    distribution: {
      p10: 1200,
      p25: 5011,
      p50: 28844,
      p75: 253637,
      p90: 480000,
      p95: 820000,
      p99: 2100000,
    }
  }
}

The fee value is in microLamports per compute unit — the exact unit that ComputeBudgetProgram.setComputeUnitPrice expects. No conversion needed.

Configuration

init({
  cluster: "mainnet-beta", // "mainnet-beta" | "devnet" (default: "mainnet-beta")
  cacheDurationMs: 7000,   // how long to cache results in ms (default: 7000)
});

Sample Code

import express from "express";
import { init, estimateFee } from "fema-pf-calc";
import { ComputeBudgetProgram } from "@solana/web3.js";

const app = express();

init({ cluster: "mainnet-beta" }); // no RPC setup needed

app.get("/fee", async (req, res) => {
  try {
    const { fee } = await estimateFee({ speed: "fast", strategy: "balanced" });

    const priorityIx = ComputeBudgetProgram.setComputeUnitPrice({
      microLamports: fee,
    });

    res.json({ fee, priorityIx });
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: err.message });
  }
});

app.listen(8000, () => {
  console.log("Server is running on port http://localhost:8000");
});

export default app;

safeSend

safeSend handles the full lifecycle of sending a Solana transaction. It simulates before sending, signs with your wallet, submits, and confirms on-chain. It catches errors before they cost SOL, retries automatically when safe to do so, and tells you exactly what went wrong when it isn't.

safeSend Quick Start

import { safeSend } from "fema-pf-calc";

const result = await safeSend({
  tx: myTransaction,
  wallet: walletAdapter, // any wallet with signTransaction (Phantom, Backpack, etc.)
  network: "mainnet-beta",
  mode: "safe",
});

if (result.success) {
  console.log("Confirmed:", result.signature);
} else {
  console.log("Failed:", result.error?.type);
}

safeSend Options

const result = await safeSend({
  tx: myTransaction,          // Transaction | VersionedTransaction
  wallet: walletAdapter,      // must implement signTransaction
  network: "mainnet-beta",    // "devnet" | "mainnet-beta" (default: "devnet")
  mode: "safe",               // "safe" | "fast" (default: "safe")
  ai: true,                   // enable AI diagnostics on failure (default: false)
});

Mode

| Mode | What it does | | ------ | -------------------------------------------------------------------------- | | safe | Simulates first, retries up to 3× on recoverable errors, confirms on-chain | | fast | Simulates first, sends once, returns immediately — no retries |

safeSend Response

// Success
{ success: true, signature: "5Kj...", network: "mainnet-beta", retriesUsed: 0 }

// Failure
{
  success: false,
  network: "mainnet-beta",
  retriesUsed: 2,
  error: {
    type: "INSUFFICIENT_FUNDS",
    logs: ["..."],

    // only included when ai: true
    explanation: "The sender account does not have enough lamports...",
    suggestedFix: "Fund the account with at least 0.05 SOL before retrying.",
  }
}

Error Types

| Type | Recoverable | What happened | | ---------------------- | ----------- | ------------------------------------------------- | | INSUFFICIENT_FUNDS | No | Sender cannot cover the transfer + fees | | BLOCKHASH_EXPIRED | Yes | Blockhash went stale, retried with a fresh one | | COMPUTE_EXCEEDED | Yes | Compute limit too low, auto-bumped and retried | | INVALID_INSTRUCTION | No | Instruction references a wrong or unknown program | | NETWORK_FAILURE | No | Could not reach the RPC | | SEND_FAILED | No | Transaction was rejected at submission | | SIGNING_REJECTED | No | Wallet refused to sign | | CONFIRMATION_TIMEOUT | No | Transaction was sent but not confirmed in time | | MAX_RETRIES_EXCEEDED | No | Hit the 3-retry limit without landing |

AI Diagnostics

Set ai: true and add a GROQ_API_KEY to your environment to get a plain-English explanation and a concrete fix suggestion on every failure.

const result = await safeSend({ tx, wallet, network: "mainnet-beta", ai: true });

if (!result.success) {
  console.log(result.error?.explanation);  // "The compute budget was exceeded..."
  console.log(result.error?.suggestedFix); // "Add ComputeBudgetProgram.setComputeUnitLimit..."
}

Get a free Groq API key at console.groq.com. Fema uses Llama 3.3-70b under the hood and falls back silently if the key is missing or the API is unavailable.

License

MIT