UNPKG

@vechain.energy/gas

Version:

calculate estimated gas usage for transactions

217 lines (216 loc) 10.6 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const getNodeMock = jest.fn(); const postNodeMock = jest.fn(); const bentMock = jest.fn().mockImplementation((url, method) => { if (method === 'GET') { return getNodeMock; } return postNodeMock; }); jest.mock('bent', () => bentMock, { virtual: true }); const bignumber_js_1 = __importDefault(require("bignumber.js")); const feeMarket_1 = __importDefault(require("./feeMarket")); describe('feeMarket', () => { beforeEach(() => { jest.clearAllMocks(); }); describe('with dynamic fee calculation', () => { it('returns a BigNumber', () => __awaiter(void 0, void 0, void 0, function* () { // Mock successful base fee response getNodeMock.mockResolvedValueOnce({ baseFeePerGas: '0x2540be400' // 10 gwei in hex }); // Mock successful priority fee response getNodeMock.mockResolvedValueOnce({ maxPriorityFeePerGas: '0x3b9aca00' // 1 gwei in hex }); const fee = yield (0, feeMarket_1.default)('https://node.vechain.energy'); expect(fee).toBeInstanceOf(bignumber_js_1.default); })); it('calculates total fee as base fee + priority fee', () => __awaiter(void 0, void 0, void 0, function* () { // Mock base fee: 10 gwei getNodeMock.mockResolvedValueOnce({ baseFeePerGas: '0x2540be400' }); // Mock priority fee response (will be used for optimal calculation) getNodeMock.mockResolvedValueOnce({ maxPriorityFeePerGas: '0x3b9aca00' // 1 gwei }); const fee = yield (0, feeMarket_1.default)('https://node.vechain.energy'); // Base fee: 10 gwei = 10000000000 wei // Optimal priority fee: 4.6% of 10 gwei = 0.46 gwei = 460000000 wei // Total: 10000000000 + 460000000 = 10460000000 wei expect(fee.toString()).toEqual('10460000000'); })); it('uses custom priority fee when provided', () => __awaiter(void 0, void 0, void 0, function* () { // Mock base fee: 10 gwei getNodeMock.mockResolvedValueOnce({ baseFeePerGas: '0x2540be400' }); const fee = yield (0, feeMarket_1.default)('https://node.vechain.energy', { maxPriorityFeePerGas: '2000000000' // 2 gwei }); // Expected: 10 + 2 = 12 gwei = 12000000000 wei expect(fee.toString()).toEqual('12000000000'); })); it('applies maxFeePerGas cap when provided', () => __awaiter(void 0, void 0, void 0, function* () { // Mock base fee: 10 gwei getNodeMock.mockResolvedValueOnce({ baseFeePerGas: '0x2540be400' }); // Mock priority fee: 1 gwei getNodeMock.mockResolvedValueOnce({ maxPriorityFeePerGas: '0x3b9aca00' }); const fee = yield (0, feeMarket_1.default)('https://node.vechain.energy', { maxFeePerGas: '8000000000' // 8 gwei cap }); // Expected: min(10 + 1, 8) = 8 gwei = 8000000000 wei expect(fee.toString()).toEqual('8000000000'); })); it('falls back to legacy base gas price when baseFeePerGas not available', () => __awaiter(void 0, void 0, void 0, function* () { // Mock block response without baseFeePerGas getNodeMock.mockResolvedValueOnce({ // No baseFeePerGas field }); // Mock legacy base gas price response postNodeMock.mockResolvedValueOnce([ { data: '0x000000000000000000000000000000000000000000000000000009184e72a000', // 10 gwei events: [], transfers: [], gasUsed: 591, reverted: false, vmError: '' } ]); // Mock priority fee response getNodeMock.mockResolvedValueOnce({ maxPriorityFeePerGas: '0x3b9aca00' // 1 gwei }); const fee = yield (0, feeMarket_1.default)('https://node.vechain.energy'); // Legacy base price: 0x000000000000000000000000000000000000000000000000000009184e72a000 // = 10000000000000 (10 gwei) // Priority fee: 0x3b9aca00 = 1000000000 (1 gwei) // Total: 10000000000000 + 1000000000 = 10001000000000 expect(fee.toString()).toEqual('10001000000000'); // Verify legacy call was made expect(postNodeMock).toHaveBeenCalledWith('/accounts/*', { clauses: [{ to: '0x0000000000000000000000000000506172616d73', data: '0x8eaa6ac0000000000000000000000000000000000000626173652d6761732d7072696365', value: '0' }] }); })); it('calculates optimal priority fee using fee history', () => __awaiter(void 0, void 0, void 0, function* () { // Mock base fee: 1000 gwei getNodeMock.mockResolvedValueOnce({ baseFeePerGas: '0xe8d4a51000' // 1000 gwei }); // Mock fee history with equal rewards getNodeMock.mockResolvedValueOnce({ oldestBlock: '0x1', baseFeePerGas: ['0x1', '0x2', '0x3'], gasUsedRatio: ['0.5', '0.6', '0.7'], reward: [ ['0x20', '0x20', '0x20'] // Equal rewards: 32 wei each ] }); const fee = yield (0, feeMarket_1.default)('https://node.vechain.energy'); // 4.6% of 1000 gwei = 46 gwei // 75th percentile = 32 wei // Should use min(46, 32) = 32 wei // Total: 1000 + 0.000000032 = 1000.000000032 gwei expect(fee.toString()).toEqual('1000000000032'); })); it('calculates optimal priority fee using average of 75th percentiles', () => __awaiter(void 0, void 0, void 0, function* () { // Mock base fee: 1000 gwei getNodeMock.mockResolvedValueOnce({ baseFeePerGas: '0xe8d4a51000' // 1000 gwei }); // Mock fee history with varying rewards getNodeMock.mockResolvedValueOnce({ oldestBlock: '0x1', baseFeePerGas: ['0x1', '0x2'], gasUsedRatio: ['0.5', '0.6'], reward: [ ['0x10', '0x20', '0x30'], // Block 1: 75th percentile = 48 wei ['0x15', '0x25', '0x35'] // Block 2: 75th percentile = 53 wei ] }); const fee = yield (0, feeMarket_1.default)('https://node.vechain.energy'); // Average of 75th percentiles: (48 + 53) / 2 = 50.5 wei // 4.6% of 1000 gwei = 46 gwei // Should use min(46, 50.5) = 46 gwei // Total: 1000 + 0.000000046 = 1000.000000046 gwei expect(fee.toString()).toEqual('1000000000053'); })); it('falls back to suggested priority fee when fee history is empty', () => __awaiter(void 0, void 0, void 0, function* () { // Mock base fee: 1000 gwei getNodeMock.mockResolvedValueOnce({ baseFeePerGas: '0xe8d4a51000' // 1000 gwei }); // Mock empty fee history getNodeMock.mockResolvedValueOnce({ oldestBlock: '0x1', baseFeePerGas: [], gasUsedRatio: [], reward: [] }); // Mock suggested priority fee getNodeMock.mockResolvedValueOnce({ maxPriorityFeePerGas: '0x14' // 20 wei }); const fee = yield (0, feeMarket_1.default)('https://node.vechain.energy'); // 4.6% of 1000 gwei = 46 gwei // Suggested priority fee = 20 wei // Should use min(46, 20) = 20 wei // Total: 1000 + 0.000000020 = 1000.000000020 gwei expect(fee.toString()).toEqual('1000000000020'); })); it('handles network errors gracefully with fallbacks', () => __awaiter(void 0, void 0, void 0, function* () { // Mock base fee error getNodeMock.mockRejectedValueOnce(new Error('Network error')); // Mock legacy base gas price response postNodeMock.mockResolvedValueOnce([ { data: '0x000000000000000000000000000000000000000000000000000009184e72a000', // 10 gwei events: [], transfers: [], gasUsed: 591, reverted: false, vmError: '' } ]); // Mock priority fee error getNodeMock.mockRejectedValueOnce(new Error('Network error')); const fee = yield (0, feeMarket_1.default)('https://node.vechain.energy'); // Should use legacy base price + default priority fee (1 gwei) // Legacy base price: 10000000000000 (10 gwei) // Default priority fee: 1000000000 (1 gwei) // Total: 10000000000000 + 1000000000 = 10001000000000 expect(fee.toString()).toEqual('10001000000000'); })); }); describe('with Connex object', () => { it('returns zero for Connex objects', () => __awaiter(void 0, void 0, void 0, function* () { const mockConnex = {}; const fee = yield (0, feeMarket_1.default)(mockConnex); expect(fee.toString()).toEqual('0'); })); }); });