@toruslabs/ethereum-controllers 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/dist/ethereumControllers.cjs.js +6153 -0
  2. package/dist/ethereumControllers.cjs.js.map +1 -0
  3. package/dist/ethereumControllers.esm.js +5570 -0
  4. package/dist/ethereumControllers.esm.js.map +1 -0
  5. package/dist/ethereumControllers.umd.min.js +3 -0
  6. package/dist/ethereumControllers.umd.min.js.LICENSE.txt +38 -0
  7. package/dist/ethereumControllers.umd.min.js.map +1 -0
  8. package/dist/types/Account/AccountTrackerController.d.ts +35 -0
  9. package/dist/types/Block/PollingBlockTracker.d.ts +14 -0
  10. package/dist/types/Currency/CurrencyController.d.ts +30 -0
  11. package/dist/types/Gas/GasFeeController.d.ts +64 -0
  12. package/dist/types/Gas/IGasFeeController.d.ts +49 -0
  13. package/dist/types/Gas/gasUtil.d.ts +21 -0
  14. package/dist/types/Keyring/KeyringController.d.ts +20 -0
  15. package/dist/types/Message/AbstractMessageController.d.ts +36 -0
  16. package/dist/types/Message/DecryptMessageController.d.ts +20 -0
  17. package/dist/types/Message/EncryptionPublicKeyController.d.ts +20 -0
  18. package/dist/types/Message/MessageController.d.ts +20 -0
  19. package/dist/types/Message/PersonalMessageController.d.ts +20 -0
  20. package/dist/types/Message/TypedMessageController.d.ts +21 -0
  21. package/dist/types/Message/utils.d.ts +10 -0
  22. package/dist/types/Network/NetworkController.d.ts +40 -0
  23. package/dist/types/Network/createEthereumMiddleware.d.ts +66 -0
  24. package/dist/types/Network/createJsonRpcClient.d.ts +9 -0
  25. package/dist/types/Nfts/INftsController.d.ts +10 -0
  26. package/dist/types/Nfts/NftHandler.d.ts +35 -0
  27. package/dist/types/Nfts/NftsController.d.ts +40 -0
  28. package/dist/types/Preferences/PreferencesController.d.ts +53 -0
  29. package/dist/types/Tokens/ITokensController.d.ts +10 -0
  30. package/dist/types/Tokens/TokenHandler.d.ts +20 -0
  31. package/dist/types/Tokens/TokenRatesController.d.ts +42 -0
  32. package/dist/types/Tokens/TokensController.d.ts +42 -0
  33. package/dist/types/Transaction/NonceTracker.d.ts +37 -0
  34. package/dist/types/Transaction/PendingTransactionTracker.d.ts +32 -0
  35. package/dist/types/Transaction/TransactionController.d.ts +67 -0
  36. package/dist/types/Transaction/TransactionGasUtil.d.ts +21 -0
  37. package/dist/types/Transaction/TransactionStateHistoryHelper.d.ts +16 -0
  38. package/dist/types/Transaction/TransactionStateManager.d.ts +30 -0
  39. package/dist/types/Transaction/TransactionUtils.d.ts +70 -0
  40. package/dist/types/index.d.ts +43 -0
  41. package/dist/types/utils/abiDecoder.d.ts +17 -0
  42. package/dist/types/utils/abis.d.ts +84 -0
  43. package/dist/types/utils/constants.d.ts +81 -0
  44. package/dist/types/utils/contractAddresses.d.ts +1 -0
  45. package/dist/types/utils/conversionUtils.d.ts +42 -0
  46. package/dist/types/utils/helpers.d.ts +24 -0
  47. package/dist/types/utils/interfaces.d.ts +384 -0
  48. package/package.json +71 -0
  49. package/src/Account/AccountTrackerController.ts +157 -0
  50. package/src/Block/PollingBlockTracker.ts +89 -0
  51. package/src/Currency/CurrencyController.ts +117 -0
  52. package/src/Gas/GasFeeController.ts +254 -0
  53. package/src/Gas/IGasFeeController.ts +56 -0
  54. package/src/Gas/gasUtil.ts +163 -0
  55. package/src/Keyring/KeyringController.ts +118 -0
  56. package/src/Message/AbstractMessageController.ts +136 -0
  57. package/src/Message/DecryptMessageController.ts +81 -0
  58. package/src/Message/EncryptionPublicKeyController.ts +83 -0
  59. package/src/Message/MessageController.ts +74 -0
  60. package/src/Message/PersonalMessageController.ts +74 -0
  61. package/src/Message/TypedMessageController.ts +112 -0
  62. package/src/Message/utils.ts +107 -0
  63. package/src/Network/NetworkController.ts +184 -0
  64. package/src/Network/createEthereumMiddleware.ts +307 -0
  65. package/src/Network/createJsonRpcClient.ts +59 -0
  66. package/src/Nfts/INftsController.ts +13 -0
  67. package/src/Nfts/NftHandler.ts +191 -0
  68. package/src/Nfts/NftsController.ts +230 -0
  69. package/src/Preferences/PreferencesController.ts +409 -0
  70. package/src/Tokens/ITokensController.ts +13 -0
  71. package/src/Tokens/TokenHandler.ts +60 -0
  72. package/src/Tokens/TokenRatesController.ts +134 -0
  73. package/src/Tokens/TokensController.ts +278 -0
  74. package/src/Transaction/NonceTracker.ts +152 -0
  75. package/src/Transaction/PendingTransactionTracker.ts +235 -0
  76. package/src/Transaction/TransactionController.ts +558 -0
  77. package/src/Transaction/TransactionGasUtil.ts +74 -0
  78. package/src/Transaction/TransactionStateHistoryHelper.ts +41 -0
  79. package/src/Transaction/TransactionStateManager.ts +315 -0
  80. package/src/Transaction/TransactionUtils.ts +333 -0
  81. package/src/index.ts +45 -0
  82. package/src/utils/abiDecoder.ts +195 -0
  83. package/src/utils/abis.ts +677 -0
  84. package/src/utils/constants.ts +379 -0
  85. package/src/utils/contractAddresses.ts +21 -0
  86. package/src/utils/conversionUtils.ts +269 -0
  87. package/src/utils/helpers.ts +177 -0
  88. package/src/utils/interfaces.ts +454 -0
@@ -0,0 +1,74 @@
1
+ import { BaseConfig, randomId } from "@toruslabs/base-controllers";
2
+ import { JRPCRequest } from "@toruslabs/openlogin-jrpc";
3
+ import log from "loglevel";
4
+
5
+ import KeyringController from "../Keyring/KeyringController";
6
+ import NetworkController from "../Network/NetworkController";
7
+ import { MessageStatus, METHOD_TYPES } from "../utils/constants";
8
+ import { Message, MessageParams, UserRequestApprovalParams } from "../utils/interfaces";
9
+ import AbstractMessageController, { MessageControllerState } from "./AbstractMessageController";
10
+ import { normalizeMessageData, validateSignMessageData } from "./utils";
11
+
12
+ export class PersonalMessageController extends AbstractMessageController<Message, MessageParams> {
13
+ override name = "PersonalMessageController";
14
+
15
+ protected signPersonalMessage: KeyringController["signPersonalMessage"];
16
+
17
+ constructor({
18
+ config,
19
+ state,
20
+ signPersonalMessage,
21
+ getNetworkIdentifier,
22
+ }: {
23
+ config: Partial<BaseConfig>;
24
+ state: Partial<MessageControllerState<Message>>;
25
+ signPersonalMessage: KeyringController["signPersonalMessage"];
26
+ getNetworkIdentifier: NetworkController["getNetworkIdentifier"];
27
+ }) {
28
+ super({ config, state, getNetworkIdentifier });
29
+ this.signPersonalMessage = signPersonalMessage;
30
+ this.initialize();
31
+ }
32
+
33
+ async processPersonalSignMessage(messageId: string): Promise<string> {
34
+ try {
35
+ const msgObject = this.getMessage(messageId);
36
+ const cleanMsgParams = await this.approveMessage(msgObject.messageParams);
37
+ const rawSig = await this.signPersonalMessage(cleanMsgParams.data, cleanMsgParams.from);
38
+ this.updateMessage({ ...msgObject, rawSig });
39
+ this.setMessageStatus(messageId, MessageStatus.SIGNED);
40
+ return rawSig;
41
+ } catch (error) {
42
+ log.error(error);
43
+ this.setMessageStatus(messageId, MessageStatus.FAILED);
44
+ }
45
+ }
46
+
47
+ async addNewUnapprovedMessage(messageParams: MessageParams, req: JRPCRequest<MessageParams> & UserRequestApprovalParams): Promise<string> {
48
+ await this.addUnapprovedMessage(messageParams, req);
49
+ return this.waitForFinishStatus(messageParams, this.name);
50
+ }
51
+
52
+ async addUnapprovedMessage(messageParams: MessageParams, req: JRPCRequest<MessageParams> & UserRequestApprovalParams): Promise<string> {
53
+ validateSignMessageData(messageParams);
54
+ if (req) {
55
+ messageParams.origin = req.origin;
56
+ }
57
+ messageParams.data = normalizeMessageData(messageParams.data);
58
+ const messageId = randomId();
59
+ const messageData: Message = {
60
+ id: messageId,
61
+ messageParams,
62
+ status: MessageStatus.UNAPPROVED,
63
+ time: Date.now(),
64
+ type: METHOD_TYPES.PERSONAL_SIGN,
65
+ };
66
+ await this.addMessage(messageData);
67
+ this.emit(`unapprovedMessage`, messageParams);
68
+ return messageId;
69
+ }
70
+
71
+ prepMessageForSigning(messageParams: MessageParams): Promise<MessageParams> {
72
+ return Promise.resolve(messageParams);
73
+ }
74
+ }
@@ -0,0 +1,112 @@
1
+ import { MessageTypes, SignTypedDataVersion, TypedDataV1, TypedMessage as EthSigTypedMessage } from "@metamask/eth-sig-util";
2
+ import { BaseConfig, randomId } from "@toruslabs/base-controllers";
3
+ import { JRPCRequest } from "@toruslabs/openlogin-jrpc";
4
+ import log from "loglevel";
5
+
6
+ import KeyringController from "../Keyring/KeyringController";
7
+ import NetworkController from "../Network/NetworkController";
8
+ import { MessageStatus, METHOD_TYPES } from "../utils/constants";
9
+ import { METHOD_TYPES_TYPE, TypedMessage, TypedMessageParams, UserRequestApprovalParams } from "../utils/interfaces";
10
+ import AbstractMessageController, { MessageControllerState } from "./AbstractMessageController";
11
+ import { validateTypedSignMessageDataV1, validateTypedSignMessageDataV3V4 } from "./utils";
12
+
13
+ function getMessageType(version: SignTypedDataVersion): METHOD_TYPES_TYPE {
14
+ switch (version) {
15
+ case SignTypedDataVersion.V1:
16
+ return METHOD_TYPES.ETH_SIGN_TYPED_DATA;
17
+ case SignTypedDataVersion.V3:
18
+ return METHOD_TYPES.ETH_SIGN_TYPED_DATA_V3;
19
+ case SignTypedDataVersion.V4:
20
+ return METHOD_TYPES.ETH_SIGN_TYPED_DATA_V4;
21
+ default:
22
+ return METHOD_TYPES.ETH_SIGN_TYPED_DATA;
23
+ }
24
+ }
25
+
26
+ export class TypedMessageController extends AbstractMessageController<TypedMessage, TypedMessageParams> {
27
+ override name = "TypedMessageController";
28
+
29
+ protected signTypedData: KeyringController["signTypedData"];
30
+
31
+ constructor({
32
+ config,
33
+ state,
34
+ signTypedData,
35
+ getNetworkIdentifier,
36
+ }: {
37
+ config: Partial<BaseConfig>;
38
+ state: Partial<MessageControllerState<TypedMessage>>;
39
+ signTypedData: KeyringController["signTypedData"];
40
+ getNetworkIdentifier: NetworkController["getNetworkIdentifier"];
41
+ }) {
42
+ super({ config, state, getNetworkIdentifier });
43
+ this.signTypedData = signTypedData;
44
+ this.initialize();
45
+ }
46
+
47
+ async processPersonalSignMessage(messageId: string): Promise<string> {
48
+ try {
49
+ const msgObject = this.getMessage(messageId);
50
+ const cleanMsgParams = await this.approveMessage(msgObject.messageParams);
51
+ const rawSig = await this.signTypedData(
52
+ cleanMsgParams.data as TypedDataV1 | EthSigTypedMessage<MessageTypes>,
53
+ cleanMsgParams.from,
54
+ cleanMsgParams.version
55
+ );
56
+ this.updateMessage({ ...msgObject, rawSig });
57
+ this.setMessageStatus(messageId, MessageStatus.SIGNED);
58
+ return rawSig;
59
+ } catch (error) {
60
+ log.error(error);
61
+ this.setMessageStatus(messageId, MessageStatus.FAILED);
62
+ }
63
+ }
64
+
65
+ async addNewUnapprovedMessage(
66
+ messageParams: TypedMessageParams,
67
+ req: JRPCRequest<TypedMessageParams> & UserRequestApprovalParams,
68
+ version: SignTypedDataVersion
69
+ ): Promise<string> {
70
+ await this.addUnapprovedMessage(messageParams, req, version);
71
+ return this.waitForFinishStatus(messageParams, this.name);
72
+ }
73
+
74
+ async addUnapprovedMessage(
75
+ messageParams: TypedMessageParams,
76
+ req: JRPCRequest<TypedMessageParams> & UserRequestApprovalParams,
77
+ version: SignTypedDataVersion
78
+ ): Promise<string> {
79
+ if (version === SignTypedDataVersion.V1) {
80
+ validateTypedSignMessageDataV1(messageParams);
81
+ }
82
+
83
+ if (version === SignTypedDataVersion.V3 || version === SignTypedDataVersion.V4) {
84
+ const currentChainId = this.getNetworkIdentifier();
85
+ validateTypedSignMessageDataV3V4(messageParams, currentChainId);
86
+ }
87
+
88
+ if (typeof messageParams.data !== "string" && (version === SignTypedDataVersion.V3 || version === SignTypedDataVersion.V4)) {
89
+ messageParams.data = JSON.stringify(messageParams.data);
90
+ }
91
+
92
+ if (req) {
93
+ messageParams.origin = req.origin;
94
+ }
95
+ messageParams.version = version;
96
+ const messageId = randomId();
97
+ const messageData: TypedMessage = {
98
+ id: messageId,
99
+ messageParams,
100
+ status: MessageStatus.UNAPPROVED,
101
+ time: Date.now(),
102
+ type: getMessageType(version),
103
+ };
104
+ await this.addMessage(messageData);
105
+ this.emit(`unapprovedMessage`, messageParams);
106
+ return messageId;
107
+ }
108
+
109
+ prepMessageForSigning(messageParams: TypedMessageParams): Promise<TypedMessageParams> {
110
+ return Promise.resolve(messageParams);
111
+ }
112
+ }
@@ -0,0 +1,107 @@
1
+ import { addHexPrefix, bytesToHex, isValidAddress, stripHexPrefix } from "@ethereumjs/util";
2
+ import { EthEncryptedData, TYPED_MESSAGE_SCHEMA, TypedDataV1Field, typedSignatureHash } from "@metamask/eth-sig-util";
3
+ import { validate } from "jsonschema";
4
+
5
+ import { DecryptMessageParams, EncryptionPublicKeyParams, MessageParams, TypedMessageParams } from "../utils/interfaces";
6
+
7
+ const hexRe = /^[0-9A-Fa-f]+$/gu;
8
+
9
+ export function validateAddress(address: string, propertyName: string) {
10
+ if (!address || typeof address !== "string" || !isValidAddress(address)) {
11
+ throw new Error(`Invalid "${propertyName}" address: ${address} must be a valid string.`);
12
+ }
13
+ }
14
+
15
+ export function validateSignMessageData(messageData: MessageParams) {
16
+ const { from, data } = messageData;
17
+ validateAddress(from, "from");
18
+
19
+ if (!data || typeof data !== "string") {
20
+ throw new Error(`Invalid message "data": ${data} must be a valid string.`);
21
+ }
22
+ }
23
+
24
+ export function normalizeMessageData(data: string): string {
25
+ try {
26
+ const stripped = stripHexPrefix(data);
27
+ if (stripped.match(hexRe)) {
28
+ return addHexPrefix(stripped);
29
+ }
30
+ } catch (e) {}
31
+ return bytesToHex(Buffer.from(data, "utf8"));
32
+ }
33
+
34
+ export function validateTypedSignMessageDataV1(messageData: TypedMessageParams) {
35
+ validateAddress(messageData.from, "from");
36
+
37
+ if (!messageData.data || !Array.isArray(messageData.data)) {
38
+ throw new Error(`Invalid message "data": ${messageData.data} must be a valid array.`);
39
+ }
40
+
41
+ try {
42
+ // typedSignatureHash will throw if the data is invalid.
43
+ typedSignatureHash(messageData.data as TypedDataV1Field[]);
44
+ } catch (e) {
45
+ throw new Error(`Expected EIP712 typed data.`);
46
+ }
47
+ }
48
+
49
+ export function validateTypedSignMessageDataV3V4(messageData: TypedMessageParams, currentChainId: string) {
50
+ validateAddress(messageData.from, "from");
51
+
52
+ if (!messageData.data || Array.isArray(messageData.data) || (typeof messageData.data !== "object" && typeof messageData.data !== "string")) {
53
+ throw new Error(`Invalid message "data": Must be a valid string or object.`);
54
+ }
55
+
56
+ let data;
57
+ if (typeof messageData.data === "object") {
58
+ data = messageData.data;
59
+ } else {
60
+ try {
61
+ data = JSON.parse(messageData.data);
62
+ } catch (e) {
63
+ throw new Error("Data must be passed as a valid JSON string.");
64
+ }
65
+ }
66
+
67
+ const validation = validate(data, TYPED_MESSAGE_SCHEMA);
68
+ if (validation.errors.length > 0) {
69
+ throw new Error("Data must conform to EIP-712 schema. See https://git.io/fNtcx.");
70
+ }
71
+
72
+ if (!currentChainId) {
73
+ throw new Error("Current chainId cannot be null or undefined.");
74
+ }
75
+
76
+ let { chainId } = data.domain;
77
+ if (chainId) {
78
+ if (typeof chainId === "string") {
79
+ chainId = parseInt(chainId, chainId.startsWith("0x") ? 16 : 10);
80
+ }
81
+
82
+ const activeChainId = parseInt(currentChainId, 16);
83
+ if (Number.isNaN(activeChainId)) {
84
+ throw new Error(`Cannot sign messages for chainId "${chainId}", because MetaMask is switching networks.`);
85
+ }
86
+
87
+ if (chainId !== activeChainId) {
88
+ throw new Error(`Provided chainId "${chainId}" must match the active chainId "${activeChainId}"`);
89
+ }
90
+ }
91
+ }
92
+
93
+ export function validateEncryptionPublicKeyMessageData(messageData: EncryptionPublicKeyParams) {
94
+ const { from } = messageData;
95
+ validateAddress(from, "from");
96
+ }
97
+
98
+ export function validateDecryptedMessageData(messageData: DecryptMessageParams) {
99
+ const { from } = messageData;
100
+ validateAddress(from, "from");
101
+ }
102
+
103
+ export function parseDecryptMessageData(data: string): EthEncryptedData {
104
+ const stripped = stripHexPrefix(data);
105
+ const buffer = Buffer.from(stripped, "hex");
106
+ return JSON.parse(buffer.toString("utf8")) as EthEncryptedData;
107
+ }
@@ -0,0 +1,184 @@
1
+ import { BaseController, createEventEmitterProxy, createSwappableProxy, INetworkController } from "@toruslabs/base-controllers";
2
+ import { JRPCEngine, JRPCMiddleware, providerFromEngine, SafeEventEmitterProvider } from "@toruslabs/openlogin-jrpc";
3
+ import { Mutex } from "async-mutex";
4
+ import log from "loglevel";
5
+
6
+ import PollingBlockTracker from "../Block/PollingBlockTracker";
7
+ import { SUPPORTED_NETWORKS } from "../utils/constants";
8
+ import { EthereumNetworkConfig, EthereumNetworkState, EthereumProviderConfig } from "../utils/interfaces";
9
+ import { createEthereumMiddleware, IProviderHandlers } from "./createEthereumMiddleware";
10
+ import { createJsonRpcClient } from "./createJsonRpcClient";
11
+
12
+ export default class NetworkController
13
+ extends BaseController<EthereumNetworkConfig, EthereumNetworkState>
14
+ implements INetworkController<EthereumNetworkConfig, EthereumNetworkState>
15
+ {
16
+ name = "NetworkController";
17
+
18
+ providerProxy: SafeEventEmitterProvider;
19
+
20
+ blockTrackerProxy: PollingBlockTracker;
21
+
22
+ private mutex: Mutex = new Mutex();
23
+
24
+ private provider?: SafeEventEmitterProvider = null;
25
+
26
+ private blockTracker?: PollingBlockTracker = null;
27
+
28
+ private baseProviderHandlers: IProviderHandlers;
29
+
30
+ constructor({ config, state }: { config?: Partial<EthereumNetworkConfig>; state?: Partial<EthereumNetworkState> }) {
31
+ super({ config, state });
32
+
33
+ this.defaultState = {
34
+ chainId: "loading",
35
+ properties: { EIPS_1559: undefined },
36
+ providerConfig: SUPPORTED_NETWORKS.mainnet,
37
+ };
38
+
39
+ // when a new network is set,
40
+ // we set to loading first and
41
+ // then when connection succeeds,
42
+ // we update the network
43
+ this.initialize();
44
+ }
45
+
46
+ getNetworkIdentifier(): string {
47
+ return this.state.chainId;
48
+ }
49
+
50
+ getNetworkRPCUrl(): string {
51
+ return this.state.providerConfig.rpcTarget;
52
+ }
53
+
54
+ /**
55
+ * Called by orchestrator once while initializing the class
56
+ * @param providerHandlers - JRPC handlers for provider
57
+ * @returns - provider - Returns the providerProxy
58
+ */
59
+ public initializeProvider(providerHandlers: IProviderHandlers): SafeEventEmitterProvider {
60
+ this.baseProviderHandlers = providerHandlers;
61
+ this.configureProvider();
62
+ this.lookupNetwork(); // Not awaiting this, because we don't want to block the initialization
63
+ return this.providerProxy;
64
+ }
65
+
66
+ getProvider(): SafeEventEmitterProvider {
67
+ return this.providerProxy;
68
+ }
69
+
70
+ getBlockTracker(): PollingBlockTracker {
71
+ return this.blockTrackerProxy;
72
+ }
73
+
74
+ getProviderConfig(): EthereumProviderConfig {
75
+ return this.state.providerConfig;
76
+ }
77
+
78
+ setProviderConfig(config: EthereumProviderConfig): void {
79
+ this.update({
80
+ providerConfig: { ...config },
81
+ });
82
+ this.refreshNetwork();
83
+ }
84
+
85
+ async getEIP1559Compatibility(): Promise<boolean> {
86
+ const { EIPS_1559 } = this.state.properties;
87
+ // log.info('checking eip 1559 compatibility')
88
+ if (EIPS_1559 !== undefined) {
89
+ return EIPS_1559 as boolean;
90
+ }
91
+ const latestBlock = await this.blockTracker.getLatestBlock();
92
+ const supportsEIP1559 = latestBlock && latestBlock.baseFeePerGas !== undefined;
93
+ this.update({ properties: { EIPS_1559: supportsEIP1559 } });
94
+ return supportsEIP1559;
95
+ }
96
+
97
+ /**
98
+ * Refreshes the current network code
99
+ */
100
+ async lookupNetwork(): Promise<void> {
101
+ const { chainId, rpcTarget } = this.getProviderConfig();
102
+ if (!chainId || !rpcTarget || !this.provider) {
103
+ this.update({ chainId: "loading", properties: {} });
104
+ return;
105
+ }
106
+ const releaseLock = await this.mutex.acquire();
107
+ try {
108
+ // use eth_chainId
109
+ const [networkChainId] = await Promise.all([this.provider.request<never, string>({ method: "eth_chainId" }), this.getEIP1559Compatibility()]);
110
+ log.info("network fetched chain id", networkChainId);
111
+ // update chain ID
112
+ this.update({
113
+ chainId: networkChainId,
114
+ });
115
+ this.emit("networkDidChange");
116
+ } catch {
117
+ this.update({
118
+ chainId: "loading",
119
+ });
120
+ } finally {
121
+ releaseLock();
122
+ }
123
+ }
124
+
125
+ private configureProvider(): void {
126
+ const { chainId, rpcTarget, ...rest } = this.getProviderConfig();
127
+ if (!chainId || !rpcTarget) {
128
+ throw new Error("chainId and rpcTarget must be provider in providerConfig");
129
+ }
130
+ this.configureStandardProvider({ chainId, rpcTarget, ...rest });
131
+ }
132
+
133
+ private setNetworkClient({
134
+ networkMiddleware,
135
+ blockTracker,
136
+ }: {
137
+ networkMiddleware: JRPCMiddleware<unknown, unknown>;
138
+ blockTracker: PollingBlockTracker;
139
+ }): void {
140
+ const ethereumMiddleware = createEthereumMiddleware(this.baseProviderHandlers);
141
+ const engine = new JRPCEngine();
142
+ engine.push(ethereumMiddleware);
143
+ engine.push(networkMiddleware);
144
+ const provider = providerFromEngine(engine);
145
+ this.setProvider({ provider, blockTracker });
146
+ }
147
+
148
+ private setProvider({ provider, blockTracker }: { provider: SafeEventEmitterProvider; blockTracker: PollingBlockTracker }): void {
149
+ if (this.providerProxy) {
150
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
151
+ // @ts-ignore
152
+ this.providerProxy.setTarget(provider);
153
+ } else {
154
+ this.providerProxy = createSwappableProxy<SafeEventEmitterProvider>(provider);
155
+ }
156
+
157
+ if (this.blockTrackerProxy) {
158
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
159
+ // @ts-ignore
160
+ this.blockTrackerProxy.setTarget(blockTracker);
161
+ } else {
162
+ this.blockTrackerProxy = createEventEmitterProxy<PollingBlockTracker>(blockTracker, {
163
+ eventFilter: "skipInternal",
164
+ });
165
+ }
166
+
167
+ // set new provider and blockTracker
168
+ this.provider = provider;
169
+ provider.setMaxListeners(10);
170
+ this.blockTracker = blockTracker;
171
+ }
172
+
173
+ private configureStandardProvider(providerConfig: EthereumProviderConfig): void {
174
+ const networkClient = createJsonRpcClient(providerConfig);
175
+ log.info("networkClient", networkClient);
176
+ this.setNetworkClient(networkClient);
177
+ }
178
+
179
+ private refreshNetwork() {
180
+ this.update({ chainId: "loading", properties: {} });
181
+ this.configureProvider();
182
+ this.lookupNetwork();
183
+ }
184
+ }