@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,212 @@
1
+ import _defineProperty from '@babel/runtime/helpers/defineProperty';
2
+ import { isHexString, addHexPrefix } from '@ethereumjs/util';
3
+ import { BaseController, cloneDeep } from '@toruslabs/base-controllers';
4
+ import log from 'loglevel';
5
+ import { GAS_ESTIMATE_TYPES } from '../utils/constants.js';
6
+ import { idleTimeTracker } from '../utils/helpers.js';
7
+ import { fetchGasEstimates, fetchEthGasPriceEstimate, fetchLegacyGasPriceEstimates, fetchGasEstimatesViaEthFeeHistory, calculateTimeEstimate } from './gasUtil.js';
8
+
9
+ const GAS_FEE_API = "https://mock-gas-server.herokuapp.com/";
10
+ const LEGACY_GAS_PRICES_API_URL = "https://api.metaswap.codefi.network/gasPrices";
11
+ /**
12
+ * Returns gas prices in dec gwei
13
+ */
14
+ class GasFeeController extends BaseController {
15
+ constructor({
16
+ config,
17
+ state,
18
+ getNetworkIdentifier,
19
+ getProvider,
20
+ fetchGasEstimates: fetchGasEstimates$1 = fetchGasEstimates,
21
+ fetchEthGasPriceEstimate: fetchEthGasPriceEstimate$1 = fetchEthGasPriceEstimate,
22
+ fetchLegacyGasPriceEstimates: fetchLegacyGasPriceEstimates$1 = fetchLegacyGasPriceEstimates,
23
+ fetchGasEstimatesViaEthFeeHistory: fetchGasEstimatesViaEthFeeHistory$1 = fetchGasEstimatesViaEthFeeHistory,
24
+ getCurrentNetworkLegacyGasAPICompatibility,
25
+ getCurrentNetworkEIP1559Compatibility,
26
+ getCurrentAccountEIP1559Compatibility,
27
+ onNetworkStateChange
28
+ }) {
29
+ super({
30
+ config,
31
+ state
32
+ });
33
+ _defineProperty(this, "name", "GasFeeController");
34
+ // https://0x.org/docs/introduction/0x-cheat-sheet#swap-api-endpoints
35
+ _defineProperty(this, "API_SUPPORTED_CHAINIDS", new Set(["0x1", "0x5", "0xa4b1", "0xa86a", "0x2105", "0x38", "0xfa", "0xa", "0x89"]));
36
+ _defineProperty(this, "intervalId", void 0);
37
+ _defineProperty(this, "provider", void 0);
38
+ _defineProperty(this, "currentChainId", void 0);
39
+ _defineProperty(this, "getNetworkIdentifier", void 0);
40
+ _defineProperty(this, "getProvider", void 0);
41
+ _defineProperty(this, "fetchGasEstimates", void 0);
42
+ _defineProperty(this, "fetchGasEstimatesViaEthFeeHistory", void 0);
43
+ _defineProperty(this, "fetchEthGasPriceEstimate", void 0);
44
+ _defineProperty(this, "fetchLegacyGasPriceEstimates", void 0);
45
+ _defineProperty(this, "getCurrentNetworkEIP1559Compatibility", void 0);
46
+ _defineProperty(this, "getCurrentAccountEIP1559Compatibility", void 0);
47
+ _defineProperty(this, "getCurrentNetworkLegacyGasAPICompatibility", void 0);
48
+ this.getNetworkIdentifier = getNetworkIdentifier;
49
+ this.getProvider = getProvider;
50
+ this.fetchGasEstimates = fetchGasEstimates$1;
51
+ this.fetchEthGasPriceEstimate = fetchEthGasPriceEstimate$1;
52
+ this.fetchLegacyGasPriceEstimates = fetchLegacyGasPriceEstimates$1;
53
+ this.getCurrentNetworkEIP1559Compatibility = getCurrentNetworkEIP1559Compatibility;
54
+ this.getCurrentNetworkLegacyGasAPICompatibility = getCurrentNetworkLegacyGasAPICompatibility;
55
+ this.getCurrentAccountEIP1559Compatibility = getCurrentAccountEIP1559Compatibility;
56
+ this.fetchGasEstimatesViaEthFeeHistory = fetchGasEstimatesViaEthFeeHistory$1;
57
+ this.defaultConfig = {
58
+ interval: 30000,
59
+ legacyAPIEndpoint: LEGACY_GAS_PRICES_API_URL,
60
+ EIP1559APIEndpoint: GAS_FEE_API
61
+ };
62
+ this.defaultState = {
63
+ gasFeeEstimates: {},
64
+ estimatedGasFeeTimeBounds: {},
65
+ gasEstimateType: GAS_ESTIMATE_TYPES.NONE
66
+ };
67
+ // Initialize.
68
+ this.currentChainId = this.getNetworkIdentifier();
69
+ this.provider = this.getProvider();
70
+ this.initialize();
71
+ onNetworkStateChange(() => {
72
+ this.onNetworkStateChange();
73
+ });
74
+ }
75
+ async onNetworkStateChange() {
76
+ this.provider = this.getProvider();
77
+ const newChainId = this.getNetworkIdentifier();
78
+ if (this.currentChainId !== newChainId) {
79
+ this.currentChainId = newChainId;
80
+ await this.fetchGasFeeEstimates();
81
+ }
82
+ }
83
+ async resetPolling() {
84
+ this.stopPolling();
85
+ await this.getGasFeeEstimatesAndStartPolling();
86
+ }
87
+ async fetchGasFeeEstimates() {
88
+ return this._fetchGasFeeEstimateData();
89
+ }
90
+ async getGasFeeEstimatesAndStartPolling() {
91
+ await this._fetchGasFeeEstimateData();
92
+ this._startPolling();
93
+ }
94
+ disconnectPoller() {
95
+ this.stopPolling();
96
+ }
97
+
98
+ /**
99
+ * Prepare to discard this controller.
100
+ *
101
+ * This stops any active polling.
102
+ */
103
+ destroy() {
104
+ this.stopPolling();
105
+ }
106
+ stopPolling() {
107
+ if (this.intervalId) {
108
+ clearInterval(this.intervalId);
109
+ }
110
+ this.resetState();
111
+ }
112
+
113
+ /**
114
+ * Gets and sets gasFeeEstimates in state
115
+ *
116
+ * @returns GasFeeEstimates
117
+ */
118
+ async _fetchGasFeeEstimateData() {
119
+ let isEIP1559Compatible;
120
+ const isLegacyGasAPICompatible = this.getCurrentNetworkLegacyGasAPICompatibility();
121
+ const chainId = this.getNetworkIdentifier();
122
+ if (chainId === "loading") return;
123
+ let chainIdInt;
124
+ if (typeof chainId === "string" && isHexString(addHexPrefix(chainId))) {
125
+ chainIdInt = Number.parseInt(chainId, 16);
126
+ }
127
+ try {
128
+ isEIP1559Compatible = await this.getEIP1559Compatibility();
129
+ log.info("eip1559 compatible", isEIP1559Compatible);
130
+ } catch (error) {
131
+ log.warn(error);
132
+ isEIP1559Compatible = false;
133
+ }
134
+ let newState = cloneDeep(this.defaultState);
135
+ try {
136
+ if (isEIP1559Compatible) {
137
+ let estimates;
138
+ try {
139
+ if (this.API_SUPPORTED_CHAINIDS.has(chainId)) {
140
+ estimates = await this.fetchGasEstimates(this.config.EIP1559APIEndpoint.replace("<chain_id>", `${chainIdInt}`));
141
+ } else {
142
+ throw new Error("ChainId not supported by api");
143
+ }
144
+ } catch (error) {
145
+ estimates = await this.fetchGasEstimatesViaEthFeeHistory(this.provider);
146
+ }
147
+ const {
148
+ suggestedMaxPriorityFeePerGas,
149
+ suggestedMaxFeePerGas
150
+ } = estimates.medium;
151
+ const estimatedGasFeeTimeBounds = this.getTimeEstimate(suggestedMaxPriorityFeePerGas, suggestedMaxFeePerGas);
152
+ newState = {
153
+ gasFeeEstimates: estimates,
154
+ estimatedGasFeeTimeBounds,
155
+ gasEstimateType: GAS_ESTIMATE_TYPES.FEE_MARKET
156
+ };
157
+ } else if (isLegacyGasAPICompatible) {
158
+ const estimates = await this.fetchLegacyGasPriceEstimates(this.config.legacyAPIEndpoint.replace("<chain_id>", `${chainIdInt}`));
159
+ newState = {
160
+ gasFeeEstimates: estimates,
161
+ estimatedGasFeeTimeBounds: {},
162
+ gasEstimateType: GAS_ESTIMATE_TYPES.LEGACY
163
+ };
164
+ } else {
165
+ throw new Error("Main gas fee/price estimation failed. Use fallback");
166
+ }
167
+ } catch {
168
+ try {
169
+ const estimates = await this.fetchEthGasPriceEstimate(this.provider);
170
+ newState = {
171
+ gasFeeEstimates: estimates,
172
+ estimatedGasFeeTimeBounds: {},
173
+ gasEstimateType: GAS_ESTIMATE_TYPES.ETH_GASPRICE
174
+ };
175
+ } catch (error) {
176
+ throw new Error(`Gas fee/price estimation failed. Message: ${error.message}`);
177
+ }
178
+ }
179
+ this.update(newState);
180
+ return newState;
181
+ }
182
+ async _startPolling() {
183
+ this._poll();
184
+ }
185
+ async _poll() {
186
+ if (this.intervalId) {
187
+ window.clearInterval(this.intervalId);
188
+ }
189
+ this.intervalId = window.setInterval(async () => {
190
+ if (!idleTimeTracker.checkIfIdle()) {
191
+ await this._fetchGasFeeEstimateData();
192
+ }
193
+ }, this.config.interval);
194
+ }
195
+ resetState() {
196
+ this.update(cloneDeep(this.defaultState));
197
+ }
198
+ async getEIP1559Compatibility() {
199
+ var _this$getCurrentAccou, _this$getCurrentAccou2;
200
+ const currentNetworkIsEIP1559Compatible = await this.getCurrentNetworkEIP1559Compatibility();
201
+ const currentAccountIsEIP1559Compatible = (_this$getCurrentAccou = (_this$getCurrentAccou2 = this.getCurrentAccountEIP1559Compatibility) === null || _this$getCurrentAccou2 === void 0 ? void 0 : _this$getCurrentAccou2.call(this)) !== null && _this$getCurrentAccou !== void 0 ? _this$getCurrentAccou : true;
202
+ return currentNetworkIsEIP1559Compatible && currentAccountIsEIP1559Compatible;
203
+ }
204
+ getTimeEstimate(maxPriorityFeePerGas, maxFeePerGas) {
205
+ if (!this.state.gasFeeEstimates || this.state.gasEstimateType !== GAS_ESTIMATE_TYPES.FEE_MARKET) {
206
+ return {};
207
+ }
208
+ return calculateTimeEstimate(maxPriorityFeePerGas, maxFeePerGas, this.state.gasFeeEstimates);
209
+ }
210
+ }
211
+
212
+ export { GasFeeController };
@@ -0,0 +1,141 @@
1
+ import _objectSpread from '@babel/runtime/helpers/objectSpread2';
2
+ import { get } from '@toruslabs/http-helpers';
3
+ import BigNumber from 'bignumber.js';
4
+ import { METHOD_TYPES } from '../utils/constants.js';
5
+ import { hexWEIToDecGWEI, decGWEIToHexWEI } from '../utils/conversionUtils.js';
6
+
7
+ function normalizeGWEIDecimalNumbers(n) {
8
+ const numberAsWEIHex = decGWEIToHexWEI(new BigNumber(n));
9
+ const numberAsGWEI = hexWEIToDecGWEI(numberAsWEIHex);
10
+ return numberAsGWEI;
11
+ }
12
+ async function fetchGasEstimates(url) {
13
+ const estimates = await get(url);
14
+ const normalizedEstimates = {
15
+ estimatedBaseFee: normalizeGWEIDecimalNumbers(estimates.estimatedBaseFee).toString(10),
16
+ low: _objectSpread(_objectSpread({}, estimates.low), {}, {
17
+ suggestedMaxPriorityFeePerGas: normalizeGWEIDecimalNumbers(estimates.low.suggestedMaxPriorityFeePerGas).toString(10),
18
+ suggestedMaxFeePerGas: normalizeGWEIDecimalNumbers(estimates.low.suggestedMaxFeePerGas).toString(10)
19
+ }),
20
+ medium: _objectSpread(_objectSpread({}, estimates.medium), {}, {
21
+ suggestedMaxPriorityFeePerGas: normalizeGWEIDecimalNumbers(estimates.medium.suggestedMaxPriorityFeePerGas).toString(10),
22
+ suggestedMaxFeePerGas: normalizeGWEIDecimalNumbers(estimates.medium.suggestedMaxFeePerGas).toString(10)
23
+ }),
24
+ high: _objectSpread(_objectSpread({}, estimates.high), {}, {
25
+ suggestedMaxPriorityFeePerGas: normalizeGWEIDecimalNumbers(estimates.high.suggestedMaxPriorityFeePerGas).toString(10),
26
+ suggestedMaxFeePerGas: normalizeGWEIDecimalNumbers(estimates.high.suggestedMaxFeePerGas).toString(10)
27
+ })
28
+ };
29
+ return normalizedEstimates;
30
+ }
31
+ async function fetchGasEstimatesViaEthFeeHistory(provider) {
32
+ const noOfBlocks = 10;
33
+ const newestBlock = "latest";
34
+ // get the 10, 50 and 95th percentile of the tip fees from the last 10 blocks
35
+ const percentileValues = [10, 50, 95];
36
+ const feeHistory = await provider.request({
37
+ method: "eth_feeHistory",
38
+ params: [noOfBlocks, newestBlock, percentileValues]
39
+ });
40
+ // this is in hex wei
41
+ const finalBaseFeePerGas = feeHistory.baseFeePerGas[feeHistory.baseFeePerGas.length - 1];
42
+ // this is in hex wei
43
+ const priorityFeeCalcs = feeHistory.reward.reduce((acc, curr) => {
44
+ return {
45
+ slow: acc.slow.plus(new BigNumber(curr[0], 16)),
46
+ average: acc.average.plus(new BigNumber(curr[1], 16)),
47
+ fast: acc.fast.plus(new BigNumber(curr[2], 16))
48
+ };
49
+ }, {
50
+ slow: new BigNumber(0),
51
+ average: new BigNumber(0),
52
+ fast: new BigNumber(0)
53
+ });
54
+ return {
55
+ estimatedBaseFee: hexWEIToDecGWEI(finalBaseFeePerGas).toString(10),
56
+ high: {
57
+ maxWaitTimeEstimate: 30000,
58
+ minWaitTimeEstimate: 15000,
59
+ suggestedMaxFeePerGas: hexWEIToDecGWEI(priorityFeeCalcs.fast.plus(finalBaseFeePerGas).toString(16)).toString(),
60
+ suggestedMaxPriorityFeePerGas: hexWEIToDecGWEI(priorityFeeCalcs.fast.toString(16)).toString()
61
+ },
62
+ medium: {
63
+ maxWaitTimeEstimate: 45000,
64
+ minWaitTimeEstimate: 15000,
65
+ suggestedMaxFeePerGas: hexWEIToDecGWEI(priorityFeeCalcs.average.plus(finalBaseFeePerGas).toString(16)).toString(),
66
+ suggestedMaxPriorityFeePerGas: hexWEIToDecGWEI(priorityFeeCalcs.average.toString(16)).toString()
67
+ },
68
+ low: {
69
+ maxWaitTimeEstimate: 60000,
70
+ minWaitTimeEstimate: 15000,
71
+ suggestedMaxFeePerGas: hexWEIToDecGWEI(priorityFeeCalcs.slow.plus(finalBaseFeePerGas).toString(16)).toString(),
72
+ suggestedMaxPriorityFeePerGas: hexWEIToDecGWEI(priorityFeeCalcs.slow.toString(16)).toString()
73
+ }
74
+ };
75
+ }
76
+
77
+ /**
78
+ * Hit the legacy MetaSwaps gasPrices estimate api and return the low, medium
79
+ * high values from that API.
80
+ */
81
+ async function fetchLegacyGasPriceEstimates(url) {
82
+ const result = await get(url, {
83
+ referrer: url,
84
+ referrerPolicy: "no-referrer-when-downgrade",
85
+ method: "GET"
86
+ });
87
+ // this returns decimal gwei
88
+ return {
89
+ low: result.SafeGasPrice,
90
+ medium: result.ProposeGasPrice,
91
+ high: result.FastGasPrice
92
+ };
93
+ }
94
+ async function fetchEthGasPriceEstimate(provider) {
95
+ const gasPrice = await provider.request({
96
+ method: METHOD_TYPES.ETH_GET_GAS_PRICE
97
+ });
98
+ return {
99
+ gasPrice: hexWEIToDecGWEI(gasPrice).toString()
100
+ };
101
+ }
102
+ function calculateTimeEstimate(maxPriorityFeePerGas, maxFeePerGas, gasFeeEstimates) {
103
+ // all are in dec gwei
104
+ const {
105
+ low,
106
+ medium,
107
+ high,
108
+ estimatedBaseFee
109
+ } = gasFeeEstimates;
110
+ const maxPriorityFeePerGasInWEI = new BigNumber(decGWEIToHexWEI(new BigNumber(maxPriorityFeePerGas)), 16);
111
+ const maxFeePerGasInWEI = new BigNumber(decGWEIToHexWEI(new BigNumber(maxFeePerGas)), 16);
112
+ const estimatedBaseFeeInWEI = new BigNumber(decGWEIToHexWEI(new BigNumber(estimatedBaseFee)), 16);
113
+ const effectiveMaxPriorityFee = BigNumber.min(maxPriorityFeePerGasInWEI, maxFeePerGasInWEI.minus(estimatedBaseFeeInWEI));
114
+ const lowMaxPriorityFeeInWEI = new BigNumber(decGWEIToHexWEI(new BigNumber(low.suggestedMaxPriorityFeePerGas)), 16);
115
+ const mediumMaxPriorityFeeInWEI = new BigNumber(decGWEIToHexWEI(new BigNumber(medium.suggestedMaxPriorityFeePerGas)), 16);
116
+ const highMaxPriorityFeeInWEI = new BigNumber(decGWEIToHexWEI(new BigNumber(high.suggestedMaxPriorityFeePerGas)), 16);
117
+ let lowerTimeBound;
118
+ let upperTimeBound;
119
+ if (effectiveMaxPriorityFee.lt(lowMaxPriorityFeeInWEI)) {
120
+ lowerTimeBound = null;
121
+ upperTimeBound = "unknown";
122
+ } else if (effectiveMaxPriorityFee.gte(lowMaxPriorityFeeInWEI) && effectiveMaxPriorityFee.lt(mediumMaxPriorityFeeInWEI)) {
123
+ lowerTimeBound = low.minWaitTimeEstimate;
124
+ upperTimeBound = low.maxWaitTimeEstimate;
125
+ } else if (effectiveMaxPriorityFee.gte(mediumMaxPriorityFeeInWEI) && effectiveMaxPriorityFee.lt(highMaxPriorityFeeInWEI)) {
126
+ lowerTimeBound = medium.minWaitTimeEstimate;
127
+ upperTimeBound = medium.maxWaitTimeEstimate;
128
+ } else if (effectiveMaxPriorityFee.eq(highMaxPriorityFeeInWEI)) {
129
+ lowerTimeBound = high.minWaitTimeEstimate;
130
+ upperTimeBound = high.maxWaitTimeEstimate;
131
+ } else {
132
+ lowerTimeBound = 0;
133
+ upperTimeBound = high.maxWaitTimeEstimate;
134
+ }
135
+ return {
136
+ lowerTimeBound,
137
+ upperTimeBound
138
+ };
139
+ }
140
+
141
+ export { calculateTimeEstimate, fetchEthGasPriceEstimate, fetchGasEstimates, fetchGasEstimatesViaEthFeeHistory, fetchLegacyGasPriceEstimates, normalizeGWEIDecimalNumbers };
@@ -0,0 +1,91 @@
1
+ import { bytesToHex, privateToPublic, toChecksumAddress, privateToAddress, stripHexPrefix, ecsign, bigIntToBytes, addHexPrefix } from '@ethereumjs/util';
2
+ import { BaseKeyringController, concatSig } from '@toruslabs/base-controllers';
3
+ import { SigningKey, hashMessage, TypedDataEncoder } from 'ethers';
4
+
5
+ class KeyringController extends BaseKeyringController {
6
+ constructor({
7
+ config,
8
+ state
9
+ }) {
10
+ super({
11
+ config,
12
+ state
13
+ });
14
+ this.defaultState = {
15
+ wallets: []
16
+ };
17
+ this.initialize();
18
+ }
19
+ async signTransaction(tx, address) {
20
+ const txPayload = tx;
21
+ const wallet = this._getWalletForAccount(address);
22
+ const privKey = this.getBufferPrivateKey(wallet.privateKey);
23
+ const signedTx = txPayload.sign(privKey);
24
+ // Newer versions of Ethereumjs-tx are immutable and return a new tx object
25
+ return signedTx === undefined ? tx : signedTx;
26
+ }
27
+ getAccounts() {
28
+ return this.state.wallets.map(w => w.publicKey);
29
+ }
30
+ importAccount(accountPrivateKey) {
31
+ const hexPrivateKey = accountPrivateKey.padStart(64, "0");
32
+ const bufferPrivKey = Buffer.from(hexPrivateKey, "hex");
33
+ const publicKey = bytesToHex(privateToPublic(bufferPrivKey));
34
+ const address = toChecksumAddress(bytesToHex(privateToAddress(bufferPrivKey)));
35
+ const existingWallet = this.state.wallets.find(w => w.address === address);
36
+ if (existingWallet) return existingWallet.address;
37
+ this.update({
38
+ wallets: [...this.state.wallets, {
39
+ publicKey,
40
+ privateKey: accountPrivateKey,
41
+ address
42
+ }]
43
+ });
44
+ return address;
45
+ }
46
+ removeAccount(address) {
47
+ const newWallets = [...this.state.wallets];
48
+ const idx = newWallets.findIndex(w => w.address === address);
49
+ if (idx !== -1) {
50
+ newWallets.splice(idx, 1);
51
+ this.update({
52
+ wallets: newWallets
53
+ });
54
+ }
55
+ }
56
+ getBufferPrivateKey(privateKey) {
57
+ const stripped = stripHexPrefix(privateKey);
58
+ return Buffer.from(stripped, "hex");
59
+ }
60
+
61
+ // For eth_sign, we need to sign arbitrary data:
62
+ async signMessage(data, address) {
63
+ const wallet = this._getWalletForAccount(address);
64
+ const privKey = this.getBufferPrivateKey(wallet.privateKey);
65
+ const messageSig = ecsign(Buffer.from(stripHexPrefix(data), "hex"), privKey);
66
+ const sig = concatSig(Buffer.from(bigIntToBytes(messageSig.v)), Buffer.from(messageSig.r), Buffer.from(messageSig.s));
67
+ return sig;
68
+ }
69
+ async signPersonalMessage(data, address) {
70
+ const wallet = this._getWalletForAccount(address);
71
+ const privKey = new SigningKey(addHexPrefix(wallet.privateKey));
72
+ const signature = privKey.sign(hashMessage(data)).serialized;
73
+ return signature;
74
+ }
75
+
76
+ // personal_signTypedData, signs data along with the schema
77
+ async signTypedData(typedData, address) {
78
+ const wallet = this._getWalletForAccount(address);
79
+ const privKey = new SigningKey(addHexPrefix(wallet.privateKey));
80
+ const signature = privKey.sign(TypedDataEncoder.hash(typedData.domain, typedData.types, typedData.message)).serialized;
81
+ return signature;
82
+ }
83
+ _getWalletForAccount(account) {
84
+ const address = account.toLowerCase();
85
+ const wallet = this.state.wallets.find(w => w.address.toLowerCase() === address);
86
+ if (!wallet) throw new Error("Torus Keyring - Unable to find matching address.");
87
+ return wallet;
88
+ }
89
+ }
90
+
91
+ export { KeyringController };
@@ -0,0 +1,105 @@
1
+ import _defineProperty from '@babel/runtime/helpers/defineProperty';
2
+ import { BaseController } from '@toruslabs/base-controllers';
3
+ import { providerErrors, rpcErrors } from '@web3auth/auth';
4
+ import { MessageStatus } from '../utils/constants.js';
5
+
6
+ class AbstractMessageController extends BaseController {
7
+ /**
8
+ * Controller in charge of managing - storing, adding, removing, updating - Messages.
9
+ *
10
+ */
11
+ constructor({
12
+ config,
13
+ state,
14
+ getNetworkIdentifier
15
+ }) {
16
+ super({
17
+ config,
18
+ state
19
+ });
20
+ _defineProperty(this, "messages", void 0);
21
+ _defineProperty(this, "getNetworkIdentifier", void 0);
22
+ this.defaultState = {
23
+ unapprovedMessages: {},
24
+ unapprovedMessagesCount: 0
25
+ };
26
+ this.messages = [];
27
+ this.defaultConfig = {};
28
+ this.getNetworkIdentifier = getNetworkIdentifier;
29
+ super.initialize();
30
+ }
31
+ getMessage(messageId) {
32
+ return this.messages.find(message => message.id === messageId);
33
+ }
34
+ getAllMessages() {
35
+ return this.messages;
36
+ }
37
+ setMetadata(messageId, metadata) {
38
+ const message = this.getMessage(messageId);
39
+ if (!message) {
40
+ throw new Error(`${this.name}: Message not found for id: ${messageId}.`);
41
+ }
42
+ message.metadata = metadata;
43
+ this.updateMessage(message);
44
+ }
45
+ getUnapprovedMessages() {
46
+ return this.messages.filter(message => message.status === MessageStatus.UNAPPROVED).reduce((result, message) => {
47
+ result[message.id] = message;
48
+ return result;
49
+ }, {});
50
+ }
51
+ async addMessage(message) {
52
+ this.messages.push(message);
53
+ this.saveMessageList();
54
+ }
55
+ approveMessage(messageId, messageParams) {
56
+ this.setMessageStatus(messageId, MessageStatus.APPROVED);
57
+ return this.prepMessageForSigning(messageParams);
58
+ }
59
+ setMessageStatus(messageId, status) {
60
+ const message = this.getMessage(messageId);
61
+ if (!message) {
62
+ throw new Error(`${this.name}: Message not found for id: ${messageId}.`);
63
+ }
64
+ message.status = status;
65
+ this.updateMessage(message);
66
+ this.emit(`${messageId}:${status}`, message);
67
+ if (status === MessageStatus.REJECTED || status === MessageStatus.SIGNED || status === MessageStatus.FAILED) {
68
+ this.emit(`${messageId}:finished`, message);
69
+ }
70
+ }
71
+ async waitForFinishStatus(msgParams, messageName) {
72
+ return new Promise((resolve, reject) => {
73
+ const handleFinished = msg => {
74
+ if (msg.status === MessageStatus.REJECTED) {
75
+ return reject(providerErrors.userRejectedRequest(`${messageName} Signature: User denied message signature`));
76
+ }
77
+ if (msg.status === MessageStatus.FAILED) {
78
+ return reject(rpcErrors.internal(`${messageName} Signature: failed to sign message ${msg.error}`));
79
+ }
80
+ if (msg.status === MessageStatus.SIGNED) {
81
+ return resolve(msg.rawSig);
82
+ }
83
+ return reject(rpcErrors.internal(`${messageName} Signature: Unknown problem: ${JSON.stringify(msgParams)}`));
84
+ };
85
+ this.once(`${msgParams.id}:finished`, handleFinished);
86
+ });
87
+ }
88
+ updateMessage(message) {
89
+ const index = this.messages.findIndex(msg => message.id === msg.id);
90
+ if (index !== -1) {
91
+ this.messages[index] = message;
92
+ }
93
+ this.saveMessageList();
94
+ }
95
+ saveMessageList() {
96
+ const unapprovedMessages = this.getUnapprovedMessages();
97
+ const unapprovedMessagesCount = Object.keys(unapprovedMessages).length;
98
+ this.update({
99
+ unapprovedMessages,
100
+ unapprovedMessagesCount
101
+ });
102
+ }
103
+ }
104
+
105
+ export { AbstractMessageController };
@@ -0,0 +1,76 @@
1
+ import _objectSpread from '@babel/runtime/helpers/objectSpread2';
2
+ import _defineProperty from '@babel/runtime/helpers/defineProperty';
3
+ import { randomId } from '@toruslabs/base-controllers';
4
+ import log from 'loglevel';
5
+ import { MessageStatus, METHOD_TYPES, MESSAGE_EVENTS } from '../utils/constants.js';
6
+ import { AbstractMessageController } from './AbstractMessageController.js';
7
+ import { validateAddChainData } from './utils.js';
8
+
9
+ class AddChainController extends AbstractMessageController {
10
+ constructor({
11
+ config,
12
+ state,
13
+ getNetworkIdentifier,
14
+ addChain
15
+ }) {
16
+ super({
17
+ config,
18
+ state,
19
+ getNetworkIdentifier
20
+ });
21
+ _defineProperty(this, "name", "AddChainController");
22
+ _defineProperty(this, "addChain", void 0);
23
+ this.addChain = addChain;
24
+ this.initialize();
25
+ }
26
+ async processAddChain(messageId) {
27
+ const msgObject = this.getMessage(messageId);
28
+ if (!msgObject) {
29
+ throw new Error("Message not found");
30
+ }
31
+ try {
32
+ await this.approveMessage(messageId, msgObject.messageParams);
33
+ await this.addChain(msgObject.messageParams);
34
+ this.updateMessage(_objectSpread(_objectSpread({}, msgObject), {}, {
35
+ rawSig: JSON.stringify(msgObject.messageParams)
36
+ }));
37
+ this.setMessageStatus(messageId, MessageStatus.SIGNED);
38
+ return null;
39
+ } catch (error) {
40
+ log.error(error);
41
+ msgObject.error = (error === null || error === void 0 ? void 0 : error.message) || (error === null || error === void 0 ? void 0 : error.toString());
42
+ this.setMessageStatus(messageId, MessageStatus.FAILED);
43
+ }
44
+ }
45
+ async addNewUnapprovedMessage(messageParams, req) {
46
+ await this.addUnapprovedMessage(messageParams, req);
47
+ return this.waitForFinishStatus(messageParams, this.name);
48
+ }
49
+ async addUnapprovedMessage(messageParams, req) {
50
+ // set message params origin first to satisfy the eslint rule (origin won't be checked by validateAddChainData)
51
+ // for "Possible race condition: `messageParams.origin` might be assigned based on an outdated state of `messageParams`"
52
+ if (req) {
53
+ messageParams.origin = req.origin;
54
+ }
55
+ await validateAddChainData(messageParams);
56
+ const messageId = messageParams.id || randomId();
57
+ const messageData = {
58
+ id: messageId,
59
+ messageParams,
60
+ status: MessageStatus.UNAPPROVED,
61
+ time: Date.now(),
62
+ type: METHOD_TYPES.ADD_CHAIN
63
+ };
64
+ await this.addMessage(messageData);
65
+ this.emit(MESSAGE_EVENTS.UNAPPROVED_MESSAGE, {
66
+ messageData,
67
+ req
68
+ });
69
+ return messageId;
70
+ }
71
+ prepMessageForSigning(messageParams) {
72
+ return Promise.resolve(messageParams);
73
+ }
74
+ }
75
+
76
+ export { AddChainController };