Skip to content

Commit 55b22e8

Browse files
Delay EthQuery instantiation until network provider is available (#274)
* wip * lint fix * fix unit tests * Pass the nonce lock at the initialization step * remove delayedInit function * fix tests * clean up
1 parent 69d07c1 commit 55b22e8

File tree

2 files changed

+78
-25
lines changed

2 files changed

+78
-25
lines changed

src/SmartTransactionsController.test.ts

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { convertHexToDecimal } from '@metamask/controller-utils';
1+
import { NetworkType, convertHexToDecimal } from '@metamask/controller-utils';
22
import type { NetworkState } from '@metamask/network-controller';
3+
import { NetworkStatus } from '@metamask/network-controller';
34
import nock from 'nock';
45
import * as sinon from 'sinon';
56

@@ -9,7 +10,7 @@ import { API_BASE_URL, CHAIN_IDS } from './constants';
910
import SmartTransactionsController, {
1011
DEFAULT_INTERVAL,
1112
} from './SmartTransactionsController';
12-
import { flushPromises, advanceTime } from './test-helpers';
13+
import { advanceTime, flushPromises } from './test-helpers';
1314
import type { SmartTransaction, UnsignedTransaction } from './types';
1415
import { SmartTransactionStatuses } from './types';
1516
import * as utils from './utils';
@@ -308,12 +309,47 @@ const defaultState = {
308309
},
309310
};
310311

312+
const mockProvider = {
313+
sendAsync: jest.fn(),
314+
};
315+
316+
const mockProviderConfig = {
317+
chainId: '0x1' as `0x${string}`,
318+
provider: mockProvider,
319+
type: NetworkType.mainnet,
320+
ticker: 'ticker',
321+
};
322+
323+
const mockNetworkState = {
324+
providerConfig: mockProviderConfig,
325+
selectedNetworkClientId: 'id',
326+
networkConfigurations: {
327+
id: {
328+
id: 'id',
329+
rpcUrl: 'string',
330+
chainId: '0x1' as `0x${string}`,
331+
ticker: 'string',
332+
},
333+
},
334+
networksMetadata: {
335+
id: {
336+
EIPS: {
337+
1155: true,
338+
},
339+
status: NetworkStatus.Available,
340+
},
341+
},
342+
};
343+
311344
describe('SmartTransactionsController', () => {
312345
let smartTransactionsController: SmartTransactionsController;
313346
let networkListener: (networkState: NetworkState) => void;
347+
314348
beforeEach(() => {
315349
smartTransactionsController = new SmartTransactionsController({
316-
onNetworkStateChange: (listener) => {
350+
onNetworkStateChange: (
351+
listener: (networkState: NetworkState) => void,
352+
) => {
317353
networkListener = listener;
318354
},
319355
getNonceLock: jest.fn(() => {
@@ -346,6 +382,8 @@ describe('SmartTransactionsController', () => {
346382
});
347383
// eslint-disable-next-line jest/prefer-spy-on
348384
smartTransactionsController.subscribe = jest.fn();
385+
386+
networkListener(mockNetworkState);
349387
});
350388

351389
afterEach(async () => {

src/SmartTransactionsController.ts

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
// eslint-disable-next-line import/no-nodejs-modules
22
import { hexlify } from '@ethersproject/bytes';
33
import type { BaseConfig, BaseState } from '@metamask/base-controller';
4-
import { safelyExecute, query } from '@metamask/controller-utils';
4+
import { query, safelyExecute } from '@metamask/controller-utils';
55
import type { Provider } from '@metamask/eth-query';
66
import EthQuery from '@metamask/eth-query';
77
import type {
8-
NetworkState,
9-
NetworkController,
108
NetworkClientId,
9+
NetworkController,
10+
NetworkState,
1111
} from '@metamask/network-controller';
1212
import { StaticIntervalPollingControllerV1 } from '@metamask/polling-controller';
1313
import { BigNumber } from 'bignumber.js';
1414
// eslint-disable-next-line import/no-nodejs-modules
15-
import { EventEmitter } from 'events';
15+
import EventEmitter from 'events';
1616
import cloneDeep from 'lodash/cloneDeep';
1717

1818
import {
@@ -21,31 +21,33 @@ import {
2121
MetaMetricsEventName,
2222
} from './constants';
2323
import type {
24-
SmartTransaction,
25-
SignedTransaction,
26-
SignedCanceledTransaction,
27-
UnsignedTransaction,
28-
SmartTransactionsStatus,
2924
Fees,
30-
IndividualTxFees,
3125
Hex,
26+
IndividualTxFees,
27+
SignedCanceledTransaction,
28+
SignedTransaction,
29+
SmartTransaction,
30+
SmartTransactionsStatus,
31+
UnsignedTransaction,
3232
} from './types';
3333
import { APIType, SmartTransactionStatuses } from './types';
3434
import {
35-
getAPIRequestURL,
36-
isSmartTransactionPending,
3735
calculateStatus,
38-
snapshotFromTxMeta,
39-
replayHistory,
4036
generateHistoryEntry,
37+
getAPIRequestURL,
4138
getStxProcessingTime,
4239
handleFetch,
43-
isSmartTransactionCancellable,
4440
incrementNonceInHex,
41+
isSmartTransactionCancellable,
42+
isSmartTransactionPending,
43+
replayHistory,
44+
snapshotFromTxMeta,
4545
} from './utils';
4646

4747
const SECOND = 1000;
4848
export const DEFAULT_INTERVAL = SECOND * 5;
49+
const ETH_QUERY_ERROR_MSG =
50+
'`ethQuery` is not defined on SmartTransactionsController';
4951

5052
export type SmartTransactionsControllerConfig = BaseConfig & {
5153
interval: number;
@@ -84,7 +86,7 @@ export default class SmartTransactionsController extends StaticIntervalPollingCo
8486

8587
private readonly getNonceLock: any;
8688

87-
private ethQuery: EthQuery;
89+
private ethQuery: EthQuery | undefined;
8890

8991
public confirmExternalTransaction: any;
9092

@@ -168,7 +170,7 @@ export default class SmartTransactionsController extends StaticIntervalPollingCo
168170
this.initialize();
169171
this.setIntervalLength(this.config.interval);
170172
this.getNonceLock = getNonceLock;
171-
this.ethQuery = new EthQuery(provider);
173+
this.ethQuery = undefined;
172174
this.confirmExternalTransaction = confirmExternalTransaction;
173175
this.trackMetaMetricsEvent = trackMetaMetricsEvent;
174176
this.getNetworkClientById = getNetworkClientById;
@@ -333,7 +335,7 @@ export default class SmartTransactionsController extends StaticIntervalPollingCo
333335
ethQuery = this.ethQuery,
334336
}: {
335337
chainId: Hex;
336-
ethQuery: EthQuery;
338+
ethQuery: EthQuery | undefined;
337339
},
338340
): void {
339341
const { smartTransactionsState } = this.state;
@@ -345,6 +347,9 @@ export default class SmartTransactionsController extends StaticIntervalPollingCo
345347
const isNewSmartTransaction = this.isNewSmartTransaction(
346348
smartTransaction.uuid,
347349
);
350+
if (this.ethQuery === undefined) {
351+
throw new Error(ETH_QUERY_ERROR_MSG);
352+
}
348353

349354
this.trackStxStatusChange(
350355
smartTransaction,
@@ -445,12 +450,16 @@ export default class SmartTransactionsController extends StaticIntervalPollingCo
445450
ethQuery = this.ethQuery,
446451
}: {
447452
chainId: Hex;
448-
ethQuery: EthQuery;
453+
ethQuery: EthQuery | undefined;
449454
},
450455
) {
451456
if (smartTransaction.skipConfirm) {
452457
return;
453458
}
459+
460+
if (ethQuery === undefined) {
461+
throw new Error(ETH_QUERY_ERROR_MSG);
462+
}
454463
const txHash = smartTransaction.statusMetadata?.minedHash;
455464
try {
456465
const transactionReceipt: {
@@ -744,9 +753,15 @@ export default class SmartTransactionsController extends StaticIntervalPollingCo
744753
}: {
745754
networkClientId?: NetworkClientId;
746755
} = {}): EthQuery {
747-
return networkClientId
748-
? new EthQuery(this.getNetworkClientById(networkClientId).provider)
749-
: this.ethQuery;
756+
if (networkClientId) {
757+
return new EthQuery(this.getNetworkClientById(networkClientId).provider);
758+
}
759+
760+
if (this.ethQuery === undefined) {
761+
throw new Error(ETH_QUERY_ERROR_MSG);
762+
}
763+
764+
return this.ethQuery;
750765
}
751766

752767
// TODO: This should return if the cancellation was on chain or not (for nonce management)

0 commit comments

Comments
 (0)