From ca38df485d036f0c72a019bab813814ff78d0521 Mon Sep 17 00:00:00 2001 From: Derek Brans Date: Mon, 10 Jun 2024 19:57:05 -0400 Subject: [PATCH 1/2] Revert "fix: use hardcoded Infura gas API urls (#4068)" This reverts commit 850461d323fc304baaffa94bfa5bee196761ddb2. merge conflicts: - determineGasFeeCalculations.ts - GasFeeController.ts - GasFeeController.test.ts --- packages/gas-fee-controller/package.json | 1 + .../src/GasFeeController.test.ts | 106 ++++++++------ .../src/GasFeeController.ts | 23 ++-- .../src/determineGasFeeCalculations.test.ts | 3 - .../src/determineGasFeeCalculations.ts | 13 +- .../gas-fee-controller/src/gas-util.test.ts | 130 ++++++------------ packages/gas-fee-controller/src/gas-util.ts | 45 ++---- yarn.lock | 1 + 8 files changed, 132 insertions(+), 190 deletions(-) diff --git a/packages/gas-fee-controller/package.json b/packages/gas-fee-controller/package.json index b81ed2bbacd..58476c211cd 100644 --- a/packages/gas-fee-controller/package.json +++ b/packages/gas-fee-controller/package.json @@ -60,6 +60,7 @@ "deepmerge": "^4.2.2", "jest": "^27.5.1", "jest-when": "^3.4.2", + "nock": "^13.3.1", "sinon": "^9.2.4", "ts-jest": "^27.1.4", "typedoc": "^0.24.8", diff --git a/packages/gas-fee-controller/src/GasFeeController.test.ts b/packages/gas-fee-controller/src/GasFeeController.test.ts index e1c0fa4cca3..68017e24f54 100644 --- a/packages/gas-fee-controller/src/GasFeeController.test.ts +++ b/packages/gas-fee-controller/src/GasFeeController.test.ts @@ -24,11 +24,7 @@ import { fetchEthGasPriceEstimate, calculateTimeEstimate, } from './gas-util'; -import { - GAS_API_BASE_URL, - GAS_ESTIMATE_TYPES, - GasFeeController, -} from './GasFeeController'; +import { GAS_ESTIMATE_TYPES, GasFeeController } from './GasFeeController'; import type { GasFeeState, GasFeeStateChange, @@ -222,19 +218,23 @@ describe('GasFeeController', () => { * GasFeeController. * @param options.getCurrentNetworkLegacyGasAPICompatibility - Sets * getCurrentNetworkLegacyGasAPICompatibility on the GasFeeController. + * @param options.legacyAPIEndpoint - Sets legacyAPIEndpoint on the GasFeeController. + * @param options.EIP1559APIEndpoint - Sets EIP1559APIEndpoint on the GasFeeController. * @param options.clientId - Sets clientId on the GasFeeController. * @param options.networkControllerState - State object to initialize * NetworkController with. * @param options.interval - The polling interval. * @param options.state - The initial GasFeeController state - * @param options.infuraAPIKey - The Infura API key. + * @param options.initializeNetworkProvider - Whether to instruct the + * NetworkController to initialize its provider. */ async function setupGasFeeController({ getIsEIP1559Compatible = jest.fn().mockResolvedValue(true), getCurrentNetworkLegacyGasAPICompatibility = jest .fn() .mockReturnValue(false), - infuraAPIKey = 'INFURA_API_KEY', + legacyAPIEndpoint = 'http://legacy.endpoint/', + EIP1559APIEndpoint = 'http://eip-1559.endpoint/', clientId, getChainId, onNetworkDidChange, @@ -246,11 +246,14 @@ describe('GasFeeController', () => { onNetworkDidChange?: jest.Mock; getIsEIP1559Compatible?: jest.Mock>; getCurrentNetworkLegacyGasAPICompatibility?: jest.Mock; + legacyAPIEndpoint?: string; + // eslint-disable-next-line @typescript-eslint/naming-convention + EIP1559APIEndpoint?: string; clientId?: string; networkControllerState?: Partial; state?: GasFeeState; interval?: number; - infuraAPIKey?: string; + initializeNetworkProvider?: boolean; } = {}) { const controllerMessenger = getControllerMessenger(); networkController = await setupNetworkController({ @@ -266,10 +269,11 @@ describe('GasFeeController', () => { messenger, getCurrentNetworkLegacyGasAPICompatibility, getCurrentNetworkEIP1559Compatibility: getIsEIP1559Compatible, // change this for networkDetails.state.networkDetails.isEIP1559Compatible ??? + legacyAPIEndpoint, + EIP1559APIEndpoint, state, clientId, interval, - infuraAPIKey, }); } @@ -322,6 +326,8 @@ describe('GasFeeController', () => { getCurrentNetworkLegacyGasAPICompatibility: jest .fn() .mockReturnValue(true), + legacyAPIEndpoint: 'https://some-legacy-endpoint/', + EIP1559APIEndpoint: 'https://some-eip-1559-endpoint/', networkControllerState: { providerConfig: { type: NetworkType.rpc, @@ -339,14 +345,14 @@ describe('GasFeeController', () => { isEIP1559Compatible: false, isLegacyGasAPICompatible: true, fetchGasEstimates, - fetchGasEstimatesUrl: `${GAS_API_BASE_URL}/networks/1337/suggestedGasFees`, + fetchGasEstimatesUrl: 'https://some-eip-1559-endpoint/1337', fetchLegacyGasPriceEstimates, - fetchLegacyGasPriceEstimatesUrl: `${GAS_API_BASE_URL}/networks/1337/gasPrices`, + fetchLegacyGasPriceEstimatesUrl: + 'https://some-legacy-endpoint/1337', fetchEthGasPriceEstimate, calculateTimeEstimate, clientId: '99999', ethQuery: expect.any(EthQuery), - infuraAPIKey: expect.any(String), nonRPCGasFeeApisDisabled: false, }); }); @@ -376,6 +382,8 @@ describe('GasFeeController', () => { getCurrentNetworkLegacyGasAPICompatibility: jest .fn() .mockReturnValue(true), + legacyAPIEndpoint: 'https://some-legacy-endpoint/', + EIP1559APIEndpoint: 'https://some-eip-1559-endpoint/', networkControllerState: { providerConfig: { type: NetworkType.rpc, @@ -395,14 +403,14 @@ describe('GasFeeController', () => { isEIP1559Compatible: false, isLegacyGasAPICompatible: true, fetchGasEstimates, - fetchGasEstimatesUrl: `${GAS_API_BASE_URL}/networks/1337/suggestedGasFees`, + fetchGasEstimatesUrl: 'https://some-eip-1559-endpoint/1337', fetchLegacyGasPriceEstimates, - fetchLegacyGasPriceEstimatesUrl: `${GAS_API_BASE_URL}/networks/1337/gasPrices`, + fetchLegacyGasPriceEstimatesUrl: + 'https://some-legacy-endpoint/1337', fetchEthGasPriceEstimate, calculateTimeEstimate, clientId: '99999', ethQuery: expect.any(EthQuery), - infuraAPIKey: expect.any(String), nonRPCGasFeeApisDisabled: false, }); }); @@ -715,6 +723,8 @@ describe('GasFeeController', () => { it('should call determineGasFeeCalculations correctly', async () => { await setupGasFeeController({ ...defaultConstructorOptions, + legacyAPIEndpoint: 'https://some-legacy-endpoint/', + EIP1559APIEndpoint: 'https://some-eip-1559-endpoint/', networkControllerState: { providerConfig: { type: NetworkType.rpc, @@ -732,14 +742,13 @@ describe('GasFeeController', () => { isEIP1559Compatible: false, isLegacyGasAPICompatible: true, fetchGasEstimates, - fetchGasEstimatesUrl: `${GAS_API_BASE_URL}/networks/1337/suggestedGasFees`, + fetchGasEstimatesUrl: 'https://some-eip-1559-endpoint/1337', fetchLegacyGasPriceEstimates, - fetchLegacyGasPriceEstimatesUrl: `${GAS_API_BASE_URL}/networks/1337/gasPrices`, + fetchLegacyGasPriceEstimatesUrl: 'https://some-legacy-endpoint/1337', fetchEthGasPriceEstimate, calculateTimeEstimate, clientId: '99999', ethQuery: expect.any(EthQuery), - infuraAPIKey: expect.any(String), nonRPCGasFeeApisDisabled: false, }); }); @@ -765,6 +774,7 @@ describe('GasFeeController', () => { it('should call determineGasFeeCalculations correctly when getChainId returns a number input', async () => { await setupGasFeeController({ ...defaultConstructorOptions, + legacyAPIEndpoint: 'http://legacy.endpoint/', getChainId: jest.fn().mockReturnValue(1), }); @@ -772,7 +782,7 @@ describe('GasFeeController', () => { expect(mockedDetermineGasFeeCalculations).toHaveBeenCalledWith( expect.objectContaining({ - fetchLegacyGasPriceEstimatesUrl: `${GAS_API_BASE_URL}/networks/1/gasPrices`, + fetchLegacyGasPriceEstimatesUrl: 'http://legacy.endpoint/1', }), ); }); @@ -780,6 +790,7 @@ describe('GasFeeController', () => { it('should call determineGasFeeCalculations correctly when getChainId returns a hexstring input', async () => { await setupGasFeeController({ ...defaultConstructorOptions, + legacyAPIEndpoint: 'http://legacy.endpoint/', getChainId: jest.fn().mockReturnValue('0x1'), }); @@ -787,7 +798,7 @@ describe('GasFeeController', () => { expect(mockedDetermineGasFeeCalculations).toHaveBeenCalledWith( expect.objectContaining({ - fetchLegacyGasPriceEstimatesUrl: `${GAS_API_BASE_URL}/networks/1/gasPrices`, + fetchLegacyGasPriceEstimatesUrl: 'http://legacy.endpoint/1', }), ); }); @@ -831,6 +842,7 @@ describe('GasFeeController', () => { it('should call determineGasFeeCalculations correctly when getChainId returns a numeric string input', async () => { await setupGasFeeController({ ...defaultConstructorOptions, + legacyAPIEndpoint: 'http://legacy.endpoint/', getChainId: jest.fn().mockReturnValue('1'), }); @@ -838,7 +850,7 @@ describe('GasFeeController', () => { expect(mockedDetermineGasFeeCalculations).toHaveBeenCalledWith( expect.objectContaining({ - fetchLegacyGasPriceEstimatesUrl: `${GAS_API_BASE_URL}/networks/1/gasPrices`, + fetchLegacyGasPriceEstimatesUrl: 'http://legacy.endpoint/1', }), ); }); @@ -859,6 +871,8 @@ describe('GasFeeController', () => { it('should call determineGasFeeCalculations correctly', async () => { await setupGasFeeController({ ...defaultConstructorOptions, + legacyAPIEndpoint: 'https://some-legacy-endpoint/', + EIP1559APIEndpoint: 'https://some-eip-1559-endpoint/', networkControllerState: { providerConfig: { type: NetworkType.rpc, @@ -876,14 +890,13 @@ describe('GasFeeController', () => { isEIP1559Compatible: true, isLegacyGasAPICompatible: false, fetchGasEstimates, - fetchGasEstimatesUrl: `${GAS_API_BASE_URL}/networks/1337/suggestedGasFees`, + fetchGasEstimatesUrl: 'https://some-eip-1559-endpoint/1337', fetchLegacyGasPriceEstimates, - fetchLegacyGasPriceEstimatesUrl: `${GAS_API_BASE_URL}/networks/1337/gasPrices`, + fetchLegacyGasPriceEstimatesUrl: 'https://some-legacy-endpoint/1337', fetchEthGasPriceEstimate, calculateTimeEstimate, clientId: '99999', ethQuery: expect.any(EthQuery), - infuraAPIKey: expect.any(String), nonRPCGasFeeApisDisabled: false, }); }); @@ -909,6 +922,7 @@ describe('GasFeeController', () => { it('should call determineGasFeeCalculations with a URL that contains the chain ID', async () => { await setupGasFeeController({ ...defaultConstructorOptions, + EIP1559APIEndpoint: 'http://eip-1559.endpoint/', getChainId: jest.fn().mockReturnValue('0x1'), }); @@ -916,7 +930,7 @@ describe('GasFeeController', () => { expect(mockedDetermineGasFeeCalculations).toHaveBeenCalledWith( expect.objectContaining({ - fetchGasEstimatesUrl: `${GAS_API_BASE_URL}/networks/1/suggestedGasFees`, + fetchGasEstimatesUrl: 'http://eip-1559.endpoint/1', }), ); }); @@ -958,6 +972,8 @@ describe('GasFeeController', () => { it('should call determineGasFeeCalculations correctly', async () => { await setupGasFeeController({ ...defaultConstructorOptions, + legacyAPIEndpoint: 'https://some-legacy-endpoint/', + EIP1559APIEndpoint: 'https://some-eip-1559-endpoint/', clientId: '99999', }); @@ -969,18 +985,19 @@ describe('GasFeeController', () => { isEIP1559Compatible: true, isLegacyGasAPICompatible: false, fetchGasEstimates, - fetchGasEstimatesUrl: `${GAS_API_BASE_URL}/networks/${convertHexToDecimal( - ChainId.goerli, - )}/suggestedGasFees`, + // TODO: Either fix this lint violation or explain why it's necessary to ignore. + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + fetchGasEstimatesUrl: 'https://some-eip-1559-endpoint/5', fetchLegacyGasPriceEstimates, - fetchLegacyGasPriceEstimatesUrl: `${GAS_API_BASE_URL}/networks/${convertHexToDecimal( + // TODO: Either fix this lint violation or explain why it's necessary to ignore. + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + fetchLegacyGasPriceEstimatesUrl: `https://some-legacy-endpoint/${convertHexToDecimal( ChainId.goerli, - )}/gasPrices`, + )}`, fetchEthGasPriceEstimate, calculateTimeEstimate, clientId: '99999', ethQuery: expect.any(EthQuery), - infuraAPIKey: expect.any(String), nonRPCGasFeeApisDisabled: false, }); }); @@ -1068,6 +1085,7 @@ describe('GasFeeController', () => { it('should call determineGasFeeCalculations with a URL that contains the chain ID', async () => { await setupGasFeeController({ ...defaultConstructorOptions, + EIP1559APIEndpoint: 'http://eip-1559.endpoint/', }); await gasFeeController.fetchGasFeeEstimates({ @@ -1076,9 +1094,11 @@ describe('GasFeeController', () => { expect(mockedDetermineGasFeeCalculations).toHaveBeenCalledWith( expect.objectContaining({ - fetchGasEstimatesUrl: `${GAS_API_BASE_URL}/networks/${convertHexToDecimal( + // TODO: Either fix this lint violation or explain why it's necessary to ignore. + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + fetchGasEstimatesUrl: `http://eip-1559.endpoint/${convertHexToDecimal( ChainId.sepolia, - )}/suggestedGasFees`, + )}`, }), ); }); @@ -1093,6 +1113,8 @@ describe('GasFeeController', () => { getCurrentNetworkLegacyGasAPICompatibility: jest .fn() .mockReturnValue(true), + legacyAPIEndpoint: 'https://some-legacy-endpoint/', + EIP1559APIEndpoint: 'https://some-eip-1559-endpoint/', networkControllerState: { networksMetadata: { goerli: { @@ -1118,9 +1140,11 @@ describe('GasFeeController', () => { expect(mockedDetermineGasFeeCalculations).toHaveBeenNthCalledWith( 1, expect.objectContaining({ - fetchGasEstimatesUrl: `${GAS_API_BASE_URL}/networks/${convertHexToDecimal( + // TODO: Either fix this lint violation or explain why it's necessary to ignore. + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + fetchGasEstimatesUrl: `https://some-eip-1559-endpoint/${convertHexToDecimal( ChainId.goerli, - )}/suggestedGasFees`, + )}`, }), ); await clock.tickAsync(pollingInterval / 2); @@ -1129,9 +1153,11 @@ describe('GasFeeController', () => { expect(mockedDetermineGasFeeCalculations).toHaveBeenNthCalledWith( 2, expect.objectContaining({ - fetchGasEstimatesUrl: `${GAS_API_BASE_URL}/networks/${convertHexToDecimal( + // TODO: Either fix this lint violation or explain why it's necessary to ignore. + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + fetchGasEstimatesUrl: `https://some-eip-1559-endpoint/${convertHexToDecimal( ChainId.goerli, - )}/suggestedGasFees`, + )}`, }), ); expect( @@ -1142,9 +1168,11 @@ describe('GasFeeController', () => { await clock.tickAsync(pollingInterval); expect(mockedDetermineGasFeeCalculations).toHaveBeenCalledWith( expect.objectContaining({ - fetchGasEstimatesUrl: `${GAS_API_BASE_URL}/networks/${convertHexToDecimal( + // TODO: Either fix this lint violation or explain why it's necessary to ignore. + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + fetchGasEstimatesUrl: `https://some-eip-1559-endpoint/${convertHexToDecimal( ChainId.sepolia, - )}/suggestedGasFees`, + )}`, }), ); }); diff --git a/packages/gas-fee-controller/src/GasFeeController.ts b/packages/gas-fee-controller/src/GasFeeController.ts index 43da8894d48..19a458f8d61 100644 --- a/packages/gas-fee-controller/src/GasFeeController.ts +++ b/packages/gas-fee-controller/src/GasFeeController.ts @@ -24,13 +24,13 @@ import { v1 as random } from 'uuid'; import determineGasFeeCalculations from './determineGasFeeCalculations'; import { - calculateTimeEstimate, fetchGasEstimates, fetchLegacyGasPriceEstimates, fetchEthGasPriceEstimate, + calculateTimeEstimate, } from './gas-util'; -export const GAS_API_BASE_URL = 'https://gas.api.infura.io'; +export const LEGACY_GAS_PRICES_API_URL = `https://api.metaswap.codefi.network/gasPrices`; export type unknownString = 'unknown'; @@ -278,8 +278,6 @@ export class GasFeeController extends StaticIntervalPollingController< private readonly getCurrentAccountEIP1559Compatibility; - private readonly infuraAPIKey: string; - private currentChainId; private ethQuery?: EthQuery; @@ -305,9 +303,11 @@ export class GasFeeController extends StaticIntervalPollingController< * @param options.getProvider - Returns a network provider for the current network. * @param options.onNetworkDidChange - A function for registering an event handler for the * network state change event. + * @param options.legacyAPIEndpoint - The legacy gas price API URL. This option is primarily for + * testing purposes. + * @param options.EIP1559APIEndpoint - The EIP-1559 gas price API URL. * @param options.clientId - The client ID used to identify to the gas estimation API who is * asking for estimates. - * @param options.infuraAPIKey - The Infura API key used for infura API requests. */ constructor({ interval = 15000, @@ -319,8 +319,9 @@ export class GasFeeController extends StaticIntervalPollingController< getCurrentNetworkLegacyGasAPICompatibility, getProvider, onNetworkDidChange, + legacyAPIEndpoint = LEGACY_GAS_PRICES_API_URL, + EIP1559APIEndpoint, clientId, - infuraAPIKey, }: { interval?: number; messenger: GasFeeMessenger; @@ -331,8 +332,10 @@ export class GasFeeController extends StaticIntervalPollingController< getChainId?: () => Hex; getProvider: () => ProviderProxy; onNetworkDidChange?: (listener: (state: NetworkState) => void) => void; + legacyAPIEndpoint?: string; + // eslint-disable-next-line @typescript-eslint/naming-convention + EIP1559APIEndpoint: string; clientId?: string; - infuraAPIKey: string; }) { super({ name, @@ -350,10 +353,9 @@ export class GasFeeController extends StaticIntervalPollingController< this.getCurrentAccountEIP1559Compatibility = getCurrentAccountEIP1559Compatibility; this.#getProvider = getProvider; - this.EIP1559APIEndpoint = `${GAS_API_BASE_URL}/networks//suggestedGasFees`; - this.legacyAPIEndpoint = `${GAS_API_BASE_URL}/networks//gasPrices`; + this.EIP1559APIEndpoint = EIP1559APIEndpoint; + this.legacyAPIEndpoint = legacyAPIEndpoint; this.clientId = clientId; - this.infuraAPIKey = infuraAPIKey; this.ethQuery = new EthQuery(this.#getProvider()); @@ -475,7 +477,6 @@ export class GasFeeController extends StaticIntervalPollingController< calculateTimeEstimate, clientId: this.clientId, ethQuery, - infuraAPIKey: this.infuraAPIKey, nonRPCGasFeeApisDisabled: this.state.nonRPCGasFeeApisDisabled, }); diff --git a/packages/gas-fee-controller/src/determineGasFeeCalculations.test.ts b/packages/gas-fee-controller/src/determineGasFeeCalculations.test.ts index aee4f05b8a7..a8df42bc14c 100644 --- a/packages/gas-fee-controller/src/determineGasFeeCalculations.test.ts +++ b/packages/gas-fee-controller/src/determineGasFeeCalculations.test.ts @@ -33,8 +33,6 @@ const mockedCalculateTimeEstimate = calculateTimeEstimate as jest.Mock< Parameters >; -const INFURA_API_KEY_MOCK = 'test'; - /** * Builds mock data for the `fetchGasEstimates` function. All of the data here is filled in to make * the gas fee estimation code function in a way that represents a reasonably happy path; it does @@ -126,7 +124,6 @@ describe('determineGasFeeCalculations', () => { calculateTimeEstimate: mockedCalculateTimeEstimate, clientId: 'some-client-id', ethQuery: {}, - infuraAPIKey: INFURA_API_KEY_MOCK, }; describe('when isEIP1559Compatible is true', () => { diff --git a/packages/gas-fee-controller/src/determineGasFeeCalculations.ts b/packages/gas-fee-controller/src/determineGasFeeCalculations.ts index 72697cc4f54..732540a7276 100644 --- a/packages/gas-fee-controller/src/determineGasFeeCalculations.ts +++ b/packages/gas-fee-controller/src/determineGasFeeCalculations.ts @@ -12,13 +12,11 @@ type DetermineGasFeeCalculationsRequest = { isLegacyGasAPICompatible: boolean; fetchGasEstimates: ( url: string, - infuraAPIKey: string, clientId?: string, ) => Promise; fetchGasEstimatesUrl: string; fetchLegacyGasPriceEstimates: ( url: string, - infuraAPIKey: string, clientId?: string, ) => Promise; fetchLegacyGasPriceEstimatesUrl: string; @@ -34,7 +32,6 @@ type DetermineGasFeeCalculationsRequest = { // TODO: Replace `any` with type // eslint-disable-next-line @typescript-eslint/no-explicit-any ethQuery: any; - infuraAPIKey: string; nonRPCGasFeeApisDisabled?: boolean; }; @@ -60,7 +57,6 @@ type DetermineGasFeeCalculationsRequest = { * @param args.calculateTimeEstimate - A function that determine time estimate bounds. * @param args.clientId - An identifier that an API can use to know who is asking for estimates. * @param args.ethQuery - An EthQuery instance we can use to talk to Ethereum directly. - * @param args.infuraAPIKey - Infura API key to use for requests to Infura. * @param args.nonRPCGasFeeApisDisabled - Whether to disable requests to the legacyAPIEndpoint and the EIP1559APIEndpoint * @returns The gas fee calculations. */ @@ -120,16 +116,11 @@ async function getEstimatesUsingFeeMarketEndpoint( const { fetchGasEstimates, fetchGasEstimatesUrl, - infuraAPIKey, clientId, calculateTimeEstimate, } = request; - const estimates = await fetchGasEstimates( - fetchGasEstimatesUrl, - infuraAPIKey, - clientId, - ); + const estimates = await fetchGasEstimates(fetchGasEstimatesUrl, clientId); const { suggestedMaxPriorityFeePerGas, suggestedMaxFeePerGas } = estimates.medium; @@ -158,13 +149,11 @@ async function getEstimatesUsingLegacyEndpoint( const { fetchLegacyGasPriceEstimates, fetchLegacyGasPriceEstimatesUrl, - infuraAPIKey, clientId, } = request; const estimates = await fetchLegacyGasPriceEstimates( fetchLegacyGasPriceEstimatesUrl, - infuraAPIKey, clientId, ); diff --git a/packages/gas-fee-controller/src/gas-util.test.ts b/packages/gas-fee-controller/src/gas-util.test.ts index b1e5647be84..baea4369289 100644 --- a/packages/gas-fee-controller/src/gas-util.test.ts +++ b/packages/gas-fee-controller/src/gas-util.test.ts @@ -1,4 +1,4 @@ -import { handleFetch } from '@metamask/controller-utils'; +import nock from 'nock'; import { fetchLegacyGasPriceEstimates, @@ -8,14 +8,6 @@ import { } from './gas-util'; import type { GasFeeEstimates } from './GasFeeController'; -jest.mock('@metamask/controller-utils', () => { - return { - ...jest.requireActual('@metamask/controller-utils'), - handleFetch: jest.fn(), - }; -}); -const handleFetchMock = jest.mocked(handleFetch); - const mockEIP1559ApiResponses: GasFeeEstimates[] = [ { low: { @@ -73,49 +65,27 @@ const mockEIP1559ApiResponses: GasFeeEstimates[] = [ }, ]; -const INFURA_API_KEY_MOCK = 'test'; -const INFURA_AUTH_TOKEN_MOCK = 'dGVzdDo='; -const INFURA_GAS_API_URL_MOCK = 'https://gas.api.infura.io'; - describe('gas utils', () => { - beforeEach(() => { - jest.resetAllMocks(); - }); - describe('fetchGasEstimates', () => { it('should fetch external gasFeeEstimates when data is valid', async () => { - handleFetchMock.mockResolvedValue(mockEIP1559ApiResponses[0]); - const result = await fetchGasEstimates( - INFURA_GAS_API_URL_MOCK, - INFURA_API_KEY_MOCK, - ); - - expect(handleFetchMock).toHaveBeenCalledTimes(1); - expect(handleFetchMock).toHaveBeenCalledWith(INFURA_GAS_API_URL_MOCK, { - headers: expect.objectContaining({ - Authorization: `Basic ${INFURA_AUTH_TOKEN_MOCK}`, - }), - }); + const scope = nock('https://not-a-real-url/') + .get(/.+/u) + .reply(200, mockEIP1559ApiResponses[0]) + .persist(); + const result = await fetchGasEstimates('https://not-a-real-url/'); expect(result).toMatchObject(mockEIP1559ApiResponses[0]); + scope.done(); }); it('should fetch external gasFeeEstimates with client id header when clientId arg is added', async () => { - const clientIdMock = 'test'; - handleFetchMock.mockResolvedValue(mockEIP1559ApiResponses[0]); - const result = await fetchGasEstimates( - INFURA_GAS_API_URL_MOCK, - INFURA_API_KEY_MOCK, - clientIdMock, - ); - - expect(handleFetchMock).toHaveBeenCalledTimes(1); - expect(handleFetchMock).toHaveBeenCalledWith(INFURA_GAS_API_URL_MOCK, { - headers: expect.objectContaining({ - Authorization: `Basic ${INFURA_AUTH_TOKEN_MOCK}`, - 'X-Client-Id': clientIdMock, - }), - }); + const scope = nock('https://not-a-real-url/') + .matchHeader('x-client-id', 'test') + .get(/.+/u) + .reply(200, mockEIP1559ApiResponses[0]) + .persist(); + const result = await fetchGasEstimates('https://not-a-real-url/', 'test'); expect(result).toMatchObject(mockEIP1559ApiResponses[0]); + scope.done(); }); it('should fetch and normalize external gasFeeEstimates when data is has an invalid number of decimals', async () => { @@ -141,73 +111,57 @@ describe('gas utils', () => { estimatedBaseFee: '32.000000017', }; - handleFetchMock.mockResolvedValue(mockEIP1559ApiResponses[1]); - const result = await fetchGasEstimates( - INFURA_GAS_API_URL_MOCK, - INFURA_API_KEY_MOCK, - ); + const scope = nock('https://not-a-real-url/') + .get(/.+/u) + .reply(200, mockEIP1559ApiResponses[1]) + .persist(); + const result = await fetchGasEstimates('https://not-a-real-url/'); expect(result).toMatchObject(expectedResult); + scope.done(); }); }); describe('fetchLegacyGasPriceEstimates', () => { it('should fetch external gasPrices and return high/medium/low', async () => { - handleFetchMock.mockResolvedValue({ - SafeGasPrice: '22', - ProposeGasPrice: '25', - FastGasPrice: '30', - }); + const scope = nock('https://not-a-real-url/') + .get(/.+/u) + .reply(200, { + SafeGasPrice: '22', + ProposeGasPrice: '25', + FastGasPrice: '30', + }) + .persist(); const result = await fetchLegacyGasPriceEstimates( - INFURA_GAS_API_URL_MOCK, - INFURA_API_KEY_MOCK, - ); - - expect(handleFetchMock).toHaveBeenCalledTimes(1); - expect(handleFetchMock).toHaveBeenCalledWith( - INFURA_GAS_API_URL_MOCK, - - expect.objectContaining({ - headers: expect.objectContaining({ - Authorization: `Basic ${INFURA_AUTH_TOKEN_MOCK}`, - }), - }), + 'https://not-a-real-url/', ); expect(result).toMatchObject({ high: '30', medium: '25', low: '22', }); + scope.done(); }); it('should fetch external gasPrices with client id header when clientId arg is passed', async () => { - const clientIdMock = 'test'; - handleFetchMock.mockResolvedValue({ - SafeGasPrice: '22', - ProposeGasPrice: '25', - FastGasPrice: '30', - }); + const scope = nock('https://not-a-real-url/') + .matchHeader('x-client-id', 'test') + .get(/.+/u) + .reply(200, { + SafeGasPrice: '22', + ProposeGasPrice: '25', + FastGasPrice: '30', + }) + .persist(); const result = await fetchLegacyGasPriceEstimates( - INFURA_GAS_API_URL_MOCK, - INFURA_API_KEY_MOCK, - clientIdMock, - ); - - expect(handleFetchMock).toHaveBeenCalledTimes(1); - expect(handleFetchMock).toHaveBeenCalledWith( - INFURA_GAS_API_URL_MOCK, - - expect.objectContaining({ - headers: expect.objectContaining({ - Authorization: `Basic ${INFURA_AUTH_TOKEN_MOCK}`, - 'X-Client-Id': clientIdMock, - }), - }), + 'https://not-a-real-url/', + 'test', ); expect(result).toMatchObject({ high: '30', medium: '25', low: '22', }); + scope.done(); }); }); diff --git a/packages/gas-fee-controller/src/gas-util.ts b/packages/gas-fee-controller/src/gas-util.ts index 8a7c863f2f1..17a242ac8be 100644 --- a/packages/gas-fee-controller/src/gas-util.ts +++ b/packages/gas-fee-controller/src/gas-util.ts @@ -33,19 +33,17 @@ export function normalizeGWEIDecimalNumbers(n: string | number) { * Fetch gas estimates from the given URL. * * @param url - The gas estimate URL. - * @param infuraAPIKey - The Infura API key used for infura API requests. * @param clientId - The client ID used to identify to the API who is asking for estimates. * @returns The gas estimates. */ export async function fetchGasEstimates( url: string, - infuraAPIKey: string, clientId?: string, ): Promise { - const infuraAuthToken = buildInfuraAuthToken(infuraAPIKey); - const estimates = await handleFetch(url, { - headers: getHeaders(infuraAuthToken, clientId), - }); + const estimates = await handleFetch( + url, + clientId ? { headers: makeClientIdHeader(clientId) } : undefined, + ); return { low: { ...estimates.low, @@ -89,22 +87,22 @@ export async function fetchGasEstimates( * high values from that API. * * @param url - The URL to fetch gas price estimates from. - * @param infuraAPIKey - The Infura API key used for infura API requests. * @param clientId - The client ID used to identify to the API who is asking for estimates. * @returns The gas price estimates. */ export async function fetchLegacyGasPriceEstimates( url: string, - infuraAPIKey: string, clientId?: string, ): Promise { - const infuraAuthToken = buildInfuraAuthToken(infuraAPIKey); const result = await handleFetch(url, { referrer: url, referrerPolicy: 'no-referrer-when-downgrade', method: 'GET', mode: 'cors', - headers: getHeaders(infuraAuthToken, clientId), + headers: { + 'Content-Type': 'application/json', + ...(clientId && makeClientIdHeader(clientId)), + }, }); return { low: result.SafeGasPrice, @@ -193,30 +191,3 @@ export function calculateTimeEstimate( upperTimeBound, }; } - -/** - * Build an infura auth token from the given API key and secret. - * - * @param infuraAPIKey - The Infura API key. - * @returns The base64 encoded auth token. - */ -function buildInfuraAuthToken(infuraAPIKey: string) { - // We intentionally leave the password empty, as Infura does not require one - return Buffer.from(`${infuraAPIKey}:`).toString('base64'); -} - -/** - * Get the headers for a request to the gas fee API. - * - * @param infuraAuthToken - The Infura auth token to use for the request. - * @param clientId - The client ID used to identify to the API who is asking for estimates. - * @returns The headers for the request. - */ -function getHeaders(infuraAuthToken: string, clientId?: string) { - return { - 'Content-Type': 'application/json', - Authorization: `Basic ${infuraAuthToken}`, - // Only add the clientId header if clientId is a non-empty string - ...(clientId?.trim() ? makeClientIdHeader(clientId) : {}), - }; -} diff --git a/yarn.lock b/yarn.lock index a1a145fc161..cf0ff1e5096 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2300,6 +2300,7 @@ __metadata: deepmerge: ^4.2.2 jest: ^27.5.1 jest-when: ^3.4.2 + nock: ^13.3.1 sinon: ^9.2.4 ts-jest: ^27.1.4 typedoc: ^0.24.8 From f37138e0490404f6146adb1a7cee5a5df859c8fd Mon Sep 17 00:00:00 2001 From: Derek Brans Date: Tue, 11 Jun 2024 08:45:28 -0400 Subject: [PATCH 2/2] update jest config --- packages/gas-fee-controller/jest.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gas-fee-controller/jest.config.js b/packages/gas-fee-controller/jest.config.js index b165bc85627..14cf684c6a7 100644 --- a/packages/gas-fee-controller/jest.config.js +++ b/packages/gas-fee-controller/jest.config.js @@ -18,7 +18,7 @@ module.exports = merge(baseConfig, { coverageThreshold: { global: { branches: 81.35, - functions: 81.57, + functions: 80.55, lines: 86.28, statements: 86.44, },