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, }, diff --git a/packages/gas-fee-controller/package.json b/packages/gas-fee-controller/package.json index 61c1093a9dc..d72cc271f72 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 2c4d59b02af..df8c914d409 100644 --- a/packages/gas-fee-controller/src/GasFeeController.test.ts +++ b/packages/gas-fee-controller/src/GasFeeController.test.ts @@ -23,11 +23,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, @@ -228,12 +224,13 @@ 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. */ @@ -242,7 +239,8 @@ describe('GasFeeController', () => { getCurrentNetworkLegacyGasAPICompatibility = jest .fn() .mockReturnValue(false), - infuraAPIKey = 'INFURA_API_KEY', + legacyAPIEndpoint = 'http://legacy.endpoint/', + EIP1559APIEndpoint = 'http://eip-1559.endpoint/', clientId, getChainId, onNetworkDidChange, @@ -255,11 +253,13 @@ 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(); @@ -277,10 +277,11 @@ describe('GasFeeController', () => { messenger, getCurrentNetworkLegacyGasAPICompatibility, getCurrentNetworkEIP1559Compatibility: getIsEIP1559Compatible, // change this for networkDetails.state.networkDetails.isEIP1559Compatible ??? + legacyAPIEndpoint, + EIP1559APIEndpoint, state, clientId, interval, - infuraAPIKey, }); } @@ -335,6 +336,8 @@ describe('GasFeeController', () => { getCurrentNetworkLegacyGasAPICompatibility: jest .fn() .mockReturnValue(true), + legacyAPIEndpoint: 'https://some-legacy-endpoint/', + EIP1559APIEndpoint: 'https://some-eip-1559-endpoint/', networkControllerState: { networkConfigurations: { 'AAAA-BBBB-CCCC-DDDD': { @@ -362,14 +365,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, }); }); @@ -399,6 +402,8 @@ describe('GasFeeController', () => { getCurrentNetworkLegacyGasAPICompatibility: jest .fn() .mockReturnValue(true), + legacyAPIEndpoint: 'https://some-legacy-endpoint/', + EIP1559APIEndpoint: 'https://some-eip-1559-endpoint/', networkControllerState: { networkConfigurations: { 'AAAA-BBBB-CCCC-DDDD': { @@ -428,14 +433,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, }); }); @@ -752,6 +757,8 @@ describe('GasFeeController', () => { it('should call determineGasFeeCalculations correctly', async () => { await setupGasFeeController({ ...defaultConstructorOptions, + legacyAPIEndpoint: 'https://some-legacy-endpoint/', + EIP1559APIEndpoint: 'https://some-eip-1559-endpoint/', networkControllerState: { networkConfigurations: { 'AAAA-BBBB-CCCC-DDDD': { @@ -779,14 +786,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, }); }); @@ -812,6 +818,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), }); @@ -819,7 +826,7 @@ describe('GasFeeController', () => { expect(mockedDetermineGasFeeCalculations).toHaveBeenCalledWith( expect.objectContaining({ - fetchLegacyGasPriceEstimatesUrl: `${GAS_API_BASE_URL}/networks/1/gasPrices`, + fetchLegacyGasPriceEstimatesUrl: 'http://legacy.endpoint/1', }), ); }); @@ -827,6 +834,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'), }); @@ -834,7 +842,7 @@ describe('GasFeeController', () => { expect(mockedDetermineGasFeeCalculations).toHaveBeenCalledWith( expect.objectContaining({ - fetchLegacyGasPriceEstimatesUrl: `${GAS_API_BASE_URL}/networks/1/gasPrices`, + fetchLegacyGasPriceEstimatesUrl: 'http://legacy.endpoint/1', }), ); }); @@ -878,6 +886,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'), }); @@ -885,7 +894,7 @@ describe('GasFeeController', () => { expect(mockedDetermineGasFeeCalculations).toHaveBeenCalledWith( expect.objectContaining({ - fetchLegacyGasPriceEstimatesUrl: `${GAS_API_BASE_URL}/networks/1/gasPrices`, + fetchLegacyGasPriceEstimatesUrl: 'http://legacy.endpoint/1', }), ); }); @@ -906,6 +915,8 @@ describe('GasFeeController', () => { it('should call determineGasFeeCalculations correctly', async () => { await setupGasFeeController({ ...defaultConstructorOptions, + legacyAPIEndpoint: 'https://some-legacy-endpoint/', + EIP1559APIEndpoint: 'https://some-eip-1559-endpoint/', networkControllerState: { networkConfigurations: { 'AAAA-BBBB-CCCC-DDDD': { @@ -933,14 +944,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, }); }); @@ -966,6 +976,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'), }); @@ -973,7 +984,7 @@ describe('GasFeeController', () => { expect(mockedDetermineGasFeeCalculations).toHaveBeenCalledWith( expect.objectContaining({ - fetchGasEstimatesUrl: `${GAS_API_BASE_URL}/networks/1/suggestedGasFees`, + fetchGasEstimatesUrl: 'http://eip-1559.endpoint/1', }), ); }); @@ -1015,6 +1026,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', }); @@ -1028,20 +1041,17 @@ describe('GasFeeController', () => { fetchGasEstimates, // TODO: Either fix this lint violation or explain why it's necessary to ignore. // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - fetchGasEstimatesUrl: `${GAS_API_BASE_URL}/networks/${convertHexToDecimal( - ChainId.goerli, - )}/suggestedGasFees`, + fetchGasEstimatesUrl: 'https://some-eip-1559-endpoint/5', fetchLegacyGasPriceEstimates, // TODO: Either fix this lint violation or explain why it's necessary to ignore. // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - fetchLegacyGasPriceEstimatesUrl: `${GAS_API_BASE_URL}/networks/${convertHexToDecimal( + fetchLegacyGasPriceEstimatesUrl: `https://some-legacy-endpoint/${convertHexToDecimal( ChainId.goerli, - )}/gasPrices`, + )}`, fetchEthGasPriceEstimate, calculateTimeEstimate, clientId: '99999', ethQuery: expect.any(EthQuery), - infuraAPIKey: expect.any(String), nonRPCGasFeeApisDisabled: false, }); }); @@ -1129,6 +1139,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({ @@ -1139,9 +1150,9 @@ describe('GasFeeController', () => { expect.objectContaining({ // TODO: Either fix this lint violation or explain why it's necessary to ignore. // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - fetchGasEstimatesUrl: `${GAS_API_BASE_URL}/networks/${convertHexToDecimal( + fetchGasEstimatesUrl: `http://eip-1559.endpoint/${convertHexToDecimal( ChainId.sepolia, - )}/suggestedGasFees`, + )}`, }), ); }); @@ -1156,6 +1167,8 @@ describe('GasFeeController', () => { getCurrentNetworkLegacyGasAPICompatibility: jest .fn() .mockReturnValue(true), + legacyAPIEndpoint: 'https://some-legacy-endpoint/', + EIP1559APIEndpoint: 'https://some-eip-1559-endpoint/', networkControllerState: { networksMetadata: { goerli: { @@ -1183,9 +1196,9 @@ describe('GasFeeController', () => { expect.objectContaining({ // TODO: Either fix this lint violation or explain why it's necessary to ignore. // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - fetchGasEstimatesUrl: `${GAS_API_BASE_URL}/networks/${convertHexToDecimal( + fetchGasEstimatesUrl: `https://some-eip-1559-endpoint/${convertHexToDecimal( ChainId.goerli, - )}/suggestedGasFees`, + )}`, }), ); await clock.tickAsync(pollingInterval / 2); @@ -1196,9 +1209,9 @@ describe('GasFeeController', () => { expect.objectContaining({ // TODO: Either fix this lint violation or explain why it's necessary to ignore. // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - fetchGasEstimatesUrl: `${GAS_API_BASE_URL}/networks/${convertHexToDecimal( + fetchGasEstimatesUrl: `https://some-eip-1559-endpoint/${convertHexToDecimal( ChainId.goerli, - )}/suggestedGasFees`, + )}`, }), ); expect( @@ -1211,9 +1224,9 @@ describe('GasFeeController', () => { expect.objectContaining({ // TODO: Either fix this lint violation or explain why it's necessary to ignore. // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - fetchGasEstimatesUrl: `${GAS_API_BASE_URL}/networks/${convertHexToDecimal( + 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 f6bc4e0a1c5..9e7b30515ef 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`; // TODO: Either fix this lint violation or explain why it's necessary to ignore. // eslint-disable-next-line @typescript-eslint/naming-convention @@ -282,8 +282,6 @@ export class GasFeeController extends StaticIntervalPollingController< private readonly getCurrentAccountEIP1559Compatibility; - private readonly infuraAPIKey: string; - private currentChainId; private ethQuery?: EthQuery; @@ -309,9 +307,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, @@ -323,8 +323,9 @@ export class GasFeeController extends StaticIntervalPollingController< getCurrentNetworkLegacyGasAPICompatibility, getProvider, onNetworkDidChange, + legacyAPIEndpoint = LEGACY_GAS_PRICES_API_URL, + EIP1559APIEndpoint, clientId, - infuraAPIKey, }: { interval?: number; messenger: GasFeeMessenger; @@ -335,8 +336,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, @@ -354,10 +357,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()); @@ -487,7 +489,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 7d3f5cedb5a..90734457147 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2960,6 +2960,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