Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/routes/feeEstimate.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ router.get("/", async (req, res, next) => {

// Cache miss or fresh=true - fetch from Horizon
const feeStats = await server.feeStats();
const ledgerHistory = await server.ledgers().order("desc").limit(5).call();
const ledgerHistoryRecords = ledgerHistory.records || [];

const base = parseInt(feeStats.fee_charged.p10);
const recommended = parseInt(feeStats.fee_charged.p50);
const priority = parseInt(feeStats.fee_charged.p95);

Expand Down Expand Up @@ -82,6 +83,13 @@ router.get("/", async (req, res, next) => {
p95: feeStats.fee_charged.p95,
p99: feeStats.fee_charged.p99,
},
history: ledgerHistoryRecords.map((ledger) => ({
ledger: parseInt(ledger.sequence, 10),
baseFee: parseInt(ledger.base_fee_in_stroops || ledger.base_fee, 10) || 0,
capacityUsage: parseFloat(
Math.min((ledger.successful_transaction_count || 0) / 1000, 1.0).toFixed(4)
),
})),
// New fields
context: "Stroops are the smallest unit of XLM; 1 XLM = 10,000,000 stroops.",
networkCongestion: (function () {
Expand Down
8 changes: 4 additions & 4 deletions tests/feeEstimate.surgeStatus.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const request = require("supertest");
const app = require("../src/index");

jest.mock("../src/config/stellar", () => {
const originalModule = jest.requireActual("../src/config/stellar");
Expand All @@ -12,14 +11,15 @@ jest.mock("../src/config/stellar", () => {
};
});

const app = require("../src/index");
const { server } = require("../src/config/stellar");
const { feeEstimateCache } = require("../src/utils/cache");
const cache = require("../src/services/cache");

describe("Fee Surge Status API", () => {
beforeEach(() => {
jest.clearAllMocks();
// Clear the cache
feeEstimateCache.clear();
// Clear the actual route cache
cache.flush();
});

it("returns isSurging: false when average capacity usage is low", async () => {
Expand Down
66 changes: 63 additions & 3 deletions tests/feeEstimate.test.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,81 @@
const request = require('supertest');
const app = require('../src/index');
const { feeEstimateCache } = require('../src/utils/cache');

let app;
let server;

describe('GET /fee-estimate', () => {
beforeEach(() => {
jest.resetModules();
jest.doMock('../src/config/stellar', () => {
const originalModule = jest.requireActual('../src/config/stellar');
return {
...originalModule,
server: {
ledgers: jest.fn(),
feeStats: jest.fn(),
},
};
});

({ server } = require('../src/config/stellar'));
app = require('../src/index');
feeEstimateCache.clear();
});

it('includes new fields in the response', async () => {
jest.spyOn(server, 'feeStats').mockResolvedValue({
fee_charged: {
min: '100',
p10: '110',
p50: '120',
p95: '140',
p99: '150',
max: '160',
},
last_ledger_base_fee: '120',
ledger_capacity_usage: '0.12',
});

jest.spyOn(server, 'ledgers').mockReturnValue({
order: jest.fn().mockReturnThis(),
limit: jest.fn().mockReturnThis(),
call: jest.fn().mockResolvedValue({
records: [
{ sequence: '500', base_fee_in_stroops: '100', successful_transaction_count: 100 },
{ sequence: '499', base_fee_in_stroops: '110', successful_transaction_count: 200 },
{ sequence: '498', base_fee_in_stroops: '120', successful_transaction_count: 300 },
{ sequence: '497', base_fee_in_stroops: '130', successful_transaction_count: 400 },
{ sequence: '496', base_fee_in_stroops: '140', successful_transaction_count: 500 },
],
}),
});

const res = await request(app).get('/fee-estimate?operations=2');
expect(res.statusCode).toBe(200);
expect(res.body.success).toBe(true);
const data = res.body.data;
// Existing fields

expect(data).toHaveProperty('operationCount');
expect(data).toHaveProperty('perOperation');
// New fields
expect(data).toHaveProperty('context');
expect(typeof data.context).toBe('string');
expect(data).toHaveProperty('networkCongestion');
expect(['low', 'medium', 'high']).toContain(data.networkCongestion);
expect(data).toHaveProperty('recommendation');
expect(typeof data.recommendation).toBe('string');
expect(data).toHaveProperty('history');
expect(Array.isArray(data.history)).toBe(true);
expect(data.history).toHaveLength(5);
expect(data.history[0]).toEqual({
ledger: 500,
baseFee: 100,
capacityUsage: 0.1,
});
expect(data.history[4]).toEqual({
ledger: 496,
baseFee: 140,
capacityUsage: 0.5,
});
});
});
5 changes: 5 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,11 @@ export interface FeeEstimateResponse {
p95: string
p99: string
}
history: Array<{
ledger: number
baseFee: number
capacityUsage: number
}>
// Human-friendly additions
context: string
networkCongestion: 'low' | 'medium' | 'high'
Expand Down
Loading