fema-pf-calc 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,265 @@
1
+ # FEMA — Fee Estimation & Management for Solana
2
+
3
+ FEMA is a TypeScript SDK that calculates optimal priority fees for Solana transactions in real time. Instead of hardcoding a fee or guessing, developers install FEMA and call one function to get the right fee based on what the network is actually paying right now.
4
+
5
+ Supports **mainnet-beta** and **devnet**.
6
+
7
+ ---
8
+
9
+ ## The Problem
10
+
11
+ 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.
12
+
13
+ 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.
14
+
15
+ FEMA solves this by scanning recent blocks, building a real fee distribution, and giving you a number you can use directly.
16
+
17
+ ---
18
+
19
+ ## How It Works
20
+
21
+ 1. FEMA connects to a Solana RPC and fetches data from the last 30 blocks
22
+ 2. For each transaction in those blocks it extracts the fee paid in microLamports per compute unit
23
+ 3. It sorts these into a distribution and computes percentiles (p25, p50, p75)
24
+ 4. If you specify a protocol or pass your transaction, it filters the data to only transactions that used the same programs as yours
25
+ 5. It returns the fee at the percentile matching your chosen speed and strategy
26
+
27
+ Results are cached for 5–10 seconds to avoid hammering the RPC on every call.
28
+
29
+ ---
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ npm install fema-pf-calc
35
+ ```
36
+
37
+ ---
38
+
39
+ ## Quick Start
40
+
41
+ ```ts
42
+ import { init, estimateFee } from "fema-pf-calc";
43
+ import { ComputeBudgetProgram } from "@solana/web3.js";
44
+
45
+ // Configure once at app startup
46
+ init({
47
+ cluster: "mainnet-beta", // or "devnet"
48
+ rpcUrl: "https://mainnet.helius-rpc.com/?api-key=YOUR_KEY", // optional override
49
+ });
50
+
51
+ // Get the recommended fee
52
+ const { fee } = await estimateFee({ speed: "fast", strategy: "balanced" });
53
+
54
+ // Apply it to your transaction
55
+ const priorityIx = ComputeBudgetProgram.setComputeUnitPrice({
56
+ microLamports: fee,
57
+ });
58
+ ```
59
+
60
+ That is all a developer needs to do. No RPC calls, no math, no guessing.
61
+
62
+ ---
63
+
64
+ ## Options
65
+
66
+ ```ts
67
+ const result = await estimateFee({
68
+ speed: "slow" | "medium" | "fast", // how urgently you need it to land
69
+ strategy: "cheap" | "balanced" | "aggressive", // how competitive to be
70
+ protocol: "jupiter" | "raydium" | "orca" | "nft" | "pumpfun" | "openbook" | "system" | "token",
71
+ transaction: myTransaction, // pass your actual tx for automatic protocol detection
72
+ maxFee: 500_000, // optional cap in microLamports
73
+ includeStats: true, // include full distribution in response
74
+ });
75
+ ```
76
+
77
+ ### Speed
78
+
79
+ | Speed | Percentile | What it means |
80
+ |-------|-----------|---------------|
81
+ | `slow` | p25 | Cheaper. May take a few blocks to land. |
82
+ | `medium` | p50 | Balanced. Lands within a couple of blocks. |
83
+ | `fast` | p75 | More expensive. Designed to land in the next block. |
84
+
85
+ ### Strategy
86
+
87
+ | Strategy | Adjustment | What it means |
88
+ |----------|-----------|---------------|
89
+ | `cheap` | −10 percentile points | Slightly undercut the target. Risk: might not land if the network spikes. |
90
+ | `balanced` | none | Hit the target exactly. Safe default for most use cases. |
91
+ | `aggressive` | +15 percentile points | Slightly overpay to guarantee landing. |
92
+
93
+ ---
94
+
95
+ ## Protocol-Aware Estimation
96
+
97
+ 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.
98
+
99
+ ```ts
100
+ // Jupiter swap
101
+ const { fee: swapFee } = await estimateFee({ speed: "fast", protocol: "jupiter" });
102
+
103
+ // NFT mint
104
+ const { fee: nftFee } = await estimateFee({ speed: "fast", protocol: "nft" });
105
+
106
+ // Pump.fun trade
107
+ const { fee: pumpFee } = await estimateFee({ speed: "fast", protocol: "pumpfun" });
108
+ ```
109
+
110
+ Alternatively, pass your actual transaction and FEMA will detect the protocol automatically:
111
+
112
+ ```ts
113
+ const { fee } = await estimateFee({
114
+ speed: "fast",
115
+ transaction: mySwapTransaction,
116
+ });
117
+ ```
118
+
119
+ ### Supported Protocols
120
+
121
+ | Protocol | Programs Included |
122
+ |----------|------------------|
123
+ | `jupiter` | Jupiter V4, Jupiter V6 |
124
+ | `raydium` | Raydium AMM V4, AMM V5, CLMM |
125
+ | `orca` | Orca Whirlpool, Orca V1 |
126
+ | `nft` | Token Metadata, Candy Machine V2/V3, Auction House |
127
+ | `pumpfun` | Pump.fun |
128
+ | `openbook` | OpenBook V1, OpenBook V2 |
129
+ | `system` | System Program (SOL transfers) |
130
+ | `token` | Token Program, Token 2022, Associated Token Program |
131
+
132
+ ---
133
+
134
+ ## Response
135
+
136
+ ```ts
137
+ {
138
+ fee: 253637, // microLamports per CU — pass directly to setComputeUnitPrice
139
+ congestion: "high", // "low" | "medium" | "high"
140
+ percentileUsed: 75, // which percentile was used
141
+ sampleSize: 1203, // number of transactions analyzed
142
+ programFiltered: true, // true = fee is based on your protocol's txs specifically
143
+
144
+ // only included when includeStats: true
145
+ stats: {
146
+ avgFee: 180000,
147
+ medianFee: 28844,
148
+ distribution: {
149
+ p10: 1200,
150
+ p25: 5011,
151
+ p50: 28844,
152
+ p75: 253637,
153
+ p90: 480000,
154
+ p95: 820000,
155
+ p99: 2100000,
156
+ }
157
+ }
158
+ }
159
+ ```
160
+
161
+ The `fee` value is in **microLamports per compute unit** — the exact unit that `ComputeBudgetProgram.setComputeUnitPrice` expects. No conversion needed.
162
+
163
+ ---
164
+
165
+ ## Configuration
166
+
167
+ ```ts
168
+ init({
169
+ cluster: "mainnet-beta", // "mainnet-beta" | "devnet" (default: "mainnet-beta")
170
+ rpcUrl: "https://your-rpc.com", // optional — overrides the cluster default
171
+ cacheDurationMs: 7000, // how long to cache results in ms (default: 7000)
172
+ });
173
+ ```
174
+
175
+ ### Cluster RPC defaults
176
+
177
+ | Cluster | Default RPC |
178
+ |---------|-------------|
179
+ | `mainnet-beta` | `https://api.mainnet-beta.solana.com` |
180
+ | `devnet` | `https://api.devnet.solana.com` |
181
+
182
+ Or configure via `.env`:
183
+
184
+ ```env
185
+ # Network: mainnet-beta (default) or devnet
186
+ SOLANA_CLUSTER=mainnet-beta
187
+
188
+ # Optional: override the RPC URL for the selected cluster
189
+ # SOLANA_RPC_URL=https://your-custom-rpc.com
190
+
191
+ # How long to cache fee data in milliseconds (default: 7000)
192
+ CACHE_DURATION_MS=7000
193
+
194
+ # Express server port (default: 3000)
195
+ PORT=3000
196
+ ```
197
+
198
+ ---
199
+
200
+ ## Test Script
201
+
202
+ Run a live fee report from the terminal:
203
+
204
+ ```bash
205
+ # Mainnet (default)
206
+ ts-node test-fees.ts
207
+
208
+ # Devnet
209
+ ts-node test-fees.ts --network devnet
210
+ ts-node test-fees.ts --network=devnet
211
+
212
+ # Via env var
213
+ SOLANA_CLUSTER=devnet ts-node test-fees.ts
214
+ ```
215
+
216
+ ---
217
+
218
+ ## Optional HTTP Server
219
+
220
+ FEMA includes an Express server for teams who want to expose fee estimation over HTTP instead of importing the package directly.
221
+
222
+ ```bash
223
+ npm run server
224
+ ```
225
+
226
+ | Endpoint | Description |
227
+ |----------|-------------|
228
+ | `GET /health` | Check server status and active RPC URL |
229
+ | `GET /estimate-fee?speed=fast&strategy=balanced` | Get a fee recommendation |
230
+ | `GET /stats` | Get fee with full distribution stats |
231
+
232
+ ---
233
+
234
+ ## RPC Recommendations
235
+
236
+ The public Solana RPC endpoints rate-limit aggressively. For reliable results use a private RPC:
237
+
238
+ - [Helius](https://helius.dev) — free tier available
239
+ - [QuickNode](https://quicknode.com)
240
+ - [Alchemy](https://alchemy.com)
241
+
242
+ ---
243
+
244
+ ## Project Structure
245
+
246
+ ```
247
+ src/
248
+ ├── index.ts # SDK entry point — estimateFee() and init()
249
+ ├── server.ts # Optional Express HTTP server
250
+ ├── types.ts # TypeScript types and interfaces
251
+ ├── config.ts # Configuration and cluster RPC resolution
252
+ ├── protocols.ts # Known protocol registry (Jupiter, Raydium, etc.)
253
+ ├── engine/
254
+ │ └── feeCalculator.ts # Percentile math, strategy modifiers, outlier filtering
255
+ └── services/
256
+ ├── solana.ts # RPC data fetching and block scanning
257
+ ├── cache.ts # In-memory TTL cache
258
+ └── database.ts # In-memory snapshot store and fallback
259
+ ```
260
+
261
+ ---
262
+
263
+ ## License
264
+
265
+ MIT
@@ -0,0 +1,6 @@
1
+ import { FemaConfig, SolanaCluster } from "./types";
2
+ declare const CLUSTER_RPC: Record<SolanaCluster, string>;
3
+ export declare function init(overrides: Partial<FemaConfig>): void;
4
+ export { CLUSTER_RPC };
5
+ export declare function getConfig(): FemaConfig;
6
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAEpD,QAAA,MAAM,WAAW,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAG9C,CAAC;AAsBF,wBAAgB,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI,CAIzD;AAED,OAAO,EAAE,WAAW,EAAE,CAAC;AAEvB,wBAAgB,SAAS,IAAI,UAAU,CAEtC"}
package/dist/config.js ADDED
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CLUSTER_RPC = void 0;
4
+ exports.init = init;
5
+ exports.getConfig = getConfig;
6
+ const CLUSTER_RPC = {
7
+ "mainnet-beta": "https://api.mainnet-beta.solana.com",
8
+ "devnet": "https://api.devnet.solana.com",
9
+ };
10
+ exports.CLUSTER_RPC = CLUSTER_RPC;
11
+ const DEFAULT_CACHE_MS = 7000;
12
+ function resolveCluster() {
13
+ const raw = process.env.SOLANA_CLUSTER ?? "mainnet-beta";
14
+ if (raw === "devnet")
15
+ return "devnet";
16
+ return "mainnet-beta";
17
+ }
18
+ function resolveRpc(cluster) {
19
+ return process.env.SOLANA_RPC_URL ?? CLUSTER_RPC[cluster];
20
+ }
21
+ const defaultCluster = resolveCluster();
22
+ let _config = {
23
+ cluster: defaultCluster,
24
+ rpcUrl: resolveRpc(defaultCluster),
25
+ cacheDurationMs: Number(process.env.CACHE_DURATION_MS ?? DEFAULT_CACHE_MS),
26
+ };
27
+ function init(overrides) {
28
+ const cluster = overrides.cluster ?? _config.cluster;
29
+ const rpcUrl = overrides.rpcUrl ?? CLUSTER_RPC[cluster];
30
+ _config = { ..._config, ...overrides, cluster, rpcUrl };
31
+ }
32
+ function getConfig() {
33
+ return _config;
34
+ }
35
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;AA2BA,oBAIC;AAID,8BAEC;AAnCD,MAAM,WAAW,GAAkC;IACjD,cAAc,EAAE,qCAAqC;IACrD,QAAQ,EAAE,+BAA+B;CAC1C,CAAC;AA4BO,kCAAW;AA1BpB,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAE9B,SAAS,cAAc;IACrB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,cAAc,CAAC;IACzD,IAAI,GAAG,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IACtC,OAAO,cAAc,CAAC;AACxB,CAAC;AAED,SAAS,UAAU,CAAC,OAAsB;IACxC,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,cAAc,GAAG,cAAc,EAAE,CAAC;AAExC,IAAI,OAAO,GAAe;IACxB,OAAO,EAAE,cAAc;IACvB,MAAM,EAAE,UAAU,CAAC,cAAc,CAAC;IAClC,eAAe,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,gBAAgB,CAAC;CAC3E,CAAC;AAEF,SAAgB,IAAI,CAAC,SAA8B;IACjD,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IACrD,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;IACxD,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AAC1D,CAAC;AAID,SAAgB,SAAS;IACvB,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { Speed, Strategy, FeeSnapshot, FeeEntry } from "../types";
2
+ /**
3
+ * Filter a fee entry dataset to entries that share at least one program
4
+ * with the target transaction. Falls back to the full dataset if too few matches.
5
+ */
6
+ export declare function filterByPrograms(entries: FeeEntry[], programIds: string[]): {
7
+ fees: number[];
8
+ programFiltered: boolean;
9
+ };
10
+ export declare function percentile(sorted: number[], p: number): number;
11
+ export declare function average(values: number[]): number;
12
+ export interface CalcResult {
13
+ fee: number;
14
+ percentileUsed: number;
15
+ snapshot: FeeSnapshot;
16
+ rawFees: number[];
17
+ }
18
+ export declare function calculateFee(rawFees: number[], speed: Speed, strategy: Strategy, maxFee?: number, computeUnits?: number): CalcResult;
19
+ //# sourceMappingURL=feeCalculator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feeCalculator.d.ts","sourceRoot":"","sources":["../../src/engine/feeCalculator.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,QAAQ,EAER,WAAW,EACX,QAAQ,EACT,MAAM,UAAU,CAAC;AAIlB;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,QAAQ,EAAE,EACnB,UAAU,EAAE,MAAM,EAAE,GACnB;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,eAAe,EAAE,OAAO,CAAA;CAAE,CAgB9C;AAID,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAO9D;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAGhD;AA6BD,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,WAAW,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EAAE,EACjB,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,QAAQ,EAClB,MAAM,CAAC,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM,GACpB,UAAU,CA6CZ"}
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.filterByPrograms = filterByPrograms;
4
+ exports.percentile = percentile;
5
+ exports.average = average;
6
+ exports.calculateFee = calculateFee;
7
+ const MIN_PROGRAM_SAMPLES = 15;
8
+ /**
9
+ * Filter a fee entry dataset to entries that share at least one program
10
+ * with the target transaction. Falls back to the full dataset if too few matches.
11
+ */
12
+ function filterByPrograms(entries, programIds) {
13
+ if (programIds.length === 0) {
14
+ return { fees: entries.map((e) => e.fee), programFiltered: false };
15
+ }
16
+ const targetSet = new Set(programIds);
17
+ const matched = entries.filter((e) => e.programs.some((p) => targetSet.has(p)));
18
+ if (matched.length >= MIN_PROGRAM_SAMPLES) {
19
+ return { fees: matched.map((e) => e.fee), programFiltered: true };
20
+ }
21
+ // Not enough program-specific samples — fall back to full network data
22
+ return { fees: entries.map((e) => e.fee), programFiltered: false };
23
+ }
24
+ // ─── Percentile helpers ───────────────────────────────────────────────────────
25
+ function percentile(sorted, p) {
26
+ if (sorted.length === 0)
27
+ return 0;
28
+ const idx = (p / 100) * (sorted.length - 1);
29
+ const lower = Math.floor(idx);
30
+ const upper = Math.ceil(idx);
31
+ if (lower === upper)
32
+ return sorted[lower];
33
+ return sorted[lower] + (sorted[upper] - sorted[lower]) * (idx - lower);
34
+ }
35
+ function average(values) {
36
+ if (values.length === 0)
37
+ return 0;
38
+ return values.reduce((a, b) => a + b, 0) / values.length;
39
+ }
40
+ // ─── Speed → base percentile ─────────────────────────────────────────────────
41
+ const SPEED_PERCENTILE = {
42
+ slow: 25,
43
+ medium: 50,
44
+ fast: 75,
45
+ };
46
+ // ─── Strategy → percentile delta ─────────────────────────────────────────────
47
+ const STRATEGY_DELTA = {
48
+ cheap: -10,
49
+ balanced: 0,
50
+ aggressive: 15,
51
+ };
52
+ // ─── Congestion thresholds (microLamports avg) ────────────────────────────────
53
+ function deriveCongestion(medianFee, txCount) {
54
+ // Use median (not avg) so MEV outliers don't inflate congestion level
55
+ if (medianFee > 100000 || txCount > 1000)
56
+ return "high";
57
+ if (medianFee > 10000 || txCount > 300)
58
+ return "medium";
59
+ return "low";
60
+ }
61
+ function calculateFee(rawFees, speed, strategy, maxFee, computeUnits) {
62
+ let fees = rawFees.length > 0 ? [...rawFees].sort((a, b) => a - b) : [1];
63
+ // Strip MEV/bot outliers above p99 so they don't distort p75/avg
64
+ if (fees.length >= 10) {
65
+ const cap = percentile(fees, 99);
66
+ fees = fees.filter((f) => f <= cap);
67
+ }
68
+ const basePercentile = SPEED_PERCENTILE[speed];
69
+ const delta = STRATEGY_DELTA[strategy];
70
+ const targetPercentile = Math.max(1, Math.min(99, basePercentile + delta));
71
+ let fee = Math.round(percentile(fees, targetPercentile));
72
+ const avgFee = Math.round(average(fees));
73
+ const medianFee = Math.round(percentile(fees, 50));
74
+ const p25Fee = Math.round(percentile(fees, 25));
75
+ const p75Fee = Math.round(percentile(fees, 75));
76
+ // Scale by compute units if provided (fee is per-CU; default CU = 200_000)
77
+ if (computeUnits && computeUnits !== 200000) {
78
+ fee = Math.round(fee * (computeUnits / 200000));
79
+ }
80
+ // Apply maxFee cap
81
+ if (maxFee !== undefined && fee > maxFee) {
82
+ fee = maxFee;
83
+ }
84
+ // Ensure a sensible minimum (1 microLamport)
85
+ fee = Math.max(1, fee);
86
+ const congestionLevel = deriveCongestion(medianFee, fees.length);
87
+ const snapshot = {
88
+ timestamp: new Date().toISOString(),
89
+ avgFee,
90
+ medianFee,
91
+ p25Fee,
92
+ p75Fee,
93
+ congestionLevel,
94
+ txCount: fees.length,
95
+ };
96
+ return { fee, percentileUsed: targetPercentile, snapshot, rawFees: fees };
97
+ }
98
+ //# sourceMappingURL=feeCalculator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feeCalculator.js","sourceRoot":"","sources":["../../src/engine/feeCalculator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { FemaConfig, EstimateFeeOptions, EstimateFeeResult } from "./types";
2
+ export type { EstimateFeeOptions, EstimateFeeResult, FemaConfig, FeeSnapshot, FeeStats, FeeEntry, Speed, Strategy, CongestionLevel, SolanaCluster, } from "./types";
3
+ export type { Protocol } from "./protocols";
4
+ export { PROTOCOLS } from "./protocols";
5
+ export declare function init(config: Partial<FemaConfig>): void;
6
+ export declare function estimateFee(options?: EstimateFeeOptions): Promise<EstimateFeeResult>;
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAA6B,MAAM,SAAS,CAAC;AAiBvG,YAAY,EACV,kBAAkB,EAClB,iBAAiB,EACjB,UAAU,EACV,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,eAAe,EACf,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAMxC,wBAAgB,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI,CAQtD;AAID,wBAAsB,WAAW,CAC/B,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CAsE5B"}
package/dist/index.js ADDED
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PROTOCOLS = void 0;
4
+ exports.init = init;
5
+ exports.estimateFee = estimateFee;
6
+ const config_1 = require("./config");
7
+ const cache_1 = require("./services/cache");
8
+ const solana_1 = require("./services/solana");
9
+ const protocols_1 = require("./protocols");
10
+ const database_1 = require("./services/database");
11
+ const feeCalculator_1 = require("./engine/feeCalculator");
12
+ var protocols_2 = require("./protocols");
13
+ Object.defineProperty(exports, "PROTOCOLS", { enumerable: true, get: function () { return protocols_2.PROTOCOLS; } });
14
+ // ─── SDK initialisation ───────────────────────────────────────────────────────
15
+ let _started = false;
16
+ function init(config) {
17
+ (0, config_1.init)(config);
18
+ (0, solana_1.resetConnection)();
19
+ if (!_started) {
20
+ (0, database_1.startPersistedInterval)(() => (0, database_1.getLatestSnapshotSync)(), 15000);
21
+ _started = true;
22
+ }
23
+ }
24
+ // ─── Primary API ──────────────────────────────────────────────────────────────
25
+ async function estimateFee(options = {}) {
26
+ const { speed = "medium", strategy = "balanced", includeStats = false, maxFee, transaction, protocol, } = options;
27
+ // 1. Resolve program IDs from protocol shorthand or raw transaction
28
+ let programIds = [];
29
+ if (protocol) {
30
+ programIds = (0, protocols_1.getProtocolProgramIds)(protocol);
31
+ }
32
+ else if (transaction) {
33
+ const txPrograms = (0, solana_1.extractProgramIds)(transaction);
34
+ programIds = txPrograms;
35
+ // Auto-detect protocol from the transaction's programs (for logging)
36
+ const detected = (0, protocols_1.detectProtocol)(txPrograms);
37
+ if (detected) {
38
+ // Expand to full protocol program list for better coverage
39
+ programIds = (0, protocols_1.getProtocolProgramIds)(detected);
40
+ }
41
+ }
42
+ const needsProgramData = programIds.length > 0;
43
+ const computeUnits = transaction ? (0, solana_1.estimateComputeUnits)(transaction) : undefined;
44
+ // 2. Try in-memory cache first (only reuse if it has program data when needed)
45
+ const cached = (0, cache_1.getCached)();
46
+ const cacheHasProgramData = cached?.entries.some((e) => e.programs.length > 0) ?? false;
47
+ if (cached && (!needsProgramData || cacheHasProgramData)) {
48
+ const { fees, programFiltered } = (0, feeCalculator_1.filterByPrograms)(cached.entries, programIds);
49
+ const { fee, percentileUsed, snapshot, rawFees } = (0, feeCalculator_1.calculateFee)(fees, speed, strategy, maxFee, computeUnits);
50
+ return buildResult(fee, snapshot, percentileUsed, rawFees, includeStats, programFiltered);
51
+ }
52
+ // 3. Fetch fresh data from Solana RPC
53
+ let entries = [];
54
+ let fromFallback = false;
55
+ try {
56
+ entries = await (0, solana_1.fetchRecentPriorityFees)(30, needsProgramData);
57
+ if (entries.length === 0)
58
+ throw new Error("No fee data returned from RPC");
59
+ }
60
+ catch (err) {
61
+ console.warn("[FEMA] RPC fetch failed, using fallback:", err.message);
62
+ fromFallback = true;
63
+ }
64
+ // 4. Fallback: most recent in-memory snapshot
65
+ if (fromFallback || entries.length === 0) {
66
+ const cached = (0, database_1.getLatestSnapshotSync)();
67
+ const fallbackFees = cached
68
+ ? reconstructFees(cached.p25Fee, cached.medianFee, cached.p75Fee)
69
+ : [1000];
70
+ entries = fallbackFees.map((fee) => ({ fee, programs: [] }));
71
+ }
72
+ // 5. Filter to program-relevant transactions (if transaction was provided)
73
+ const { fees, programFiltered } = (0, feeCalculator_1.filterByPrograms)(entries, programIds);
74
+ // 6. Calculate
75
+ const { fee, percentileUsed, snapshot, rawFees } = (0, feeCalculator_1.calculateFee)(fees, speed, strategy, maxFee, computeUnits);
76
+ // 7. Update cache & latest snapshot reference
77
+ (0, cache_1.setCache)(snapshot, entries);
78
+ (0, database_1.setLatestSnapshot)(snapshot);
79
+ return buildResult(fee, snapshot, percentileUsed, rawFees, includeStats, programFiltered);
80
+ }
81
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
82
+ function buildResult(fee, snapshot, percentileUsed, rawFees, includeStats, programFiltered) {
83
+ const result = {
84
+ fee,
85
+ congestion: snapshot.congestionLevel,
86
+ percentileUsed,
87
+ sampleSize: rawFees.length,
88
+ programFiltered,
89
+ };
90
+ if (includeStats) {
91
+ result.stats = {
92
+ avgFee: snapshot.avgFee,
93
+ medianFee: snapshot.medianFee,
94
+ distribution: buildDistribution(rawFees),
95
+ };
96
+ }
97
+ return result;
98
+ }
99
+ function buildDistribution(sortedFees) {
100
+ const p = (n) => Math.round((0, feeCalculator_1.percentile)(sortedFees, n));
101
+ return { p10: p(10), p25: p(25), p50: p(50), p75: p(75), p90: p(90), p95: p(95), p99: p(99) };
102
+ }
103
+ function reconstructFees(p25, median, p75) {
104
+ return [
105
+ Math.round(p25 * 0.5),
106
+ p25,
107
+ Math.round((p25 + median) / 2),
108
+ median,
109
+ Math.round((median + p75) / 2),
110
+ p75,
111
+ Math.round(p75 * 1.5),
112
+ ];
113
+ }
114
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export type Protocol = "jupiter" | "raydium" | "orca" | "nft" | "pumpfun" | "openbook" | "system" | "token";
2
+ export interface ProtocolInfo {
3
+ name: string;
4
+ description: string;
5
+ programIds: string[];
6
+ }
7
+ export declare const PROTOCOLS: Record<Protocol, ProtocolInfo>;
8
+ export declare function getProtocolProgramIds(protocol: Protocol): string[];
9
+ export declare function detectProtocol(programIds: string[]): Protocol | null;
10
+ //# sourceMappingURL=protocols.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocols.d.ts","sourceRoot":"","sources":["../src/protocols.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAChB,SAAS,GACT,SAAS,GACT,MAAM,GACN,KAAK,GACL,SAAS,GACT,UAAU,GACV,QAAQ,GACR,OAAO,CAAC;AAEZ,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,QAAQ,EAAE,YAAY,CA0EpD,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,EAAE,CAElE;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,QAAQ,GAAG,IAAI,CAUpE"}
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PROTOCOLS = void 0;
4
+ exports.getProtocolProgramIds = getProtocolProgramIds;
5
+ exports.detectProtocol = detectProtocol;
6
+ exports.PROTOCOLS = {
7
+ jupiter: {
8
+ name: "Jupiter Aggregator",
9
+ description: "Token swaps via Jupiter V6",
10
+ programIds: [
11
+ "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4", // Jupiter V6
12
+ "JUP4Fb2cqiRUcaTHdrPC8h2gNsA2ETXiPDD33WcGuJB", // Jupiter V4
13
+ ],
14
+ },
15
+ raydium: {
16
+ name: "Raydium",
17
+ description: "Swaps and liquidity on Raydium AMM / CLMM",
18
+ programIds: [
19
+ "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", // Raydium AMM V4
20
+ "CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK", // Raydium CLMM
21
+ "5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h", // Raydium AMM V5
22
+ ],
23
+ },
24
+ orca: {
25
+ name: "Orca Whirlpools",
26
+ description: "Swaps on Orca concentrated liquidity pools",
27
+ programIds: [
28
+ "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc", // Orca Whirlpool
29
+ "9W959DqEETiGZocYWCQPaJ6sBmUzgfxXfqGeTEdp3aQP", // Orca V1
30
+ ],
31
+ },
32
+ nft: {
33
+ name: "NFT / Metaplex",
34
+ description: "NFT mints, transfers, and metadata via Metaplex",
35
+ programIds: [
36
+ "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s", // Token Metadata
37
+ "cndy3Z4yapfJBmL3ShUp5exZKqR3z33thTzeNMm2gRZ", // Candy Machine V3
38
+ "CndyV3LdqHUfDLmd1X2Rxm9e6CFBe8F6Qkx6kWX6YMEZ", // Candy Machine V2
39
+ "hausS13jsjafwWwGqZTUQRmWyvyxn9EQpqMwV1PBBmk", // Auction House
40
+ ],
41
+ },
42
+ pumpfun: {
43
+ name: "Pump.fun",
44
+ description: "Token launches and trades on Pump.fun",
45
+ programIds: [
46
+ "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P", // Pump.fun program
47
+ ],
48
+ },
49
+ openbook: {
50
+ name: "OpenBook",
51
+ description: "Order book trading on OpenBook (formerly Serum)",
52
+ programIds: [
53
+ "srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX", // OpenBook V1
54
+ "opnb2LAfJYbRMAHHvqjCwQxanZn7n734bNfWLcQnB8c", // OpenBook V2
55
+ ],
56
+ },
57
+ system: {
58
+ name: "System Program",
59
+ description: "SOL transfers and basic account operations",
60
+ programIds: [
61
+ "11111111111111111111111111111111", // System Program
62
+ ],
63
+ },
64
+ token: {
65
+ name: "Token Program",
66
+ description: "SPL token transfers and token account operations",
67
+ programIds: [
68
+ "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", // Token Program
69
+ "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb", // Token 2022
70
+ "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJe1bj", // Associated Token Program
71
+ ],
72
+ },
73
+ };
74
+ function getProtocolProgramIds(protocol) {
75
+ return exports.PROTOCOLS[protocol].programIds;
76
+ }
77
+ function detectProtocol(programIds) {
78
+ const idSet = new Set(programIds);
79
+ for (const [protocol, info] of Object.entries(exports.PROTOCOLS)) {
80
+ if (info.programIds.some((id) => idSet.has(id))) {
81
+ return protocol;
82
+ }
83
+ }
84
+ return null;
85
+ }
86
+ //# sourceMappingURL=protocols.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocols.js","sourceRoot":"","sources":["../src/protocols.ts"],"names":[],"mappings":";;;AA4FA,sDAEC;AAED,wCAUC;AA1FY,QAAA,SAAS,GAAmC;IACvD,OAAO,EAAE;QACP,IAAI,EAAE,oBAAoB;QAC1B,WAAW,EAAE,4BAA4B;QACzC,UAAU,EAAE;YACV,6CAA6C,EAAE,aAAa;YAC5D,6CAA6C,EAAG,aAAa;SAC9D;KACF;IAED,OAAO,EAAE;QACP,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,2CAA2C;QACxD,UAAU,EAAE;YACV,8CAA8C,EAAE,iBAAiB;YACjE,8CAA8C,EAAE,eAAe;YAC/D,8CAA8C,EAAE,iBAAiB;SAClE;KACF;IAED,IAAI,EAAE;QACJ,IAAI,EAAE,iBAAiB;QACvB,WAAW,EAAE,4CAA4C;QACzD,UAAU,EAAE;YACV,6CAA6C,EAAG,iBAAiB;YACjE,8CAA8C,EAAE,UAAU;SAC3D;KACF;IAED,GAAG,EAAE;QACH,IAAI,EAAE,gBAAgB;QACtB,WAAW,EAAE,iDAAiD;QAC9D,UAAU,EAAE;YACV,6CAA6C,EAAG,iBAAiB;YACjE,6CAA6C,EAAG,mBAAmB;YACnE,8CAA8C,EAAE,mBAAmB;YACnE,6CAA6C,EAAG,gBAAgB;SACjE;KACF;IAED,OAAO,EAAE;QACP,IAAI,EAAE,UAAU;QAChB,WAAW,EAAE,uCAAuC;QACpD,UAAU,EAAE;YACV,6CAA6C,EAAG,mBAAmB;SACpE;KACF;IAED,QAAQ,EAAE;QACR,IAAI,EAAE,UAAU;QAChB,WAAW,EAAE,iDAAiD;QAC9D,UAAU,EAAE;YACV,6CAA6C,EAAG,cAAc;YAC9D,6CAA6C,EAAG,cAAc;SAC/D;KACF;IAED,MAAM,EAAE;QACN,IAAI,EAAE,gBAAgB;QACtB,WAAW,EAAE,4CAA4C;QACzD,UAAU,EAAE;YACV,kCAAkC,EAAgB,iBAAiB;SACpE;KACF;IAED,KAAK,EAAE;QACL,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,kDAAkD;QAC/D,UAAU,EAAE;YACV,6CAA6C,EAAG,gBAAgB;YAChE,6CAA6C,EAAG,aAAa;YAC7D,6CAA6C,EAAG,2BAA2B;SAC5E;KACF;CACF,CAAC;AAEF,SAAgB,qBAAqB,CAAC,QAAkB;IACtD,OAAO,iBAAS,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC;AACxC,CAAC;AAED,SAAgB,cAAc,CAAC,UAAoB;IACjD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;IAElC,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,iBAAS,CAA+B,EAAE,CAAC;QACvF,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YAChD,OAAO,QAAQ,CAAC;QAClB,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,3 @@
1
+ declare const app: import("express-serve-static-core").Express;
2
+ export default app;
3
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAcA,QAAA,MAAM,GAAG,6CAAY,CAAC;AAiDtB,eAAe,GAAG,CAAC"}
package/dist/server.js ADDED
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const express_1 = __importDefault(require("express"));
7
+ const dotenv_1 = __importDefault(require("dotenv"));
8
+ const index_1 = require("./index");
9
+ const config_1 = require("./config");
10
+ dotenv_1.default.config();
11
+ // Initialise SDK from environment
12
+ (0, index_1.init)({
13
+ cacheDurationMs: process.env.CACHE_DURATION_MS
14
+ ? Number(process.env.CACHE_DURATION_MS)
15
+ : undefined,
16
+ });
17
+ const app = (0, express_1.default)();
18
+ app.use(express_1.default.json());
19
+ // ─── GET /health ──────────────────────────────────────────────────────────────
20
+ app.get("/health", (_req, res) => {
21
+ res.json({ status: "ok", rpcUrl: (0, config_1.getConfig)().rpcUrl });
22
+ });
23
+ // ─── GET /estimate-fee ────────────────────────────────────────────────────────
24
+ app.get("/estimate-fee", async (req, res, next) => {
25
+ try {
26
+ const { speed, strategy, includeStats, maxFee } = req.query;
27
+ const result = await (0, index_1.estimateFee)({
28
+ speed: speed ?? "medium",
29
+ strategy: strategy ?? "balanced",
30
+ includeStats: includeStats === "true",
31
+ maxFee: maxFee ? Number(maxFee) : undefined,
32
+ });
33
+ res.json(result);
34
+ }
35
+ catch (err) {
36
+ next(err);
37
+ }
38
+ });
39
+ // ─── GET /stats ───────────────────────────────────────────────────────────────
40
+ // Returns a comprehensive snapshot with stats
41
+ app.get("/stats", async (_req, res, next) => {
42
+ try {
43
+ const result = await (0, index_1.estimateFee)({ speed: "medium", includeStats: true });
44
+ res.json(result);
45
+ }
46
+ catch (err) {
47
+ next(err);
48
+ }
49
+ });
50
+ // ─── Error handler ────────────────────────────────────────────────────────────
51
+ app.use((err, _req, res, _next) => {
52
+ console.error("[FEMA server error]", err.message);
53
+ res.status(500).json({ error: err.message });
54
+ });
55
+ const PORT = Number(process.env.PORT ?? 3000);
56
+ app.listen(PORT, () => {
57
+ console.log(`[FEMA] Server running on http://localhost:${PORT}`);
58
+ console.log(`[FEMA] RPC endpoint: ${(0, config_1.getConfig)().rpcUrl}`);
59
+ });
60
+ exports.default = app;
61
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { FeeSnapshot, FeeEntry } from "../types";
2
+ export declare function getCached(): {
3
+ snapshot: FeeSnapshot;
4
+ entries: FeeEntry[];
5
+ } | null;
6
+ export declare function setCache(snapshot: FeeSnapshot, entries: FeeEntry[]): void;
7
+ export declare function clearCache(): void;
8
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/services/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAWjD,wBAAgB,SAAS,IAAI;IAAE,QAAQ,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,QAAQ,EAAE,CAAA;CAAE,GAAG,IAAI,CAKjF;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,IAAI,CAOzE;AAED,wBAAgB,UAAU,IAAI,IAAI,CAEjC"}
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCached = getCached;
4
+ exports.setCache = setCache;
5
+ exports.clearCache = clearCache;
6
+ const config_1 = require("../config");
7
+ let _entry = null;
8
+ function getCached() {
9
+ if (_entry && Date.now() < _entry.expiresAt) {
10
+ return { snapshot: _entry.snapshot, entries: _entry.entries };
11
+ }
12
+ return null;
13
+ }
14
+ function setCache(snapshot, entries) {
15
+ const { cacheDurationMs } = (0, config_1.getConfig)();
16
+ _entry = {
17
+ snapshot,
18
+ entries,
19
+ expiresAt: Date.now() + cacheDurationMs,
20
+ };
21
+ }
22
+ function clearCache() {
23
+ _entry = null;
24
+ }
25
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/services/cache.ts"],"names":[],"mappings":";;AAWA,8BAKC;AAED,4BAOC;AAED,gCAEC;AA5BD,sCAAsC;AAQtC,IAAI,MAAM,GAAsB,IAAI,CAAC;AAErC,SAAgB,SAAS;IACvB,IAAI,MAAM,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;QAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;IAChE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAgB,QAAQ,CAAC,QAAqB,EAAE,OAAmB;IACjE,MAAM,EAAE,eAAe,EAAE,GAAG,IAAA,kBAAS,GAAE,CAAC;IACxC,MAAM,GAAG;QACP,QAAQ;QACR,OAAO;QACP,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,eAAe;KACxC,CAAC;AACJ,CAAC;AAED,SAAgB,UAAU;IACxB,MAAM,GAAG,IAAI,CAAC;AAChB,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { FeeSnapshot } from "../types";
2
+ export declare function setLatestSnapshot(s: FeeSnapshot): void;
3
+ export declare function getLatestSnapshotSync(): FeeSnapshot | null;
4
+ export declare function startPersistedInterval(getSnapshot: () => FeeSnapshot | null, intervalMs?: number): void;
5
+ export declare function stopPersistedInterval(): void;
6
+ //# sourceMappingURL=database.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/services/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAKvC,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,WAAW,GAAG,IAAI,CAEtD;AAED,wBAAgB,qBAAqB,IAAI,WAAW,GAAG,IAAI,CAE1D;AAED,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,WAAW,GAAG,IAAI,EACrC,UAAU,SAAS,GAClB,IAAI,CAON;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAK5C"}
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setLatestSnapshot = setLatestSnapshot;
4
+ exports.getLatestSnapshotSync = getLatestSnapshotSync;
5
+ exports.startPersistedInterval = startPersistedInterval;
6
+ exports.stopPersistedInterval = stopPersistedInterval;
7
+ let _latestSnapshot = null;
8
+ let _persistInterval = null;
9
+ function setLatestSnapshot(s) {
10
+ _latestSnapshot = s;
11
+ }
12
+ function getLatestSnapshotSync() {
13
+ return _latestSnapshot;
14
+ }
15
+ function startPersistedInterval(getSnapshot, intervalMs = 15000) {
16
+ if (_persistInterval)
17
+ return;
18
+ _persistInterval = setInterval(() => {
19
+ const snapshot = getSnapshot();
20
+ if (snapshot)
21
+ setLatestSnapshot(snapshot);
22
+ }, intervalMs);
23
+ }
24
+ function stopPersistedInterval() {
25
+ if (_persistInterval) {
26
+ clearInterval(_persistInterval);
27
+ _persistInterval = null;
28
+ }
29
+ }
30
+ //# sourceMappingURL=database.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/services/database.ts"],"names":[],"mappings":";;AAKA,8CAEC;AAED,sDAEC;AAED,wDAUC;AAED,sDAKC;AA5BD,IAAI,eAAe,GAAuB,IAAI,CAAC;AAC/C,IAAI,gBAAgB,GAA0C,IAAI,CAAC;AAEnE,SAAgB,iBAAiB,CAAC,CAAc;IAC9C,eAAe,GAAG,CAAC,CAAC;AACtB,CAAC;AAED,SAAgB,qBAAqB;IACnC,OAAO,eAAe,CAAC;AACzB,CAAC;AAED,SAAgB,sBAAsB,CACpC,WAAqC,EACrC,UAAU,GAAG,KAAM;IAEnB,IAAI,gBAAgB;QAAE,OAAO;IAE7B,gBAAgB,GAAG,WAAW,CAAC,GAAG,EAAE;QAClC,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;QAC/B,IAAI,QAAQ;YAAE,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC,EAAE,UAAU,CAAC,CAAC;AACjB,CAAC;AAED,SAAgB,qBAAqB;IACnC,IAAI,gBAAgB,EAAE,CAAC;QACrB,aAAa,CAAC,gBAAgB,CAAC,CAAC;QAChC,gBAAgB,GAAG,IAAI,CAAC;IAC1B,CAAC;AACH,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { Transaction, VersionedTransaction } from "@solana/web3.js";
2
+ import { FeeEntry } from "../types";
3
+ export declare function resetConnection(): void;
4
+ /**
5
+ * Fetch fee entries from recent blocks.
6
+ *
7
+ * - needsProgramData = false (no protocol/transaction passed):
8
+ * Uses getRecentPrioritizationFees — fast, no program info needed.
9
+ *
10
+ * - needsProgramData = true (protocol or transaction passed):
11
+ * Uses full block scan so each entry carries program IDs for accurate filtering.
12
+ */
13
+ export declare function fetchRecentPriorityFees(blockCount?: number, needsProgramData?: boolean): Promise<FeeEntry[]>;
14
+ /**
15
+ * Extract program IDs from a user-supplied Transaction or VersionedTransaction.
16
+ * This is what we use to filter the fee dataset to relevant transactions.
17
+ */
18
+ export declare function extractProgramIds(tx: Transaction | VersionedTransaction): string[];
19
+ /**
20
+ * Estimate the compute units a transaction is likely to consume.
21
+ * Parses ComputeBudgetProgram instructions if present; otherwise returns a default.
22
+ */
23
+ export declare function estimateComputeUnits(tx: Transaction | VersionedTransaction): number;
24
+ //# sourceMappingURL=solana.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solana.d.ts","sourceRoot":"","sources":["../../src/services/solana.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,WAAW,EACX,oBAAoB,EAGrB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAWpC,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAED;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,UAAU,GAAE,MAAW,EACvB,gBAAgB,GAAE,OAAe,GAChC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAqBrB;AAsGD;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,WAAW,GAAG,oBAAoB,GACrC,MAAM,EAAE,CAmBV;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,WAAW,GAAG,oBAAoB,GACrC,MAAM,CAgCR"}
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resetConnection = resetConnection;
4
+ exports.fetchRecentPriorityFees = fetchRecentPriorityFees;
5
+ exports.extractProgramIds = extractProgramIds;
6
+ exports.estimateComputeUnits = estimateComputeUnits;
7
+ const web3_js_1 = require("@solana/web3.js");
8
+ const config_1 = require("../config");
9
+ let _connection = null;
10
+ function getConnection() {
11
+ if (!_connection) {
12
+ _connection = new web3_js_1.Connection((0, config_1.getConfig)().rpcUrl, "confirmed");
13
+ }
14
+ return _connection;
15
+ }
16
+ function resetConnection() {
17
+ _connection = null;
18
+ }
19
+ /**
20
+ * Fetch fee entries from recent blocks.
21
+ *
22
+ * - needsProgramData = false (no protocol/transaction passed):
23
+ * Uses getRecentPrioritizationFees — fast, no program info needed.
24
+ *
25
+ * - needsProgramData = true (protocol or transaction passed):
26
+ * Uses full block scan so each entry carries program IDs for accurate filtering.
27
+ */
28
+ async function fetchRecentPriorityFees(blockCount = 30, needsProgramData = false) {
29
+ const connection = getConnection();
30
+ if (!needsProgramData) {
31
+ // Fast path — just need general fee distribution
32
+ try {
33
+ const recentFees = await connection.getRecentPrioritizationFees();
34
+ if (recentFees.length > 0) {
35
+ const entries = recentFees
36
+ .slice(0, blockCount)
37
+ .filter((e) => e.prioritizationFee > 0)
38
+ .map((e) => ({ fee: e.prioritizationFee, programs: [] }));
39
+ if (entries.length >= 10)
40
+ return entries;
41
+ }
42
+ }
43
+ catch {
44
+ // fall through to block scan
45
+ }
46
+ }
47
+ // Program-aware path — full block scan with program IDs per transaction
48
+ return scanBlocks(connection, blockCount);
49
+ }
50
+ async function scanBlocks(connection, blockCount) {
51
+ const slot = await connection.getSlot();
52
+ const targetSlots = [];
53
+ for (let i = 0; i < blockCount; i++) {
54
+ targetSlots.push(slot - i);
55
+ }
56
+ const entries = [];
57
+ await Promise.all(targetSlots.map(async (s) => {
58
+ try {
59
+ const block = await connection.getBlock(s, {
60
+ maxSupportedTransactionVersion: 0,
61
+ rewards: false,
62
+ transactionDetails: "full",
63
+ });
64
+ if (!block?.transactions)
65
+ return;
66
+ for (const tx of block.transactions) {
67
+ const meta = tx.meta;
68
+ if (!meta)
69
+ continue;
70
+ const totalFeeLamports = meta.fee ?? 0;
71
+ const cuConsumed = meta.computeUnitsConsumed ?? 0;
72
+ const sigCount = "signatures" in tx.transaction
73
+ ? tx.transaction.signatures.length
74
+ : 1;
75
+ const baseFee = 5000 * sigCount;
76
+ const priorityFeeLamports = totalFeeLamports - baseFee;
77
+ if (priorityFeeLamports <= 0 || cuConsumed <= 0)
78
+ continue;
79
+ const microLamportsPerCU = Math.round((priorityFeeLamports * 1000000) / cuConsumed);
80
+ if (microLamportsPerCU <= 0)
81
+ continue;
82
+ // Extract program IDs from the transaction's instructions
83
+ const programs = extractProgramIdsFromBlock(tx.transaction);
84
+ entries.push({ fee: microLamportsPerCU, programs });
85
+ }
86
+ }
87
+ catch {
88
+ // skip failed blocks silently
89
+ }
90
+ }));
91
+ return entries;
92
+ }
93
+ /** Pull program IDs out of a raw block transaction (legacy or versioned). */
94
+ function extractProgramIdsFromBlock(tx) {
95
+ try {
96
+ const t = tx;
97
+ const msg = t.message;
98
+ if (!msg)
99
+ return [];
100
+ // Account key list (legacy)
101
+ const keys = (msg.accountKeys ?? msg.staticAccountKeys ?? []).map((k) => (typeof k.toBase58 === "function"
102
+ ? k.toBase58()
103
+ : String(k)));
104
+ const ixs = msg.instructions ?? msg.compiledInstructions ?? [];
105
+ const programIds = new Set();
106
+ for (const ix of ixs) {
107
+ const id = keys[ix.programIdIndex];
108
+ if (id)
109
+ programIds.add(id);
110
+ }
111
+ return Array.from(programIds);
112
+ }
113
+ catch {
114
+ return [];
115
+ }
116
+ }
117
+ /**
118
+ * Extract program IDs from a user-supplied Transaction or VersionedTransaction.
119
+ * This is what we use to filter the fee dataset to relevant transactions.
120
+ */
121
+ function extractProgramIds(tx) {
122
+ try {
123
+ if (tx instanceof web3_js_1.Transaction) {
124
+ return [
125
+ ...new Set(tx.instructions.map((ix) => ix.programId.toBase58())),
126
+ ];
127
+ }
128
+ // VersionedTransaction
129
+ const msg = tx.message;
130
+ const keys = msg.staticAccountKeys.map((k) => k.toBase58());
131
+ return [
132
+ ...new Set(msg.compiledInstructions.map((ix) => keys[ix.programIdIndex])),
133
+ ];
134
+ }
135
+ catch {
136
+ return [];
137
+ }
138
+ }
139
+ /**
140
+ * Estimate the compute units a transaction is likely to consume.
141
+ * Parses ComputeBudgetProgram instructions if present; otherwise returns a default.
142
+ */
143
+ function estimateComputeUnits(tx) {
144
+ const DEFAULT_CU = 200000;
145
+ try {
146
+ const instructions = tx instanceof web3_js_1.Transaction
147
+ ? tx.instructions
148
+ : tx.message.compiledInstructions;
149
+ const COMPUTE_BUDGET_PROGRAM_ID = web3_js_1.ComputeBudgetProgram.programId;
150
+ for (const ix of instructions) {
151
+ const programId = "programId" in ix
152
+ ? ix.programId
153
+ : null;
154
+ if (programId && programId.equals(COMPUTE_BUDGET_PROGRAM_ID)) {
155
+ const data = "data" in ix ? ix.data : new Uint8Array();
156
+ // Instruction type 2 = SetComputeUnitLimit
157
+ if (data[0] === 2 && data.length >= 5) {
158
+ return new DataView(data.buffer, data.byteOffset).getUint32(1, true);
159
+ }
160
+ }
161
+ }
162
+ }
163
+ catch {
164
+ // ignore parse errors
165
+ }
166
+ return DEFAULT_CU;
167
+ }
168
+ //# sourceMappingURL=solana.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solana.js","sourceRoot":"","sources":["../../src/services/solana.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import { Transaction, VersionedTransaction } from "@solana/web3.js";
2
+ import { Protocol } from "./protocols";
3
+ export type SolanaCluster = "mainnet-beta" | "devnet";
4
+ export interface FemaConfig {
5
+ rpcUrl: string;
6
+ cluster: SolanaCluster;
7
+ cacheDurationMs: number;
8
+ }
9
+ export type Speed = "slow" | "medium" | "fast";
10
+ export type Strategy = "cheap" | "balanced" | "aggressive";
11
+ export type CongestionLevel = "low" | "medium" | "high";
12
+ export interface EstimateFeeOptions {
13
+ speed?: Speed;
14
+ strategy?: Strategy;
15
+ includeStats?: boolean;
16
+ maxFee?: number;
17
+ transaction?: Transaction | VersionedTransaction;
18
+ protocol?: Protocol;
19
+ }
20
+ export interface FeeDistribution {
21
+ p10: number;
22
+ p25: number;
23
+ p50: number;
24
+ p75: number;
25
+ p90: number;
26
+ p95: number;
27
+ p99: number;
28
+ }
29
+ export interface FeeStats {
30
+ avgFee: number;
31
+ medianFee: number;
32
+ distribution: FeeDistribution;
33
+ }
34
+ export interface EstimateFeeResult {
35
+ fee: number;
36
+ congestion: CongestionLevel;
37
+ percentileUsed: number;
38
+ sampleSize: number;
39
+ programFiltered: boolean;
40
+ stats?: FeeStats;
41
+ }
42
+ export interface FeeEntry {
43
+ fee: number;
44
+ programs: string[];
45
+ }
46
+ export interface FeeSnapshot {
47
+ timestamp: string;
48
+ avgFee: number;
49
+ medianFee: number;
50
+ p25Fee: number;
51
+ p75Fee: number;
52
+ congestionLevel: CongestionLevel;
53
+ txCount: number;
54
+ }
55
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAIvC,MAAM,MAAM,aAAa,GAAG,cAAc,GAAG,QAAQ,CAAC;AAEtD,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,aAAa,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;CACzB;AAID,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;AAC/C,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,YAAY,CAAC;AAC3D,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAExD,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,WAAW,GAAG,oBAAoB,CAAC;IACjD,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,eAAe,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,eAAe,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;IACzB,KAAK,CAAC,EAAE,QAAQ,CAAC;CAClB;AAID,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAID,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,eAAe,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;CACjB"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "fema-pf-calc",
3
+ "version": "1.0.0",
4
+ "description": "Intelligent Solana priority fee estimation engine",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "require": "./dist/index.js",
10
+ "types": "./dist/index.d.ts"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "README.md"
16
+ ],
17
+ "engines": {
18
+ "node": ">=16"
19
+ },
20
+ "scripts": {
21
+ "build": "tsc",
22
+ "prepublishOnly": "npm run build",
23
+ "dev": "ts-node test-fees.ts",
24
+ "server": "ts-node src/server.ts",
25
+ "start": "node dist/server.js",
26
+ "lint": "eslint src/**/*.ts"
27
+ },
28
+ "keywords": [
29
+ "solana",
30
+ "priority-fee",
31
+ "web3",
32
+ "blockchain"
33
+ ],
34
+ "license": "MIT",
35
+ "peerDependencies": {
36
+ "@solana/web3.js": "^1.x"
37
+ },
38
+ "devDependencies": {
39
+ "@solana/web3.js": "^1.98.0",
40
+ "@types/express": "^5.0.1",
41
+ "@types/node": "^22.15.2",
42
+ "dotenv": "^16.5.0",
43
+ "express": "^4.21.2",
44
+ "ts-node": "^10.9.2",
45
+ "typescript": "^5.8.3"
46
+ }
47
+ }