@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.
- package/dist/ethereumControllers.cjs.js +80 -431
- package/dist/ethereumControllers.esm.js +30 -349
- package/dist/ethereumControllers.umd.min.js +1 -1
- package/dist/ethereumControllers.umd.min.js.LICENSE.txt +7 -2
- package/dist/lib.cjs/Account/AccountTrackerController.js +160 -0
- package/dist/lib.cjs/Block/PollingBlockTracker.js +85 -0
- package/dist/lib.cjs/Currency/CurrencyController.js +111 -0
- package/dist/lib.cjs/Gas/GasFeeController.js +214 -0
- package/dist/lib.cjs/Gas/gasUtil.js +148 -0
- package/dist/lib.cjs/Keyring/KeyringController.js +93 -0
- package/dist/lib.cjs/Message/AbstractMessageController.js +107 -0
- package/dist/lib.cjs/Message/AddChainController.js +78 -0
- package/dist/lib.cjs/Message/MessageController.js +77 -0
- package/dist/lib.cjs/Message/PersonalMessageController.js +77 -0
- package/dist/lib.cjs/Message/SwitchChainController.js +78 -0
- package/dist/lib.cjs/Message/TypedMessageController.js +81 -0
- package/dist/lib.cjs/Message/utils.js +112 -0
- package/dist/lib.cjs/Network/NetworkController.js +201 -0
- package/dist/lib.cjs/Network/cacheIdentifier.js +112 -0
- package/dist/lib.cjs/Network/createEthereumMiddleware.js +302 -0
- package/dist/lib.cjs/Network/createJsonRpcClient.js +64 -0
- package/dist/lib.cjs/Nfts/NftHandler.js +180 -0
- package/dist/lib.cjs/Nfts/NftsController.js +213 -0
- package/dist/lib.cjs/Preferences/PreferencesController.js +476 -0
- package/dist/lib.cjs/Tokens/TokenHandler.js +51 -0
- package/dist/lib.cjs/Tokens/TokenRatesController.js +112 -0
- package/dist/lib.cjs/Tokens/TokensController.js +259 -0
- package/dist/lib.cjs/Transaction/NonceTracker.js +150 -0
- package/dist/lib.cjs/Transaction/PendingTransactionTracker.js +222 -0
- package/dist/lib.cjs/Transaction/TransactionController.js +515 -0
- package/dist/lib.cjs/Transaction/TransactionGasUtil.js +81 -0
- package/dist/lib.cjs/Transaction/TransactionStateHistoryHelper.js +42 -0
- package/dist/lib.cjs/Transaction/TransactionStateManager.js +296 -0
- package/dist/lib.cjs/Transaction/TransactionUtils.js +341 -0
- package/dist/lib.cjs/index.js +171 -0
- package/dist/lib.cjs/utils/abis.js +510 -0
- package/dist/lib.cjs/utils/constants.js +362 -0
- package/dist/lib.cjs/utils/contractAddresses.js +16 -0
- package/dist/lib.cjs/utils/conversionUtils.js +232 -0
- package/dist/lib.cjs/utils/helpers.js +244 -0
- package/dist/lib.cjs/utils/lodashUtils.js +25 -0
- package/dist/lib.esm/Account/AccountTrackerController.js +158 -0
- package/dist/lib.esm/Block/PollingBlockTracker.js +83 -0
- package/dist/lib.esm/Currency/CurrencyController.js +109 -0
- package/dist/lib.esm/Gas/GasFeeController.js +212 -0
- package/dist/lib.esm/Gas/gasUtil.js +141 -0
- package/dist/lib.esm/Keyring/KeyringController.js +91 -0
- package/dist/lib.esm/Message/AbstractMessageController.js +105 -0
- package/dist/lib.esm/Message/AddChainController.js +76 -0
- package/dist/lib.esm/Message/MessageController.js +75 -0
- package/dist/lib.esm/Message/PersonalMessageController.js +75 -0
- package/dist/lib.esm/Message/SwitchChainController.js +76 -0
- package/dist/lib.esm/Message/TypedMessageController.js +79 -0
- package/dist/lib.esm/Message/utils.js +105 -0
- package/dist/lib.esm/Network/NetworkController.js +199 -0
- package/dist/lib.esm/Network/cacheIdentifier.js +107 -0
- package/dist/lib.esm/Network/createEthereumMiddleware.js +289 -0
- package/dist/lib.esm/Network/createJsonRpcClient.js +60 -0
- package/dist/lib.esm/Nfts/NftHandler.js +178 -0
- package/dist/lib.esm/Nfts/NftsController.js +211 -0
- package/dist/lib.esm/Preferences/PreferencesController.js +474 -0
- package/dist/lib.esm/Tokens/TokenHandler.js +49 -0
- package/dist/lib.esm/Tokens/TokenRatesController.js +109 -0
- package/dist/lib.esm/Tokens/TokensController.js +257 -0
- package/dist/lib.esm/Transaction/NonceTracker.js +148 -0
- package/dist/lib.esm/Transaction/PendingTransactionTracker.js +220 -0
- package/dist/lib.esm/Transaction/TransactionController.js +513 -0
- package/dist/lib.esm/Transaction/TransactionGasUtil.js +79 -0
- package/dist/lib.esm/Transaction/TransactionStateHistoryHelper.js +38 -0
- package/dist/lib.esm/Transaction/TransactionStateManager.js +294 -0
- package/dist/lib.esm/Transaction/TransactionUtils.js +326 -0
- package/dist/lib.esm/index.js +33 -0
- package/dist/lib.esm/utils/abis.js +505 -0
- package/dist/lib.esm/utils/constants.js +323 -0
- package/dist/lib.esm/utils/contractAddresses.js +14 -0
- package/dist/lib.esm/utils/conversionUtils.js +218 -0
- package/dist/lib.esm/utils/helpers.js +227 -0
- package/dist/lib.esm/utils/lodashUtils.js +21 -0
- package/dist/types/Account/AccountTrackerController.d.ts +5 -5
- package/dist/types/Block/PollingBlockTracker.d.ts +1 -2
- package/dist/types/Currency/CurrencyController.d.ts +1 -1
- package/dist/types/Gas/GasFeeController.d.ts +3 -3
- package/dist/types/Gas/gasUtil.d.ts +1 -1
- package/dist/types/Keyring/KeyringController.d.ts +3 -5
- package/dist/types/Message/AbstractMessageController.d.ts +5 -6
- package/dist/types/Message/AddChainController.d.ts +4 -4
- package/dist/types/Message/MessageController.d.ts +4 -4
- package/dist/types/Message/PersonalMessageController.d.ts +4 -4
- package/dist/types/Message/SwitchChainController.d.ts +4 -4
- package/dist/types/Message/TypedMessageController.d.ts +6 -7
- package/dist/types/Message/utils.d.ts +2 -7
- package/dist/types/Network/NetworkController.d.ts +4 -4
- package/dist/types/Network/cacheIdentifier.d.ts +1 -1
- package/dist/types/Network/createEthereumMiddleware.d.ts +2 -18
- package/dist/types/Network/createJsonRpcClient.d.ts +2 -2
- package/dist/types/Nfts/NftsController.d.ts +2 -2
- package/dist/types/Preferences/PreferencesController.d.ts +4 -4
- package/dist/types/Tokens/TokensController.d.ts +3 -3
- package/dist/types/Transaction/NonceTracker.d.ts +5 -5
- package/dist/types/Transaction/PendingTransactionTracker.d.ts +5 -5
- package/dist/types/Transaction/TransactionController.d.ts +12 -12
- package/dist/types/Transaction/TransactionGasUtil.d.ts +4 -4
- package/dist/types/Transaction/TransactionStateManager.d.ts +3 -3
- package/dist/types/Transaction/TransactionUtils.d.ts +1 -1
- package/dist/types/index.d.ts +12 -14
- package/dist/types/utils/constants.d.ts +1 -5
- package/dist/types/utils/helpers.d.ts +4 -4
- package/dist/types/utils/interfaces.d.ts +43 -23
- package/package.json +7 -7
- package/dist/types/Message/DecryptMessageController.d.ts +0 -20
- 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 };
|