@toruslabs/ethereum-controllers 5.11.0 → 6.0.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 (111) hide show
  1. package/dist/ethereumControllers.cjs.js +80 -431
  2. package/dist/ethereumControllers.esm.js +30 -349
  3. package/dist/ethereumControllers.umd.min.js +1 -1
  4. package/dist/ethereumControllers.umd.min.js.LICENSE.txt +7 -2
  5. package/dist/lib.cjs/Account/AccountTrackerController.js +160 -0
  6. package/dist/lib.cjs/Block/PollingBlockTracker.js +85 -0
  7. package/dist/lib.cjs/Currency/CurrencyController.js +111 -0
  8. package/dist/lib.cjs/Gas/GasFeeController.js +214 -0
  9. package/dist/lib.cjs/Gas/gasUtil.js +148 -0
  10. package/dist/lib.cjs/Keyring/KeyringController.js +93 -0
  11. package/dist/lib.cjs/Message/AbstractMessageController.js +107 -0
  12. package/dist/lib.cjs/Message/AddChainController.js +78 -0
  13. package/dist/lib.cjs/Message/MessageController.js +77 -0
  14. package/dist/lib.cjs/Message/PersonalMessageController.js +77 -0
  15. package/dist/lib.cjs/Message/SwitchChainController.js +78 -0
  16. package/dist/lib.cjs/Message/TypedMessageController.js +81 -0
  17. package/dist/lib.cjs/Message/utils.js +112 -0
  18. package/dist/lib.cjs/Network/NetworkController.js +201 -0
  19. package/dist/lib.cjs/Network/cacheIdentifier.js +112 -0
  20. package/dist/lib.cjs/Network/createEthereumMiddleware.js +302 -0
  21. package/dist/lib.cjs/Network/createJsonRpcClient.js +64 -0
  22. package/dist/lib.cjs/Nfts/NftHandler.js +180 -0
  23. package/dist/lib.cjs/Nfts/NftsController.js +213 -0
  24. package/dist/lib.cjs/Preferences/PreferencesController.js +476 -0
  25. package/dist/lib.cjs/Tokens/TokenHandler.js +51 -0
  26. package/dist/lib.cjs/Tokens/TokenRatesController.js +112 -0
  27. package/dist/lib.cjs/Tokens/TokensController.js +259 -0
  28. package/dist/lib.cjs/Transaction/NonceTracker.js +150 -0
  29. package/dist/lib.cjs/Transaction/PendingTransactionTracker.js +222 -0
  30. package/dist/lib.cjs/Transaction/TransactionController.js +515 -0
  31. package/dist/lib.cjs/Transaction/TransactionGasUtil.js +81 -0
  32. package/dist/lib.cjs/Transaction/TransactionStateHistoryHelper.js +42 -0
  33. package/dist/lib.cjs/Transaction/TransactionStateManager.js +296 -0
  34. package/dist/lib.cjs/Transaction/TransactionUtils.js +341 -0
  35. package/dist/lib.cjs/index.js +171 -0
  36. package/dist/lib.cjs/utils/abis.js +510 -0
  37. package/dist/lib.cjs/utils/constants.js +362 -0
  38. package/dist/lib.cjs/utils/contractAddresses.js +16 -0
  39. package/dist/lib.cjs/utils/conversionUtils.js +232 -0
  40. package/dist/lib.cjs/utils/helpers.js +244 -0
  41. package/dist/lib.cjs/utils/lodashUtils.js +25 -0
  42. package/dist/lib.esm/Account/AccountTrackerController.js +158 -0
  43. package/dist/lib.esm/Block/PollingBlockTracker.js +83 -0
  44. package/dist/lib.esm/Currency/CurrencyController.js +109 -0
  45. package/dist/lib.esm/Gas/GasFeeController.js +212 -0
  46. package/dist/lib.esm/Gas/gasUtil.js +141 -0
  47. package/dist/lib.esm/Keyring/KeyringController.js +91 -0
  48. package/dist/lib.esm/Message/AbstractMessageController.js +105 -0
  49. package/dist/lib.esm/Message/AddChainController.js +76 -0
  50. package/dist/lib.esm/Message/MessageController.js +75 -0
  51. package/dist/lib.esm/Message/PersonalMessageController.js +75 -0
  52. package/dist/lib.esm/Message/SwitchChainController.js +76 -0
  53. package/dist/lib.esm/Message/TypedMessageController.js +79 -0
  54. package/dist/lib.esm/Message/utils.js +105 -0
  55. package/dist/lib.esm/Network/NetworkController.js +199 -0
  56. package/dist/lib.esm/Network/cacheIdentifier.js +107 -0
  57. package/dist/lib.esm/Network/createEthereumMiddleware.js +289 -0
  58. package/dist/lib.esm/Network/createJsonRpcClient.js +60 -0
  59. package/dist/lib.esm/Nfts/NftHandler.js +178 -0
  60. package/dist/lib.esm/Nfts/NftsController.js +211 -0
  61. package/dist/lib.esm/Preferences/PreferencesController.js +474 -0
  62. package/dist/lib.esm/Tokens/TokenHandler.js +49 -0
  63. package/dist/lib.esm/Tokens/TokenRatesController.js +109 -0
  64. package/dist/lib.esm/Tokens/TokensController.js +257 -0
  65. package/dist/lib.esm/Transaction/NonceTracker.js +148 -0
  66. package/dist/lib.esm/Transaction/PendingTransactionTracker.js +220 -0
  67. package/dist/lib.esm/Transaction/TransactionController.js +513 -0
  68. package/dist/lib.esm/Transaction/TransactionGasUtil.js +79 -0
  69. package/dist/lib.esm/Transaction/TransactionStateHistoryHelper.js +38 -0
  70. package/dist/lib.esm/Transaction/TransactionStateManager.js +294 -0
  71. package/dist/lib.esm/Transaction/TransactionUtils.js +326 -0
  72. package/dist/lib.esm/index.js +33 -0
  73. package/dist/lib.esm/utils/abis.js +505 -0
  74. package/dist/lib.esm/utils/constants.js +323 -0
  75. package/dist/lib.esm/utils/contractAddresses.js +14 -0
  76. package/dist/lib.esm/utils/conversionUtils.js +218 -0
  77. package/dist/lib.esm/utils/helpers.js +227 -0
  78. package/dist/lib.esm/utils/lodashUtils.js +21 -0
  79. package/dist/types/Account/AccountTrackerController.d.ts +5 -5
  80. package/dist/types/Block/PollingBlockTracker.d.ts +1 -2
  81. package/dist/types/Currency/CurrencyController.d.ts +1 -1
  82. package/dist/types/Gas/GasFeeController.d.ts +3 -3
  83. package/dist/types/Gas/gasUtil.d.ts +1 -1
  84. package/dist/types/Keyring/KeyringController.d.ts +3 -5
  85. package/dist/types/Message/AbstractMessageController.d.ts +5 -6
  86. package/dist/types/Message/AddChainController.d.ts +4 -4
  87. package/dist/types/Message/MessageController.d.ts +4 -4
  88. package/dist/types/Message/PersonalMessageController.d.ts +4 -4
  89. package/dist/types/Message/SwitchChainController.d.ts +4 -4
  90. package/dist/types/Message/TypedMessageController.d.ts +6 -7
  91. package/dist/types/Message/utils.d.ts +2 -7
  92. package/dist/types/Network/NetworkController.d.ts +4 -4
  93. package/dist/types/Network/cacheIdentifier.d.ts +1 -1
  94. package/dist/types/Network/createEthereumMiddleware.d.ts +2 -18
  95. package/dist/types/Network/createJsonRpcClient.d.ts +2 -2
  96. package/dist/types/Nfts/NftsController.d.ts +2 -2
  97. package/dist/types/Preferences/PreferencesController.d.ts +4 -4
  98. package/dist/types/Tokens/TokensController.d.ts +3 -3
  99. package/dist/types/Transaction/NonceTracker.d.ts +5 -5
  100. package/dist/types/Transaction/PendingTransactionTracker.d.ts +5 -5
  101. package/dist/types/Transaction/TransactionController.d.ts +12 -12
  102. package/dist/types/Transaction/TransactionGasUtil.d.ts +4 -4
  103. package/dist/types/Transaction/TransactionStateManager.d.ts +3 -3
  104. package/dist/types/Transaction/TransactionUtils.d.ts +1 -1
  105. package/dist/types/index.d.ts +12 -14
  106. package/dist/types/utils/constants.d.ts +1 -5
  107. package/dist/types/utils/helpers.d.ts +4 -4
  108. package/dist/types/utils/interfaces.d.ts +43 -23
  109. package/package.json +7 -7
  110. package/dist/types/Message/DecryptMessageController.d.ts +0 -20
  111. package/dist/types/Message/EncryptionPublicKeyController.d.ts +0 -20
@@ -0,0 +1,211 @@
1
+ import _objectSpread from '@babel/runtime/helpers/objectSpread2';
2
+ import _defineProperty from '@babel/runtime/helpers/defineProperty';
3
+ import { BaseController } from '@toruslabs/base-controllers';
4
+ import deepmerge from 'deepmerge';
5
+ import { BrowserProvider } from 'ethers';
6
+ import log from 'loglevel';
7
+ import { SIMPLEHASH_SUPPORTED_CHAINS } from '../utils/constants.js';
8
+ import { idleTimeTracker } from '../utils/helpers.js';
9
+ import { NftHandler } from './NftHandler.js';
10
+
11
+ const DEFAULT_INTERVAL = 180 * 1000;
12
+ class NftsController extends BaseController {
13
+ constructor({
14
+ config,
15
+ state,
16
+ provider,
17
+ getCustomNfts,
18
+ getSimpleHashNfts,
19
+ onPreferencesStateChange,
20
+ onNetworkStateChange
21
+ }) {
22
+ super({
23
+ config,
24
+ state
25
+ });
26
+ _defineProperty(this, "name", "NftsController");
27
+ _defineProperty(this, "provider", void 0);
28
+ _defineProperty(this, "ethersProvider", void 0);
29
+ _defineProperty(this, "_timer", void 0);
30
+ _defineProperty(this, "getCustomNfts", void 0);
31
+ _defineProperty(this, "getSimpleHashNfts", void 0);
32
+ this.provider = provider;
33
+ this.ethersProvider = new BrowserProvider(this.provider, "any");
34
+ this.getCustomNfts = getCustomNfts;
35
+ this.getSimpleHashNfts = getSimpleHashNfts;
36
+ this.defaultConfig = {
37
+ interval: DEFAULT_INTERVAL,
38
+ selectedAddress: "",
39
+ chainId: ""
40
+ };
41
+ this.defaultState = {
42
+ nfts: {}
43
+ };
44
+ this.initialize();
45
+ onPreferencesStateChange(preferencesState => {
46
+ if (preferencesState.selectedAddress !== this.config.selectedAddress) {
47
+ this.configure({
48
+ selectedAddress: preferencesState.selectedAddress
49
+ });
50
+ this.restartNftDetection();
51
+ }
52
+ });
53
+ onNetworkStateChange(networkState => {
54
+ const {
55
+ chainId
56
+ } = networkState.providerConfig;
57
+ if (chainId !== this.config.chainId) {
58
+ this.configure({
59
+ chainId
60
+ });
61
+ this.restartNftDetection();
62
+ }
63
+ });
64
+ }
65
+ get userSelectedAddress() {
66
+ return this.config.selectedAddress;
67
+ }
68
+ get userNfts() {
69
+ var _this$state$nfts$this;
70
+ if (!this.userSelectedAddress) return [];
71
+ return (_this$state$nfts$this = this.state.nfts[this.userSelectedAddress]) !== null && _this$state$nfts$this !== void 0 ? _this$state$nfts$this : [];
72
+ }
73
+ get interval() {
74
+ return this.config.interval;
75
+ }
76
+ set interval(interval) {
77
+ if (this._timer) window.clearInterval(this._timer);
78
+ if (!interval) {
79
+ return;
80
+ }
81
+ this._timer = window.setInterval(() => {
82
+ if (!idleTimeTracker.checkIfIdle()) {
83
+ this.detectNewNfts();
84
+ this.refreshNftBalances();
85
+ }
86
+ }, interval);
87
+ }
88
+ startNftDetection(selectedAddress) {
89
+ this.configure({
90
+ selectedAddress
91
+ });
92
+ this.restartNftDetection();
93
+ }
94
+
95
+ /**
96
+ * Restart nft detection polling period and call detectNewNfts
97
+ * in case of address change or user session initialization.
98
+ *
99
+ */
100
+ restartNftDetection() {
101
+ if (!this.userSelectedAddress) {
102
+ return;
103
+ }
104
+ this.detectNewNfts();
105
+ this.refreshNftBalances();
106
+ this.config.interval = DEFAULT_INTERVAL;
107
+ }
108
+ detectNewNfts() {
109
+ const userAddress = this.userSelectedAddress;
110
+ if (!userAddress) return;
111
+ const currentChainId = this.config.chainId;
112
+ const nftsToDetect = []; // object[]
113
+ if (!currentChainId) {
114
+ this.update({
115
+ nfts: {
116
+ [userAddress]: [...nftsToDetect]
117
+ }
118
+ });
119
+ return;
120
+ }
121
+ if (this.getCustomNfts) {
122
+ const customNfts = this.getCustomNfts(userAddress);
123
+ const reducedNfts = customNfts.reduce((acc, x) => {
124
+ // first aggregate by contract address
125
+ if (x.network === currentChainId) {
126
+ const newAsset = {
127
+ description: "",
128
+ image: "",
129
+ name: "",
130
+ tokenBalance: "",
131
+ tokenId: x.nft_id,
132
+ customNftId: x.id.toString()
133
+ };
134
+ if (acc[x.nft_address]) {
135
+ acc[x.nft_address].assets.push(newAsset);
136
+ } else {
137
+ const objToPush = {
138
+ assets: [newAsset],
139
+ chainId: x.network,
140
+ contractAddress: x.nft_address,
141
+ contractName: "",
142
+ contractSymbol: "",
143
+ contractImage: "",
144
+ nftStandard: x.nft_contract_standard,
145
+ contractDescription: ""
146
+ };
147
+ acc[x.nft_address] = objToPush;
148
+ }
149
+ }
150
+ return acc;
151
+ }, {});
152
+ nftsToDetect.push(...Object.values(reducedNfts));
153
+ }
154
+ this.update({
155
+ nfts: {
156
+ [userAddress]: [...nftsToDetect]
157
+ }
158
+ });
159
+ }
160
+ async refreshNftBalances() {
161
+ const userAddress = this.userSelectedAddress;
162
+ if (userAddress === "") return;
163
+ const oldNfts = [...this.userNfts];
164
+ const nonZeroNfts = [];
165
+ try {
166
+ const currentChainId = this.config.chainId;
167
+ if (SIMPLEHASH_SUPPORTED_CHAINS.includes(currentChainId)) {
168
+ const simpleHashBalances = await this.getSimpleHashNfts(userAddress, currentChainId);
169
+ nonZeroNfts.push(...simpleHashBalances);
170
+ this.update({
171
+ nfts: {
172
+ [userAddress]: nonZeroNfts
173
+ }
174
+ });
175
+ }
176
+ if (oldNfts.length > 0) {
177
+ this.getNftBalancesUsingHandler(oldNfts);
178
+ }
179
+ } catch (error) {
180
+ log.error(error, "unable to fetch nft balances");
181
+ }
182
+ }
183
+ async getNftBalancesUsingHandler(customNfts) {
184
+ if (!this.userSelectedAddress) return;
185
+ const userAddress = this.userSelectedAddress;
186
+ const currentNetworkNfts = customNfts;
187
+ const promiseSettledResult = await Promise.allSettled(currentNetworkNfts.map(async x => {
188
+ try {
189
+ const tokenInstance = new NftHandler(_objectSpread(_objectSpread({}, x), {}, {
190
+ provider: this.ethersProvider
191
+ }));
192
+ const contractData = await tokenInstance.getContractMetadata();
193
+ const assetData = await Promise.allSettled(x.assets.map(y => tokenInstance.getNftMetadata(userAddress, y)));
194
+ return _objectSpread(_objectSpread({}, contractData), {}, {
195
+ assets: assetData.filter(z => z.status === "fulfilled").map(z => z.value)
196
+ });
197
+ } catch (error) {
198
+ log.warn("Invalid contract address while fetching", error);
199
+ return undefined;
200
+ }
201
+ }));
202
+ const nonZeroTokens = promiseSettledResult.filter(x => x.status === "fulfilled").map(x => x.value);
203
+ this.update({
204
+ nfts: {
205
+ [userAddress]: deepmerge(this.userNfts, nonZeroTokens)
206
+ }
207
+ });
208
+ }
209
+ }
210
+
211
+ export { NftsController };
@@ -0,0 +1,474 @@
1
+ import _defineProperty from '@babel/runtime/helpers/defineProperty';
2
+ import { stripHexPrefix } from '@ethereumjs/util';
3
+ import { BasePreferencesController, isUnauthorizedError, TransactionStatus } from '@toruslabs/base-controllers';
4
+ import { Mutex } from 'async-mutex';
5
+ import log from 'loglevel';
6
+ import { ETHERSCAN_SUPPORTED_CHAINS, SUPPORTED_NETWORKS } from '../utils/constants.js';
7
+ import { formatPastTx, addEtherscanTransactions, getEthTxStatus, formatTime, formatDate } from '../utils/helpers.js';
8
+
9
+ class PreferencesController extends BasePreferencesController {
10
+ constructor({
11
+ config,
12
+ state,
13
+ provider,
14
+ signAuthMessage,
15
+ getProviderConfig,
16
+ setProviderConfig,
17
+ validateSignMessage
18
+ }) {
19
+ super({
20
+ config,
21
+ state,
22
+ defaultPreferences: {
23
+ formattedPastTransactions: [],
24
+ fetchedPastTx: [],
25
+ paymentTx: [],
26
+ etherscanTransactions: []
27
+ },
28
+ signAuthMessage,
29
+ validateSignMessage
30
+ });
31
+ _defineProperty(this, "_handle", void 0);
32
+ _defineProperty(this, "_mutex", new Mutex());
33
+ _defineProperty(this, "getProviderConfig", void 0);
34
+ _defineProperty(this, "setProviderConfig", void 0);
35
+ _defineProperty(this, "provider", void 0);
36
+ this.provider = provider;
37
+ this.getProviderConfig = getProviderConfig;
38
+ this.setProviderConfig = setProviderConfig;
39
+ }
40
+ async poll(interval) {
41
+ var _this$getAddressState;
42
+ const releaseLock = await this._mutex.acquire();
43
+ if (interval) this.configure({
44
+ pollInterval: interval
45
+ });
46
+ if (this._handle) window.clearTimeout(this._handle);
47
+ // call here
48
+ const storeSelectedAddress = this.state.selectedAddress;
49
+ if (!storeSelectedAddress) return;
50
+ if (!((_this$getAddressState = this.getAddressState(storeSelectedAddress)) !== null && _this$getAddressState !== void 0 && _this$getAddressState.jwtToken)) return;
51
+ // This should never throw
52
+ await this.sync(storeSelectedAddress);
53
+ releaseLock();
54
+ this._handle = window.setTimeout(() => {
55
+ this.poll(this.config.pollInterval);
56
+ }, this.config.pollInterval);
57
+ }
58
+ async initPreferences(params) {
59
+ const {
60
+ address,
61
+ jwtToken,
62
+ calledFromEmbed,
63
+ userInfo,
64
+ rehydrate,
65
+ locale = "en",
66
+ type,
67
+ signatures,
68
+ web3AuthClientId,
69
+ web3AuthNetwork,
70
+ loginMode,
71
+ sessionPubKey
72
+ } = params;
73
+ await super.init({
74
+ address,
75
+ userInfo,
76
+ idToken: jwtToken,
77
+ type,
78
+ metadata: {
79
+ email: userInfo.email,
80
+ signatures,
81
+ network: web3AuthNetwork
82
+ }
83
+ });
84
+ const {
85
+ aggregateVerifier,
86
+ verifier,
87
+ verifierId
88
+ } = userInfo || {};
89
+ const userExists = await this.sync(address);
90
+ if (!userExists) {
91
+ const accountState = this.getAddressState(address);
92
+ await this.createUser({
93
+ selectedCurrency: accountState.selectedCurrency,
94
+ theme: accountState.theme,
95
+ verifier: aggregateVerifier || verifier,
96
+ verifierId,
97
+ locale,
98
+ address,
99
+ type,
100
+ web3AuthNetwork
101
+ });
102
+ }
103
+ this.storeUserLogin({
104
+ verifier: aggregateVerifier || verifier,
105
+ verifierId,
106
+ options: {
107
+ calledFromEmbed,
108
+ rehydrate
109
+ },
110
+ address,
111
+ web3AuthClientId,
112
+ web3AuthNetwork,
113
+ sessionPubKey,
114
+ loginMode
115
+ });
116
+ }
117
+ getSelectedAddress() {
118
+ return this.state.selectedAddress;
119
+ }
120
+ async sync(address) {
121
+ try {
122
+ const user = await this.getUser(address);
123
+ if (user) {
124
+ const {
125
+ default_currency: defaultCurrency,
126
+ contacts,
127
+ theme,
128
+ locale,
129
+ public_address: userPublicAddress,
130
+ default_public_address: defaultPublicAddress,
131
+ customNetworks,
132
+ customTokens,
133
+ customNfts,
134
+ account_type: accountType
135
+ } = user || {};
136
+
137
+ // update latest data in state.
138
+ this.updateState({
139
+ contacts,
140
+ theme,
141
+ selectedCurrency: defaultCurrency,
142
+ locale,
143
+ defaultPublicAddress: defaultPublicAddress || userPublicAddress,
144
+ customTokens,
145
+ customNfts,
146
+ customNetworks,
147
+ accountType: accountType
148
+ }, address);
149
+ return true;
150
+ }
151
+ return false;
152
+ } catch (error) {
153
+ if (isUnauthorizedError(error)) {
154
+ throw error;
155
+ }
156
+ log.error(error);
157
+ return false;
158
+ } finally {
159
+ this.getWalletOrders(address).then(walletTx => {
160
+ // eslint-disable-next-line promise/always-return
161
+ if (walletTx && walletTx.length > 0) {
162
+ this.updateState({
163
+ fetchedPastTx: [...walletTx]
164
+ }, address);
165
+ this.calculatePastTx(walletTx, address);
166
+ }
167
+ }).catch(error => log.error(error));
168
+ }
169
+ }
170
+ async patchNewTx(tx, address) {
171
+ var _this$getAddressState2;
172
+ const formattedTx = formatPastTx({
173
+ transaction: tx,
174
+ blockExplorerUrl: this.getBlockExplorerUrl()
175
+ });
176
+ const storePastTx = ((_this$getAddressState2 = this.getAddressState(address)) === null || _this$getAddressState2 === void 0 ? void 0 : _this$getAddressState2.formattedPastTransactions) || [];
177
+ const duplicateIndex = storePastTx.findIndex(x => x.transaction_hash === tx.transaction_hash && x.chainId === tx.chain_id);
178
+ if (tx.status === TransactionStatus.submitted || tx.status === TransactionStatus.confirmed) {
179
+ if (duplicateIndex === -1) {
180
+ var _tx$to;
181
+ // No duplicate found
182
+
183
+ const finalTx = this.cancelTxCalculate([...storePastTx, formattedTx]);
184
+ tx.is_cancel = formattedTx.is_cancel;
185
+ tx.to = (_tx$to = tx.to) === null || _tx$to === void 0 ? void 0 : _tx$to.toLowerCase();
186
+ tx.from = tx.from.toLowerCase();
187
+ this.updateState({
188
+ formattedPastTransactions: finalTx
189
+ }, address);
190
+ this.postPastTx(tx, address);
191
+ } else {
192
+ // avoid overriding is_cancel
193
+ formattedTx.is_cancel = storePastTx[duplicateIndex].is_cancel;
194
+ storePastTx[duplicateIndex] = formattedTx;
195
+ this.updateState({
196
+ formattedPastTransactions: this.cancelTxCalculate([...storePastTx])
197
+ }, address);
198
+ }
199
+ }
200
+ }
201
+ recalculatePastTx(address) {
202
+ // This triggers store update which calculates past Tx status for that network
203
+ const selectedAddress = address || this.state.selectedAddress;
204
+ const state = this.getAddressState(selectedAddress);
205
+ if (!(state !== null && state !== void 0 && state.fetchedPastTx)) return;
206
+ this.calculatePastTx(state.fetchedPastTx, selectedAddress);
207
+ }
208
+ async refetchEtherscanTx(address) {
209
+ var _this$getAddressState3;
210
+ const selectedAddress = address || this.state.selectedAddress;
211
+ if (!selectedAddress) return [];
212
+ const lowerCaseSelectedAddress = selectedAddress === null || selectedAddress === void 0 ? void 0 : selectedAddress.toLowerCase();
213
+ if ((_this$getAddressState3 = this.getAddressState(selectedAddress)) !== null && _this$getAddressState3 !== void 0 && _this$getAddressState3.jwtToken) {
214
+ const {
215
+ chainId
216
+ } = this.getProviderConfig();
217
+ if (ETHERSCAN_SUPPORTED_CHAINS.includes(chainId)) {
218
+ const etherscanTxn = await this.fetchEtherscanTx({
219
+ selectedAddress,
220
+ chainId: this.getProviderConfig().chainId
221
+ });
222
+ const finalEthScanTxn = await addEtherscanTransactions({
223
+ txn: etherscanTxn,
224
+ lowerCaseSelectedAddress,
225
+ provider: this.provider,
226
+ chainId,
227
+ blockExplorerUrl: this.getBlockExplorerUrl()
228
+ });
229
+ log.info("Formatted Etherscan Response", finalEthScanTxn);
230
+ this.updateState({
231
+ etherscanTransactions: finalEthScanTxn
232
+ });
233
+ return etherscanTxn;
234
+ }
235
+ }
236
+ }
237
+ async fetchEtherscanTx(parameters) {
238
+ try {
239
+ const response = await this.wsApiClient.authGet(`etherscan?chainId=${parameters.chainId}`, this.authCredentials(parameters.selectedAddress));
240
+ log.info("Etherscan Response API", response);
241
+ return response.success ? response.data : [];
242
+ } catch (error) {
243
+ log.error("unable to fetch etherscan tx", error);
244
+ return [];
245
+ }
246
+ }
247
+ async getEtherScanTokens(address, chainId) {
248
+ const selectedAddress = address;
249
+ const result = await this.wsApiClient.authGet(`tokens?chainId=${chainId}&address=${selectedAddress}`, this.authCredentials());
250
+ return result.data;
251
+ }
252
+ async getSimpleHashNfts(address, chainId) {
253
+ const selectedAddress = address;
254
+ const result = await this.wsApiClient.authGet(`nfts?chainId=${chainId}&address=${selectedAddress}`, this.authCredentials());
255
+ return result.data;
256
+ }
257
+ getCustomTokens(address) {
258
+ var _this$getAddressState4, _this$getAddressState5;
259
+ return (_this$getAddressState4 = (_this$getAddressState5 = this.getAddressState(address)) === null || _this$getAddressState5 === void 0 ? void 0 : _this$getAddressState5.customTokens) !== null && _this$getAddressState4 !== void 0 ? _this$getAddressState4 : [];
260
+ }
261
+ getCustomNfts(address) {
262
+ var _this$getAddressState6, _this$getAddressState7;
263
+ return (_this$getAddressState6 = (_this$getAddressState7 = this.getAddressState(address)) === null || _this$getAddressState7 === void 0 ? void 0 : _this$getAddressState7.customNfts) !== null && _this$getAddressState6 !== void 0 ? _this$getAddressState6 : [];
264
+ }
265
+ isChainIdSupported(address, chainId) {
266
+ const approveChainOptions = this.getChainOptions(address);
267
+ const providerConfig = approveChainOptions.find(x => stripHexPrefix(x.chainId) === chainId);
268
+ return !!providerConfig;
269
+ }
270
+ async addChain(network) {
271
+ const approveChainOptions = this.getChainOptions();
272
+ const providerConfig = approveChainOptions.find(x => x.chainId === network.chainId);
273
+ if (providerConfig) return;
274
+ const newNetwork = {
275
+ displayName: network.chainName,
276
+ rpcTarget: network.rpcUrls[0],
277
+ ticker: network.nativeCurrency.symbol,
278
+ chainId: network.chainId,
279
+ blockExplorerUrl: network.blockExplorerUrls[0],
280
+ tickerName: network.nativeCurrency.name,
281
+ logo: network.nativeCurrency.symbol
282
+ };
283
+ const isSuccess = await this.addCustomNetwork({
284
+ network: newNetwork
285
+ });
286
+ if (!isSuccess) throw new Error("unable to add custom network");
287
+ }
288
+ switchChain(data) {
289
+ const chainOptions = this.getChainOptions();
290
+ const providerConfig = chainOptions.find(x => x.chainId === data.chainId);
291
+ if (providerConfig) {
292
+ this.setProviderConfig(providerConfig);
293
+ } else {
294
+ throw new Error(`chainId ${data.chainId} is not supported`);
295
+ }
296
+ }
297
+
298
+ // Custom Network methods
299
+ async addCustomNetwork({
300
+ network
301
+ }) {
302
+ try {
303
+ const {
304
+ selectedAddress
305
+ } = this.state;
306
+ const payload = {
307
+ network_name: network.displayName,
308
+ rpc_url: network.rpcTarget,
309
+ chain_id: network.chainId,
310
+ symbol: network.ticker,
311
+ block_explorer_url: network.blockExplorerUrl || undefined,
312
+ is_testnet: network.isTestnet || false,
313
+ logo: network.logo,
314
+ symbol_name: network.tickerName
315
+ };
316
+ const res = await this.wsApiClient.authPost("customnetwork", payload, this.authCredentials(selectedAddress), {
317
+ useAPIKey: true
318
+ });
319
+ await this.sync(selectedAddress);
320
+ return res.data.id;
321
+ } catch {
322
+ log.error("error adding custom network");
323
+ return null;
324
+ }
325
+ }
326
+ async deleteCustomNetwork(id) {
327
+ try {
328
+ const {
329
+ selectedAddress
330
+ } = this.state;
331
+ await this.wsApiClient.authRemove(`customnetwork/${id}`, {}, this.authCredentials(selectedAddress), {
332
+ useAPIKey: true
333
+ });
334
+ await this.sync(selectedAddress);
335
+ return true;
336
+ } catch {
337
+ log.error("error deleting custom network");
338
+ return false;
339
+ }
340
+ }
341
+ async editCustomNetwork({
342
+ network,
343
+ id
344
+ }) {
345
+ try {
346
+ const {
347
+ selectedAddress
348
+ } = this.state;
349
+ const payload = {
350
+ network_name: network.displayName,
351
+ rpc_url: network.rpcTarget,
352
+ chain_id: network.chainId,
353
+ symbol: network.ticker || undefined,
354
+ block_explorer_url: network.blockExplorerUrl || undefined,
355
+ is_testnet: network.isTestnet || false
356
+ };
357
+ await this.wsApiClient.authPatch(`customnetwork/${id}`, payload, this.authCredentials(selectedAddress), {
358
+ useAPIKey: true
359
+ });
360
+ await this.sync(selectedAddress);
361
+ return true;
362
+ } catch {
363
+ log.error("error editing custom network");
364
+ return false;
365
+ }
366
+ }
367
+ getChainOptions(address = this.state.selectedAddress) {
368
+ var _identities$address$c, _identities$address;
369
+ const {
370
+ identities
371
+ } = this.state;
372
+ const customNetworks = (_identities$address$c = (_identities$address = identities[address]) === null || _identities$address === void 0 ? void 0 : _identities$address.customNetworks) !== null && _identities$address$c !== void 0 ? _identities$address$c : [];
373
+ const custom = Object.values(customNetworks).reduce((chains, network) => {
374
+ const networkItem = {
375
+ blockExplorerUrl: network.block_explorer_url,
376
+ chainId: network.chain_id,
377
+ displayName: network.network_name,
378
+ logo: "eth.svg",
379
+ rpcTarget: network.rpc_url,
380
+ ticker: network.symbol,
381
+ tickerName: network.symbol.toUpperCase(),
382
+ isCustom: true,
383
+ id: network.id
384
+ };
385
+ if (Object.keys(SUPPORTED_NETWORKS).includes(networkItem.chainId)) return chains;
386
+ chains.push(networkItem);
387
+ return chains;
388
+ }, []);
389
+ const supported = Object.values(SUPPORTED_NETWORKS).reduce((chains, network) => {
390
+ chains.push(network);
391
+ return chains;
392
+ }, []);
393
+ return [...supported, ...custom];
394
+ }
395
+ getBlockExplorerUrl() {
396
+ const supportedNetworks = this.getChainOptions();
397
+ const network = supportedNetworks.find(x => x.chainId === this.getProviderConfig().chainId);
398
+ if (!network) return "";
399
+ return `${network.blockExplorerUrl}`;
400
+ }
401
+ async calculatePastTx(txs, address) {
402
+ const pastTx = [];
403
+ const pendingTx = [];
404
+ const lowerCaseSelectedAddress = address.toLowerCase();
405
+ const supportedNetworks = this.getChainOptions(address);
406
+ const supportedNetwork = supportedNetworks.find(x => x.chainId === this.getProviderConfig().chainId);
407
+ for (const x of txs) {
408
+ var _x$to;
409
+ if ((supportedNetwork === null || supportedNetwork === void 0 ? void 0 : supportedNetwork.chainId) === x.chain_id && x.to && x.from && (lowerCaseSelectedAddress === x.from.toLowerCase() || lowerCaseSelectedAddress === ((_x$to = x.to) === null || _x$to === void 0 ? void 0 : _x$to.toLowerCase()))) {
410
+ if (x.status !== "confirmed") {
411
+ pendingTx.push(x);
412
+ } else {
413
+ const finalObject = formatPastTx({
414
+ transaction: x,
415
+ lowerCaseSelectedAddress,
416
+ blockExplorerUrl: this.getBlockExplorerUrl()
417
+ });
418
+ pastTx.push(finalObject);
419
+ }
420
+ }
421
+ }
422
+ const pendingTxPromises = pendingTx.map(x => getEthTxStatus(x.transaction_hash, this.provider).catch(error => log.error(error)));
423
+ const resolvedTxStatuses = await Promise.all(pendingTxPromises);
424
+ for (const [index, element] of pendingTx.entries()) {
425
+ const finalObject = formatPastTx({
426
+ transaction: element,
427
+ lowerCaseSelectedAddress,
428
+ blockExplorerUrl: this.getBlockExplorerUrl()
429
+ });
430
+ finalObject.status = resolvedTxStatuses[index] || TransactionStatus.submitted;
431
+ pastTx.push(finalObject);
432
+ if (lowerCaseSelectedAddress === element.from.toLowerCase() && finalObject.status && finalObject.status !== element.status) this.patchPastTx({
433
+ id: element.id,
434
+ status: finalObject.status
435
+ }, address);
436
+ }
437
+ const finalTx = this.cancelTxCalculate(pastTx);
438
+ this.updateState({
439
+ formattedPastTransactions: [...finalTx]
440
+ }, address);
441
+ }
442
+ cancelTxCalculate(pastTx) {
443
+ const nonceMap = {};
444
+ for (const x of pastTx) {
445
+ if (!nonceMap[x.nonce]) nonceMap[x.nonce] = [x];else {
446
+ nonceMap[x.nonce].push(x);
447
+ }
448
+ }
449
+ for (const [, value] of Object.entries(nonceMap)) {
450
+ // has duplicate
451
+ if (value.length > 1) {
452
+ // get latest and mark it as is_cancel
453
+ const latestTxs = value.sort((a, b) => {
454
+ const aDate = new Date(a.date).getTime();
455
+ const bDate = new Date(b.date).getTime();
456
+ return bDate - aDate;
457
+ });
458
+ const latestCancelTx = latestTxs[0];
459
+ latestCancelTx.is_cancel = true;
460
+ latestTxs.slice(1).forEach(x => {
461
+ x.hasCancel = true;
462
+ x.status = latestCancelTx.status === "confirmed" ? TransactionStatus.cancelled : TransactionStatus.cancelling;
463
+ x.cancelDateInitiated = `${formatTime(new Date(latestCancelTx.date).getTime())} - ${formatDate(latestCancelTx.date)}`;
464
+ x.etherscanLink = latestCancelTx.etherscanLink;
465
+ x.cancelGas = latestCancelTx.gas;
466
+ x.cancelGasPrice = latestCancelTx.gasPrice;
467
+ });
468
+ }
469
+ }
470
+ return pastTx;
471
+ }
472
+ }
473
+
474
+ export { PreferencesController };