@toruslabs/ethereum-controllers 5.10.1 → 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 +114 -432
- package/dist/ethereumControllers.esm.js +63 -351
- 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 +7 -4
- package/dist/types/utils/interfaces.d.ts +43 -23
- package/package.json +22 -10
- package/dist/types/Message/DecryptMessageController.d.ts +0 -20
- package/dist/types/Message/EncryptionPublicKeyController.d.ts +0 -20
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _objectSpread = require('@babel/runtime/helpers/objectSpread2');
|
|
4
|
+
var util = require('@ethereumjs/util');
|
|
5
|
+
var baseControllers = require('@toruslabs/base-controllers');
|
|
6
|
+
var BigNumber = require('bignumber.js');
|
|
7
|
+
var log = require('loglevel');
|
|
8
|
+
var TransactionUtils = require('../Transaction/TransactionUtils.js');
|
|
9
|
+
var constants = require('./constants.js');
|
|
10
|
+
|
|
11
|
+
function hexToBn(hex) {
|
|
12
|
+
return new BigNumber(util.stripHexPrefix(hex), 16);
|
|
13
|
+
}
|
|
14
|
+
function BNToHex(bn) {
|
|
15
|
+
return util.addHexPrefix(bn.toString(16));
|
|
16
|
+
}
|
|
17
|
+
function getEtherScanHashLink(txHash, chainId) {
|
|
18
|
+
if (!constants.SUPPORTED_NETWORKS[chainId]) return "";
|
|
19
|
+
return `${constants.SUPPORTED_NETWORKS[chainId].blockExplorerUrl}/tx/${txHash}`;
|
|
20
|
+
}
|
|
21
|
+
const formatPastTx = params => {
|
|
22
|
+
var _transaction$to;
|
|
23
|
+
const {
|
|
24
|
+
transaction,
|
|
25
|
+
lowerCaseSelectedAddress,
|
|
26
|
+
blockExplorerUrl
|
|
27
|
+
} = params;
|
|
28
|
+
let totalAmountString = "";
|
|
29
|
+
if (transaction.type === constants.CONTRACT_TYPE_ERC721 || transaction.type === constants.CONTRACT_TYPE_ERC1155) totalAmountString = transaction.symbol;else if (transaction.type === constants.CONTRACT_TYPE_ERC20) totalAmountString = baseControllers.formatSmallNumbers(Number.parseFloat(transaction.total_amount), transaction.symbol, true);else totalAmountString = baseControllers.formatSmallNumbers(Number.parseFloat(transaction.total_amount), transaction.type_name, true);
|
|
30
|
+
const currencyAmountString = transaction.type === constants.CONTRACT_TYPE_ERC721 || transaction.type === constants.CONTRACT_TYPE_ERC1155 || transaction.isEtherscan ? "" : baseControllers.formatSmallNumbers(Number.parseFloat(transaction.currency_amount), transaction.selected_currency, true);
|
|
31
|
+
const finalObject = {
|
|
32
|
+
id: transaction.created_at.toString(),
|
|
33
|
+
date: new Date(transaction.created_at).toString(),
|
|
34
|
+
from: transaction.from,
|
|
35
|
+
from_aa_address: transaction.from_aa_address,
|
|
36
|
+
slicedFrom: typeof transaction.from === "string" ? baseControllers.addressSlicer(transaction.from) : "",
|
|
37
|
+
to: transaction.to,
|
|
38
|
+
slicedTo: typeof transaction.to === "string" ? baseControllers.addressSlicer(transaction.to) : "",
|
|
39
|
+
action: lowerCaseSelectedAddress === ((_transaction$to = transaction.to) === null || _transaction$to === void 0 ? void 0 : _transaction$to.toLowerCase()) || "" ? baseControllers.ACTIVITY_ACTION_RECEIVE : baseControllers.ACTIVITY_ACTION_SEND,
|
|
40
|
+
totalAmount: transaction.total_amount,
|
|
41
|
+
totalAmountString,
|
|
42
|
+
currencyAmount: transaction.currency_amount,
|
|
43
|
+
currencyAmountString,
|
|
44
|
+
amount: `${totalAmountString} / ${currencyAmountString}`,
|
|
45
|
+
status: transaction.status,
|
|
46
|
+
etherscanLink: blockExplorerUrl ? `${blockExplorerUrl}/tx/${transaction.transaction_hash}` : "",
|
|
47
|
+
chainId: transaction.chain_id,
|
|
48
|
+
ethRate: Number.parseFloat(transaction === null || transaction === void 0 ? void 0 : transaction.total_amount) && Number.parseFloat(transaction === null || transaction === void 0 ? void 0 : transaction.currency_amount) ? `1 ${transaction.symbol} = ${baseControllers.significantDigits(Number.parseFloat(transaction.currency_amount) / Number.parseFloat(transaction.total_amount))}` : "",
|
|
49
|
+
currencyUsed: transaction.selected_currency,
|
|
50
|
+
type: transaction.type,
|
|
51
|
+
type_name: transaction.type_name,
|
|
52
|
+
type_image_link: transaction.type_image_link,
|
|
53
|
+
transaction_hash: transaction.transaction_hash,
|
|
54
|
+
transaction_category: transaction.transaction_category,
|
|
55
|
+
isEtherscan: transaction.isEtherscan,
|
|
56
|
+
input: transaction.input || "",
|
|
57
|
+
token_id: transaction.token_id || "",
|
|
58
|
+
contract_address: transaction.contract_address || "",
|
|
59
|
+
nonce: transaction.nonce || "",
|
|
60
|
+
is_cancel: !!transaction.is_cancel || false,
|
|
61
|
+
gas: transaction.gas || "",
|
|
62
|
+
gasPrice: transaction.gasPrice || ""
|
|
63
|
+
};
|
|
64
|
+
return finalObject;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Ref - https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionreceipt
|
|
69
|
+
*/
|
|
70
|
+
const getEthTxStatus = async (hash, provider) => {
|
|
71
|
+
try {
|
|
72
|
+
const result = await provider.request({
|
|
73
|
+
method: constants.METHOD_TYPES.ETH_GET_TRANSACTION_RECEIPT,
|
|
74
|
+
params: [hash]
|
|
75
|
+
});
|
|
76
|
+
if (result === null) return baseControllers.TransactionStatus.submitted;
|
|
77
|
+
if (result && result.status === "0x1") return baseControllers.TransactionStatus.confirmed;
|
|
78
|
+
if (result && result.status === "0x0") return baseControllers.TransactionStatus.rejected;
|
|
79
|
+
return undefined;
|
|
80
|
+
} catch (err) {
|
|
81
|
+
log.warn("unable to fetch transaction status", err);
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
function formatDate(inputDate) {
|
|
86
|
+
const monthList = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
87
|
+
const date = new Date(inputDate);
|
|
88
|
+
const day = date.getDate();
|
|
89
|
+
const month = monthList[date.getMonth()];
|
|
90
|
+
const year = date.getFullYear();
|
|
91
|
+
return `${day} ${month} ${year}`;
|
|
92
|
+
}
|
|
93
|
+
function formatTime(time) {
|
|
94
|
+
return new Date(time).toTimeString().slice(0, 8);
|
|
95
|
+
}
|
|
96
|
+
const idleTimeTracker = (activityThresholdTime => {
|
|
97
|
+
let isIdle = false;
|
|
98
|
+
let idleTimeout = null;
|
|
99
|
+
const resetTimer = () => {
|
|
100
|
+
if (idleTimeout) {
|
|
101
|
+
window.clearTimeout(idleTimeout);
|
|
102
|
+
}
|
|
103
|
+
isIdle = false;
|
|
104
|
+
idleTimeout = window.setTimeout(() => {
|
|
105
|
+
isIdle = true;
|
|
106
|
+
}, activityThresholdTime * 1000);
|
|
107
|
+
};
|
|
108
|
+
if (typeof window !== "undefined" && typeof document !== "undefined") {
|
|
109
|
+
window.addEventListener("load", resetTimer);
|
|
110
|
+
document.addEventListener("mousemove", resetTimer);
|
|
111
|
+
document.addEventListener("keydown", resetTimer);
|
|
112
|
+
}
|
|
113
|
+
function checkIfIdle() {
|
|
114
|
+
return isIdle;
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
checkIfIdle
|
|
118
|
+
};
|
|
119
|
+
})(60 * 3);
|
|
120
|
+
function isAddressByChainId(address, _chainId) {
|
|
121
|
+
// TOOD: add rsk network checks.
|
|
122
|
+
return util.isValidAddress(address);
|
|
123
|
+
}
|
|
124
|
+
function toChecksumAddressByChainId(address, chainId) {
|
|
125
|
+
// TOOD: add rsk network checks.
|
|
126
|
+
if (!isAddressByChainId(address)) return address;
|
|
127
|
+
return util.toChecksumAddress(address);
|
|
128
|
+
}
|
|
129
|
+
const GAS_LIMITS = {
|
|
130
|
+
// maximum gasLimit of a simple send
|
|
131
|
+
SIMPLE: util.addHexPrefix(21000 .toString(16)),
|
|
132
|
+
// a base estimate for token transfers.
|
|
133
|
+
BASE_TOKEN_ESTIMATE: util.addHexPrefix(100000 .toString(16))
|
|
134
|
+
};
|
|
135
|
+
function bnLessThan(a, b) {
|
|
136
|
+
if (a === null || a === undefined || b === null || b === undefined) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
return new BigNumber(a, 10).lt(b, 10);
|
|
140
|
+
}
|
|
141
|
+
const getIpfsEndpoint = path => `https://infura-ipfs.io/${path}`;
|
|
142
|
+
function sanitizeNftMetdataUrl(url) {
|
|
143
|
+
let finalUri = url;
|
|
144
|
+
if (url !== null && url !== void 0 && url.startsWith("ipfs")) {
|
|
145
|
+
const ipfsPath = url.split("ipfs://")[1];
|
|
146
|
+
finalUri = getIpfsEndpoint(ipfsPath);
|
|
147
|
+
}
|
|
148
|
+
return finalUri;
|
|
149
|
+
}
|
|
150
|
+
function getChainType(chainId) {
|
|
151
|
+
if (chainId === constants.MAINNET_CHAIN_ID) {
|
|
152
|
+
return "mainnet";
|
|
153
|
+
} else if (constants.TEST_CHAINS.includes(chainId)) {
|
|
154
|
+
return "testnet";
|
|
155
|
+
}
|
|
156
|
+
return "custom";
|
|
157
|
+
}
|
|
158
|
+
const addEtherscanTransactions = async params => {
|
|
159
|
+
const {
|
|
160
|
+
txn,
|
|
161
|
+
lowerCaseSelectedAddress,
|
|
162
|
+
provider,
|
|
163
|
+
chainId,
|
|
164
|
+
blockExplorerUrl
|
|
165
|
+
} = params;
|
|
166
|
+
const transactionPromises = await Promise.all(txn.map(async tx => {
|
|
167
|
+
var _SUPPORTED_NETWORKS$c, _SUPPORTED_NETWORKS$c2;
|
|
168
|
+
const {
|
|
169
|
+
category,
|
|
170
|
+
type
|
|
171
|
+
} = await TransactionUtils.determineTransactionType(_objectSpread(_objectSpread({}, tx), {}, {
|
|
172
|
+
data: tx.input
|
|
173
|
+
}), provider);
|
|
174
|
+
tx.transaction_category = tx.transaction_category || category;
|
|
175
|
+
tx.type_image_link = ((_SUPPORTED_NETWORKS$c = constants.SUPPORTED_NETWORKS[chainId]) === null || _SUPPORTED_NETWORKS$c === void 0 ? void 0 : _SUPPORTED_NETWORKS$c.logo) || "";
|
|
176
|
+
tx.type_name = (_SUPPORTED_NETWORKS$c2 = constants.SUPPORTED_NETWORKS[chainId]) === null || _SUPPORTED_NETWORKS$c2 === void 0 ? void 0 : _SUPPORTED_NETWORKS$c2.ticker;
|
|
177
|
+
tx.type = type;
|
|
178
|
+
return tx;
|
|
179
|
+
}));
|
|
180
|
+
const finalTxs = transactionPromises.reduce((accumulator, x) => {
|
|
181
|
+
var _SUPPORTED_NETWORKS$c3, _SUPPORTED_NETWORKS$c4;
|
|
182
|
+
let totalAmountString = x.value ? new BigNumber(x.value).div(new BigNumber(10).pow(new BigNumber(x.tokenDecimal || 18))).toString() : "";
|
|
183
|
+
let type = constants.CONTRACT_TYPE_ETH;
|
|
184
|
+
if (x.contractAddress !== "") {
|
|
185
|
+
if (x.tokenID) {
|
|
186
|
+
type = x.tokenValue ? constants.CONTRACT_TYPE_ERC1155 : constants.CONTRACT_TYPE_ERC721;
|
|
187
|
+
} else {
|
|
188
|
+
type = constants.CONTRACT_TYPE_ERC20;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
if (type === constants.CONTRACT_TYPE_ERC1155) {
|
|
192
|
+
totalAmountString = x.tokenValue;
|
|
193
|
+
}
|
|
194
|
+
const etherscanTransaction = {
|
|
195
|
+
type,
|
|
196
|
+
type_image_link: x.type_image_link || "n/a",
|
|
197
|
+
type_name: x.tokenName || ((_SUPPORTED_NETWORKS$c3 = constants.SUPPORTED_NETWORKS[chainId]) === null || _SUPPORTED_NETWORKS$c3 === void 0 ? void 0 : _SUPPORTED_NETWORKS$c3.ticker) || "n/a",
|
|
198
|
+
symbol: x.tokenSymbol || ((_SUPPORTED_NETWORKS$c4 = constants.SUPPORTED_NETWORKS[chainId]) === null || _SUPPORTED_NETWORKS$c4 === void 0 ? void 0 : _SUPPORTED_NETWORKS$c4.ticker),
|
|
199
|
+
token_id: x.tokenID || "",
|
|
200
|
+
total_amount: totalAmountString,
|
|
201
|
+
created_at: new Date(Number(x.timeStamp) * 1000),
|
|
202
|
+
from: x.from,
|
|
203
|
+
to: x.to,
|
|
204
|
+
transaction_hash: x.hash,
|
|
205
|
+
status: x.txreceipt_status && x.txreceipt_status === "0" ? baseControllers.TransactionStatus.failed : baseControllers.TransactionStatus.confirmed,
|
|
206
|
+
isEtherscan: true,
|
|
207
|
+
input: x.input,
|
|
208
|
+
contract_address: x.contractAddress,
|
|
209
|
+
transaction_category: x.transaction_category,
|
|
210
|
+
gas: `0x${new BigNumber(x.gasUsed || 0, 10).toString(16)}`,
|
|
211
|
+
gasPrice: `0x${new BigNumber(x.gasPrice || 0, 10).toString(16)}`,
|
|
212
|
+
chain_id: chainId,
|
|
213
|
+
currency_amount: "",
|
|
214
|
+
nonce: x.nonce,
|
|
215
|
+
from_aa_address: "",
|
|
216
|
+
is_cancel: false,
|
|
217
|
+
selected_currency: ""
|
|
218
|
+
};
|
|
219
|
+
accumulator.push(formatPastTx({
|
|
220
|
+
transaction: etherscanTransaction,
|
|
221
|
+
lowerCaseSelectedAddress,
|
|
222
|
+
blockExplorerUrl
|
|
223
|
+
}));
|
|
224
|
+
return accumulator;
|
|
225
|
+
}, []);
|
|
226
|
+
return finalTxs;
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
exports.BNToHex = BNToHex;
|
|
230
|
+
exports.GAS_LIMITS = GAS_LIMITS;
|
|
231
|
+
exports.addEtherscanTransactions = addEtherscanTransactions;
|
|
232
|
+
exports.bnLessThan = bnLessThan;
|
|
233
|
+
exports.formatDate = formatDate;
|
|
234
|
+
exports.formatPastTx = formatPastTx;
|
|
235
|
+
exports.formatTime = formatTime;
|
|
236
|
+
exports.getChainType = getChainType;
|
|
237
|
+
exports.getEthTxStatus = getEthTxStatus;
|
|
238
|
+
exports.getEtherScanHashLink = getEtherScanHashLink;
|
|
239
|
+
exports.getIpfsEndpoint = getIpfsEndpoint;
|
|
240
|
+
exports.hexToBn = hexToBn;
|
|
241
|
+
exports.idleTimeTracker = idleTimeTracker;
|
|
242
|
+
exports.isAddressByChainId = isAddressByChainId;
|
|
243
|
+
exports.sanitizeNftMetdataUrl = sanitizeNftMetdataUrl;
|
|
244
|
+
exports.toChecksumAddressByChainId = toChecksumAddressByChainId;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function sortBy(arr, key) {
|
|
4
|
+
return arr.slice().sort((a, b) => {
|
|
5
|
+
if (a[key] < b[key]) return -1;
|
|
6
|
+
if (a[key] > b[key]) return 1;
|
|
7
|
+
return 0;
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
function keyBy(arr, key) {
|
|
11
|
+
return arr.reduce((acc, item) => {
|
|
12
|
+
const keyValue = item[key];
|
|
13
|
+
if (typeof keyValue === "string" || typeof keyValue === "number") {
|
|
14
|
+
acc[keyValue.toString()] = item;
|
|
15
|
+
}
|
|
16
|
+
return acc;
|
|
17
|
+
}, {});
|
|
18
|
+
}
|
|
19
|
+
function mapValues(obj, iteratee) {
|
|
20
|
+
return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, iteratee(value, key)]));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
exports.keyBy = keyBy;
|
|
24
|
+
exports.mapValues = mapValues;
|
|
25
|
+
exports.sortBy = sortBy;
|
|
@@ -0,0 +1,158 @@
|
|
|
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 { Mutex } from 'async-mutex';
|
|
5
|
+
import { BrowserProvider, toQuantity, Contract } from 'ethers';
|
|
6
|
+
import log from 'loglevel';
|
|
7
|
+
import { singleBalanceCheckerAbi } from '../utils/abis.js';
|
|
8
|
+
import { SINGLE_CALL_BALANCES_ADDRESSES } from '../utils/contractAddresses.js';
|
|
9
|
+
|
|
10
|
+
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Tracks accounts based on blocks.
|
|
14
|
+
* If block tracker provides latest block, we query accounts from it.
|
|
15
|
+
* Preferences state changes also retrigger accounts update.
|
|
16
|
+
* Network state changes also retrigger accounts update.
|
|
17
|
+
*/
|
|
18
|
+
class AccountTrackerController extends BaseController {
|
|
19
|
+
constructor({
|
|
20
|
+
config,
|
|
21
|
+
state,
|
|
22
|
+
provider,
|
|
23
|
+
blockTracker,
|
|
24
|
+
getIdentities,
|
|
25
|
+
onPreferencesStateChange,
|
|
26
|
+
getCurrentChainId
|
|
27
|
+
}) {
|
|
28
|
+
super({
|
|
29
|
+
config,
|
|
30
|
+
state
|
|
31
|
+
});
|
|
32
|
+
_defineProperty(this, "provider", void 0);
|
|
33
|
+
_defineProperty(this, "blockTracker", void 0);
|
|
34
|
+
_defineProperty(this, "mutex", new Mutex());
|
|
35
|
+
_defineProperty(this, "ethersProvider", void 0);
|
|
36
|
+
_defineProperty(this, "getIdentities", void 0);
|
|
37
|
+
_defineProperty(this, "getCurrentChainId", void 0);
|
|
38
|
+
this.defaultState = {
|
|
39
|
+
accounts: {}
|
|
40
|
+
};
|
|
41
|
+
this.initialize();
|
|
42
|
+
this.provider = provider;
|
|
43
|
+
this.blockTracker = blockTracker;
|
|
44
|
+
this.ethersProvider = new BrowserProvider(this.provider, "any");
|
|
45
|
+
this.getIdentities = getIdentities;
|
|
46
|
+
this.getCurrentChainId = getCurrentChainId;
|
|
47
|
+
onPreferencesStateChange(() => {
|
|
48
|
+
const refreshNeeded = this.syncAccounts();
|
|
49
|
+
if (refreshNeeded) {
|
|
50
|
+
log.info("onPreferencesStateChange called");
|
|
51
|
+
this.refresh();
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
this.blockTrackerListener = this.blockTrackerListener.bind(this);
|
|
55
|
+
}
|
|
56
|
+
blockTrackerListener() {
|
|
57
|
+
this.refresh();
|
|
58
|
+
}
|
|
59
|
+
startPolling() {
|
|
60
|
+
this.stopPolling();
|
|
61
|
+
// Initiate block tracker internal tracking.
|
|
62
|
+
if (Object.keys(this.state.accounts).length > 0) {
|
|
63
|
+
// Adding this listener on block tracker triggers it to start polling.
|
|
64
|
+
this.blockTracker.on("latest", this.blockTrackerListener);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
stopPolling() {
|
|
68
|
+
this.blockTracker.removeListener("latest", this.blockTrackerListener);
|
|
69
|
+
}
|
|
70
|
+
syncAccounts() {
|
|
71
|
+
const {
|
|
72
|
+
accounts
|
|
73
|
+
} = this.state;
|
|
74
|
+
const addresses = Object.keys(this.getIdentities());
|
|
75
|
+
const existing = Object.keys(accounts);
|
|
76
|
+
const newAddresses = addresses.filter(address => existing.indexOf(address) === -1);
|
|
77
|
+
const oldAddresses = existing.filter(address => addresses.indexOf(address) === -1);
|
|
78
|
+
let isUpdated = false;
|
|
79
|
+
newAddresses.forEach(address => {
|
|
80
|
+
isUpdated = true;
|
|
81
|
+
accounts[address] = {
|
|
82
|
+
balance: "0x0"
|
|
83
|
+
};
|
|
84
|
+
});
|
|
85
|
+
oldAddresses.forEach(address => {
|
|
86
|
+
isUpdated = true;
|
|
87
|
+
delete accounts[address];
|
|
88
|
+
});
|
|
89
|
+
this.update({
|
|
90
|
+
accounts: _objectSpread({}, accounts)
|
|
91
|
+
});
|
|
92
|
+
return isUpdated;
|
|
93
|
+
}
|
|
94
|
+
async refresh() {
|
|
95
|
+
const releaseLock = await this.mutex.acquire();
|
|
96
|
+
try {
|
|
97
|
+
this._updateAccounts();
|
|
98
|
+
} catch (error) {} finally {
|
|
99
|
+
releaseLock();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async _updateAccounts() {
|
|
103
|
+
const {
|
|
104
|
+
accounts
|
|
105
|
+
} = this.state;
|
|
106
|
+
const addresses = Object.keys(accounts);
|
|
107
|
+
const chainId = this.getCurrentChainId();
|
|
108
|
+
if (chainId === "loading") return;
|
|
109
|
+
if (addresses.length > 0) {
|
|
110
|
+
if (SINGLE_CALL_BALANCES_ADDRESSES[chainId]) {
|
|
111
|
+
await this._updateAccountsViaBalanceChecker(addresses, SINGLE_CALL_BALANCES_ADDRESSES[chainId]);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
log.info("falling back to ethQuery.getBalance");
|
|
115
|
+
await Promise.all(addresses.map(x => this._updateAccount(x)));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async _updateAccount(address) {
|
|
119
|
+
const balance = await this.provider.request({
|
|
120
|
+
method: "eth_getBalance",
|
|
121
|
+
params: [address, "latest"]
|
|
122
|
+
});
|
|
123
|
+
const {
|
|
124
|
+
accounts
|
|
125
|
+
} = this.state;
|
|
126
|
+
if (!accounts[address]) return;
|
|
127
|
+
accounts[address] = {
|
|
128
|
+
balance: toQuantity(balance)
|
|
129
|
+
};
|
|
130
|
+
this.update({
|
|
131
|
+
accounts
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
async _updateAccountsViaBalanceChecker(addresses, deployedContractAddress) {
|
|
135
|
+
const ethContract = new Contract(deployedContractAddress, singleBalanceCheckerAbi, this.ethersProvider);
|
|
136
|
+
try {
|
|
137
|
+
const result = await ethContract.balances(addresses, [ZERO_ADDRESS]);
|
|
138
|
+
const {
|
|
139
|
+
accounts
|
|
140
|
+
} = this.state;
|
|
141
|
+
addresses.forEach((address, index) => {
|
|
142
|
+
const balance = toQuantity(result[index]);
|
|
143
|
+
if (!accounts[address]) return;
|
|
144
|
+
accounts[address] = {
|
|
145
|
+
balance
|
|
146
|
+
};
|
|
147
|
+
});
|
|
148
|
+
return this.update({
|
|
149
|
+
accounts
|
|
150
|
+
});
|
|
151
|
+
} catch (error) {
|
|
152
|
+
log.warn("Torus - Account Tracker single call balance fetch failed", error);
|
|
153
|
+
return Promise.all(addresses.map(x => this._updateAccount(x)));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export { AccountTrackerController };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { BaseBlockTracker, timeout } from '@toruslabs/base-controllers';
|
|
2
|
+
import log from 'loglevel';
|
|
3
|
+
import { idleTimeTracker } from '../utils/helpers.js';
|
|
4
|
+
|
|
5
|
+
const DEFAULT_POLLING_INTERVAL = 20;
|
|
6
|
+
const DEFAULT_RETRY_TIMEOUT = 2;
|
|
7
|
+
const SEC = 1000;
|
|
8
|
+
class PollingBlockTracker extends BaseBlockTracker {
|
|
9
|
+
constructor({
|
|
10
|
+
config,
|
|
11
|
+
state = {}
|
|
12
|
+
}) {
|
|
13
|
+
if (!config.provider) {
|
|
14
|
+
throw new Error("PollingBlockTracker - no provider specified.");
|
|
15
|
+
}
|
|
16
|
+
super({
|
|
17
|
+
config,
|
|
18
|
+
state
|
|
19
|
+
});
|
|
20
|
+
const pollingInterval = config.pollingInterval || DEFAULT_POLLING_INTERVAL;
|
|
21
|
+
const retryTimeout = config.retryTimeout || DEFAULT_RETRY_TIMEOUT;
|
|
22
|
+
|
|
23
|
+
// merge default + provided config.
|
|
24
|
+
this.defaultConfig = {
|
|
25
|
+
provider: config.provider,
|
|
26
|
+
pollingInterval: pollingInterval * SEC,
|
|
27
|
+
retryTimeout: retryTimeout * SEC,
|
|
28
|
+
setSkipCacheFlag: config.setSkipCacheFlag || false
|
|
29
|
+
};
|
|
30
|
+
this.initialize();
|
|
31
|
+
}
|
|
32
|
+
async checkForLatestBlock() {
|
|
33
|
+
await this._updateLatestBlock();
|
|
34
|
+
return this.getLatestBlock();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// overrides the BaseBlockTracker._start method.
|
|
38
|
+
_start() {
|
|
39
|
+
this._synchronize().catch(err => this.emit("error", err));
|
|
40
|
+
}
|
|
41
|
+
async _synchronize() {
|
|
42
|
+
while (this.state._isRunning) {
|
|
43
|
+
if (idleTimeTracker.checkIfIdle()) return;
|
|
44
|
+
try {
|
|
45
|
+
await this._updateLatestBlock();
|
|
46
|
+
await timeout(this.config.pollingInterval);
|
|
47
|
+
} catch (err) {
|
|
48
|
+
const newErr = new Error(`PollingBlockTracker - encountered an error while attempting to update latest block:\n${err.stack}`);
|
|
49
|
+
try {
|
|
50
|
+
this.emit("error", newErr);
|
|
51
|
+
} catch (emitErr) {
|
|
52
|
+
log.error(newErr);
|
|
53
|
+
}
|
|
54
|
+
await timeout(this.config.retryTimeout);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async _updateLatestBlock() {
|
|
59
|
+
// fetch + set latest block
|
|
60
|
+
const latestBlock = await this._fetchLatestBlock();
|
|
61
|
+
this._newPotentialLatest(latestBlock);
|
|
62
|
+
}
|
|
63
|
+
async _fetchLatestBlock() {
|
|
64
|
+
try {
|
|
65
|
+
const block = await this.config.provider.request({
|
|
66
|
+
method: "eth_getBlockByNumber",
|
|
67
|
+
params: ["latest", false]
|
|
68
|
+
});
|
|
69
|
+
return {
|
|
70
|
+
blockHash: block.hash,
|
|
71
|
+
idempotencyKey: block.number,
|
|
72
|
+
timestamp: block.timestamp,
|
|
73
|
+
baseFeePerGas: block.baseFeePerGas,
|
|
74
|
+
gasLimit: block.gasLimit
|
|
75
|
+
};
|
|
76
|
+
} catch (error) {
|
|
77
|
+
log.error("Polling Block Tracker: ", error);
|
|
78
|
+
throw new Error(`PollingBlockTracker - encountered error fetching block:\n${error.message}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export { PollingBlockTracker };
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import _objectSpread from '@babel/runtime/helpers/objectSpread2';
|
|
2
|
+
import _defineProperty from '@babel/runtime/helpers/defineProperty';
|
|
3
|
+
import { BaseCurrencyController } from '@toruslabs/base-controllers';
|
|
4
|
+
import { get } from '@toruslabs/http-helpers';
|
|
5
|
+
import log from 'loglevel';
|
|
6
|
+
import { idleTimeTracker } from '../utils/helpers.js';
|
|
7
|
+
|
|
8
|
+
class CurrencyController extends BaseCurrencyController {
|
|
9
|
+
constructor({
|
|
10
|
+
config,
|
|
11
|
+
state,
|
|
12
|
+
onNetworkChanged
|
|
13
|
+
}) {
|
|
14
|
+
super({
|
|
15
|
+
config,
|
|
16
|
+
state
|
|
17
|
+
});
|
|
18
|
+
_defineProperty(this, "conversionInterval", void 0);
|
|
19
|
+
this.defaultState = _objectSpread(_objectSpread({}, this.defaultState), {}, {
|
|
20
|
+
commonDenomination: "USD",
|
|
21
|
+
commonDenominatorPrice: 0
|
|
22
|
+
});
|
|
23
|
+
this.initialize();
|
|
24
|
+
onNetworkChanged(networkState => {
|
|
25
|
+
// to be called as (listener) => this.networkController.on('networkDidChange', listener);
|
|
26
|
+
if (networkState.providerConfig.ticker.toUpperCase() !== this.state.nativeCurrency.toUpperCase()) {
|
|
27
|
+
this.setNativeCurrency(networkState.providerConfig.ticker);
|
|
28
|
+
this.updateConversionRate();
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
setCommonDenomination(commonDenomination) {
|
|
33
|
+
this.update({
|
|
34
|
+
commonDenomination
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
getCommonDenomination() {
|
|
38
|
+
return this.state.commonDenomination;
|
|
39
|
+
}
|
|
40
|
+
setCommonDenominatorPrice(commonDenominatorPrice) {
|
|
41
|
+
this.update({
|
|
42
|
+
commonDenominatorPrice
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
getCommonDenominatorPrice() {
|
|
46
|
+
return this.state.commonDenominatorPrice;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Creates a new poll, using setInterval, to periodically call updateConversionRate. The id of the interval is
|
|
51
|
+
* stored at the controller's conversionInterval property. If it is called and such an id already exists, the
|
|
52
|
+
* previous interval is clear and a new one is created.
|
|
53
|
+
*/
|
|
54
|
+
scheduleConversionInterval() {
|
|
55
|
+
if (this.conversionInterval) {
|
|
56
|
+
window.clearInterval(this.conversionInterval);
|
|
57
|
+
}
|
|
58
|
+
this.conversionInterval = window.setInterval(() => {
|
|
59
|
+
if (!idleTimeTracker.checkIfIdle()) {
|
|
60
|
+
this.updateConversionRate();
|
|
61
|
+
}
|
|
62
|
+
}, this.config.pollInterval);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Updates the conversionRate and conversionDate properties associated with the currentCurrency. Updated info is
|
|
67
|
+
* fetched from an external API
|
|
68
|
+
*/
|
|
69
|
+
async updateConversionRate() {
|
|
70
|
+
const currentCurrency = this.getCurrentCurrency();
|
|
71
|
+
const nativeCurrency = this.getNativeCurrency();
|
|
72
|
+
const commonDenomination = this.getCommonDenomination();
|
|
73
|
+
const conversionRate = await this.retrieveConversionRate(nativeCurrency, currentCurrency, commonDenomination);
|
|
74
|
+
const currentCurrencyRate = Number.parseFloat(conversionRate[currentCurrency.toUpperCase()]);
|
|
75
|
+
const commonDenominationRate = Number.parseFloat(conversionRate[commonDenomination.toUpperCase()]);
|
|
76
|
+
// set conversion rate
|
|
77
|
+
if (currentCurrencyRate || commonDenominationRate) {
|
|
78
|
+
// ETC
|
|
79
|
+
this.setConversionRate(currentCurrencyRate);
|
|
80
|
+
this.setConversionDate(Math.floor(Date.now() / 1000).toString());
|
|
81
|
+
if (currentCurrency.toUpperCase() === commonDenomination.toUpperCase()) {
|
|
82
|
+
this.setCommonDenominatorPrice(currentCurrencyRate);
|
|
83
|
+
} else {
|
|
84
|
+
this.setCommonDenominatorPrice(commonDenominationRate);
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
this.setConversionRate(0);
|
|
88
|
+
this.setConversionDate("N/A");
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async retrieveConversionRate(fromCurrency, toCurrency, commonDenomination) {
|
|
92
|
+
try {
|
|
93
|
+
let apiUrl = `${this.config.api}/currency?fsym=${fromCurrency.toUpperCase()}&tsyms=${toCurrency.toUpperCase()}`;
|
|
94
|
+
if (commonDenomination && commonDenomination.toUpperCase() !== toCurrency.toUpperCase()) {
|
|
95
|
+
apiUrl += `,${commonDenomination.toUpperCase()}`;
|
|
96
|
+
}
|
|
97
|
+
const parsedResponse = await get(apiUrl);
|
|
98
|
+
return parsedResponse;
|
|
99
|
+
} catch (error) {
|
|
100
|
+
log.error(error, `CurrencyController - updateCommonDenominatorPrice: Failed to query rate for currency: ${fromCurrency}/ ${toCurrency}`);
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
[toCurrency.toUpperCase()]: "0",
|
|
104
|
+
[commonDenomination.toUpperCase()]: "0"
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export { CurrencyController };
|