@toruslabs/ethereum-controllers 4.1.0 → 4.2.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.
@@ -27,12 +27,17 @@ export default class PreferencesController extends BasePreferencesController<Ext
27
27
  userInfo?: UserInfo;
28
28
  rehydrate?: boolean;
29
29
  locale?: string;
30
+ type: string;
30
31
  }): Promise<void>;
31
32
  getSelectedAddress(): string;
32
33
  sync(address: string): Promise<boolean>;
33
34
  patchNewTx(tx: TransactionPayload, address: string): Promise<void>;
34
35
  recalculatePastTx(address?: string): void;
35
36
  refetchEtherscanTx(address?: string): Promise<void>;
37
+ fetchEtherscanTx<T>(parameters: {
38
+ selectedAddress: string;
39
+ selectedNetwork: string;
40
+ }): Promise<T[]>;
36
41
  getEtherScanTokens(address: string, chainId: string): Promise<CustomTokenInfo[]>;
37
42
  getSimpleHashNfts(address: string, chainId: string): Promise<CustomNftInfo[]>;
38
43
  getCustomTokens(address?: string): CustomToken[];
@@ -229,7 +229,6 @@ export type PollingBlockTrackerState = BaseBlockTrackerState<EthereumBlock>;
229
229
  export interface EthereumProviderConfig extends ProviderConfig {
230
230
  isErc20?: boolean;
231
231
  tokenAddress?: string;
232
- isTestNet?: boolean;
233
232
  }
234
233
  export interface EthereumNetworkState extends NetworkState {
235
234
  providerConfig: EthereumProviderConfig;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toruslabs/ethereum-controllers",
3
- "version": "4.1.0",
3
+ "version": "4.2.0",
4
4
  "homepage": "https://github.com/torusresearch/controllers#readme",
5
5
  "license": "ISC",
6
6
  "main": "dist/ethereumControllers.cjs.js",
@@ -24,7 +24,7 @@
24
24
  "@ethereumjs/util": "^9.0.0",
25
25
  "@metamask/eth-sig-util": "^7.0.0",
26
26
  "@metamask/rpc-errors": "^6.0.0",
27
- "@toruslabs/base-controllers": "^4.1.0",
27
+ "@toruslabs/base-controllers": "^4.2.0",
28
28
  "@toruslabs/http-helpers": "^5.0.0",
29
29
  "@toruslabs/openlogin-jrpc": "^5.1.0",
30
30
  "async-mutex": "^0.4.0",
@@ -64,7 +64,7 @@
64
64
  "publishConfig": {
65
65
  "access": "public"
66
66
  },
67
- "gitHead": "13b57afe21257c71e11d4e019fca62d517bfdc54",
67
+ "gitHead": "bb9d5f2612ba55375a94815e328954fc8976e07b",
68
68
  "devDependencies": {
69
69
  "ganache": "^7.9.1"
70
70
  }
@@ -89,9 +89,10 @@ export default class PreferencesController
89
89
  userInfo?: UserInfo;
90
90
  rehydrate?: boolean;
91
91
  locale?: string;
92
+ type: string;
92
93
  }): Promise<void> {
93
- const { address, jwtToken, calledFromEmbed, userInfo, rehydrate, locale = "en-US" } = params;
94
- await super.init(address, userInfo, jwtToken);
94
+ const { address, jwtToken, calledFromEmbed, userInfo, rehydrate, locale = "en-US", type } = params;
95
+ await super.init(address, userInfo, jwtToken, { type, email: userInfo.email });
95
96
  const { aggregateVerifier, verifier, verifierId } = userInfo || {};
96
97
  const userExists = await this.sync(address);
97
98
  if (!userExists) {
@@ -218,6 +219,18 @@ export default class PreferencesController
218
219
  }
219
220
  }
220
221
 
222
+ async fetchEtherscanTx<T>(parameters: { selectedAddress: string; selectedNetwork: string }): Promise<T[]> {
223
+ try {
224
+ const url = new URL(`${this.config.api}/etherscan`);
225
+ Object.keys(parameters).forEach((key) => url.searchParams.append(key, parameters[key as keyof typeof parameters]));
226
+ const response = await get<{ success: boolean; data: T[] }>(url.href, this.headers(parameters.selectedAddress));
227
+ return response.success ? response.data : [];
228
+ } catch (error) {
229
+ log.error("unable to fetch etherscan tx", error);
230
+ return [];
231
+ }
232
+ }
233
+
221
234
  public async getEtherScanTokens(address: string, chainId: string): Promise<CustomTokenInfo[]> {
222
235
  const selectedAddress = address;
223
236
  const apiUrl = new URL(this.config.api);
@@ -258,7 +271,7 @@ export default class PreferencesController
258
271
  chain_id: network.chainId,
259
272
  symbol: network.ticker,
260
273
  block_explorer_url: network.blockExplorerUrl || undefined,
261
- is_test_net: network.isTestNet || false,
274
+ is_test_net: network.isTestnet || false,
262
275
  };
263
276
  const res = await post<{ data: CustomNetworks }>(apiUrl.href, payload, this.headers(selectedAddress), { useAPIKey: true });
264
277
  await this.sync(selectedAddress);
@@ -296,7 +309,7 @@ export default class PreferencesController
296
309
  chain_id: network.chainId,
297
310
  symbol: network.ticker || undefined,
298
311
  block_explorer_url: network.blockExplorerUrl || undefined,
299
- is_test_net: network.isTestNet || false,
312
+ is_test_net: network.isTestnet || false,
300
313
  };
301
314
  await patch(apiUrl.href, payload, this.headers(selectedAddress), { useAPIKey: true });
302
315
  await this.sync(selectedAddress);
@@ -110,7 +110,7 @@ export const SUPPORTED_NETWORKS: Record<string, EthereumProviderConfig> = {
110
110
  rpcTarget: `https://goerli.infura.io/v3/${process.env.VITE_APP_INFURA_PROJECT_KEY}`,
111
111
  ticker: "ETH",
112
112
  tickerName: "Ethereum",
113
- isTestNet: true,
113
+ isTestnet: true,
114
114
  },
115
115
  [SEPOLIA_CHAIN_ID]: {
116
116
  blockExplorerUrl: "https://sepolia.etherscan.io",
@@ -120,7 +120,7 @@ export const SUPPORTED_NETWORKS: Record<string, EthereumProviderConfig> = {
120
120
  rpcTarget: `https://sepolia.infura.io/v3/${process.env.VITE_APP_INFURA_PROJECT_KEY}`,
121
121
  ticker: "ETH",
122
122
  tickerName: "Ethereum",
123
- isTestNet: true,
123
+ isTestnet: true,
124
124
  },
125
125
  [POLYGON_MUMBAI_CHAIN_ID]: {
126
126
  blockExplorerUrl: "https://mumbai.polygonscan.com",
@@ -130,7 +130,7 @@ export const SUPPORTED_NETWORKS: Record<string, EthereumProviderConfig> = {
130
130
  rpcTarget: `https://polygon-mumbai.infura.io/v3/${process.env.VITE_APP_INFURA_PROJECT_KEY}`,
131
131
  ticker: "MATIC",
132
132
  tickerName: "Matic Network Token",
133
- isTestNet: true,
133
+ isTestnet: true,
134
134
  },
135
135
  [BSC_TESTNET_CHAIN_ID]: {
136
136
  blockExplorerUrl: "https://testnet.bscscan.com",
@@ -140,7 +140,7 @@ export const SUPPORTED_NETWORKS: Record<string, EthereumProviderConfig> = {
140
140
  rpcTarget: `https://data-seed-prebsc-1-s1.binance.org:8545`,
141
141
  ticker: "BNB",
142
142
  tickerName: "Binance Coin",
143
- isTestNet: true,
143
+ isTestnet: true,
144
144
  },
145
145
  [AVALANCHE_TESTNET_CHAIN_ID]: {
146
146
  blockExplorerUrl: "https://testnet.snowtrace.io",
@@ -150,7 +150,7 @@ export const SUPPORTED_NETWORKS: Record<string, EthereumProviderConfig> = {
150
150
  rpcTarget: `https://api.avax-test.network/ext/bc/C/rpc`,
151
151
  ticker: "AVAX",
152
152
  tickerName: "Avalanche",
153
- isTestNet: true,
153
+ isTestnet: true,
154
154
  },
155
155
  [ARBITRUM_TESTNET_CHAIN_ID]: {
156
156
  blockExplorerUrl: "https://testnet.arbiscan.io",
@@ -160,7 +160,7 @@ export const SUPPORTED_NETWORKS: Record<string, EthereumProviderConfig> = {
160
160
  rpcTarget: `https://arbitrum-rinkeby.infura.io/v3/${process.env.VITE_APP_INFURA_PROJECT_KEY}`,
161
161
  ticker: "ETH",
162
162
  tickerName: "Ethereum",
163
- isTestNet: true,
163
+ isTestnet: true,
164
164
  },
165
165
  [OPTIMISM_TESTNET_CHAIN_ID]: {
166
166
  blockExplorerUrl: "https://goerli-optimism.etherscan.io",
@@ -170,7 +170,7 @@ export const SUPPORTED_NETWORKS: Record<string, EthereumProviderConfig> = {
170
170
  rpcTarget: `https://optimism-goerli.infura.io/v3/${process.env.VITE_APP_INFURA_PROJECT_KEY}`,
171
171
  ticker: "ETH",
172
172
  tickerName: "Ethereum",
173
- isTestNet: true,
173
+ isTestnet: true,
174
174
  },
175
175
  };
176
176
 
@@ -277,7 +277,6 @@ export type PollingBlockTrackerState = BaseBlockTrackerState<EthereumBlock>;
277
277
  export interface EthereumProviderConfig extends ProviderConfig {
278
278
  isErc20?: boolean;
279
279
  tokenAddress?: string;
280
- isTestNet?: boolean;
281
280
  // infuraKey?: string;
282
281
  }
283
282
 
@@ -1,17 +0,0 @@
1
- declare class AbiDecoder {
2
- state: {
3
- savedABIs: any[];
4
- methodIDs: Record<string, any>;
5
- };
6
- constructor(abi: any);
7
- getABIs(): any[];
8
- addABI(abiArray: any): void;
9
- removeABI(abiArray: any): void;
10
- getMethodIDs(): Record<string, any>;
11
- decodeMethod(data: any): {
12
- name: any;
13
- params: any[];
14
- };
15
- decodeLogs(logs: any): any;
16
- }
17
- export default AbiDecoder;
@@ -1,195 +0,0 @@
1
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2
- // @ts-nocheck
3
- // TODO: fix this when working on transaction controller
4
- import BN from "bn.js";
5
- import { AbiCoder, keccak256 } from "ethers";
6
-
7
- class AbiDecoder {
8
- // TODO: update any
9
- state: {
10
- savedABIs: any[];
11
- methodIDs: Record<string, any>;
12
- };
13
-
14
- constructor(abi) {
15
- this.state = {
16
- savedABIs: [],
17
- methodIDs: {},
18
- };
19
- this.addABI(abi);
20
- }
21
-
22
- getABIs() {
23
- return this.state.savedABIs;
24
- }
25
-
26
- addABI(abiArray) {
27
- if (Array.isArray(abiArray)) {
28
- // Iterate new abi to generate method id's
29
- abiArray.map((abi) => {
30
- if (abi.name) {
31
- const signature = keccak256(Buffer.from(`${abi.name}(${abi.inputs.map((input) => input.type).join(",")})`, "utf8"));
32
- if (abi.type === "event") {
33
- this.state.methodIDs[signature.slice(2)] = abi;
34
- } else {
35
- this.state.methodIDs[signature.slice(2, 10)] = abi;
36
- }
37
- }
38
- return undefined;
39
- });
40
-
41
- this.state.savedABIs = [...this.state.savedABIs, ...abiArray];
42
- } else {
43
- throw new TypeError(`Expected ABI array, got ${typeof abiArray}`);
44
- }
45
- }
46
-
47
- removeABI(abiArray) {
48
- if (Array.isArray(abiArray)) {
49
- // Iterate new abi to generate method id's
50
- abiArray.map((abi) => {
51
- if (abi.name) {
52
- const signature = keccak256(Buffer.from(`${abi.name}(${abi.inputs.map((input) => input.type).join(",")})`, "utf8"));
53
- if (abi.type === "event") {
54
- if (this.state.methodIDs[signature.slice(2)]) {
55
- delete this.state.methodIDs[signature.slice(2)];
56
- }
57
- } else if (this.state.methodIDs[signature.slice(2, 10)]) {
58
- delete this.state.methodIDs[signature.slice(2, 10)];
59
- }
60
- }
61
- return undefined;
62
- });
63
- } else {
64
- throw new TypeError(`Expected ABI array, got ${typeof abiArray}`);
65
- }
66
- }
67
-
68
- getMethodIDs() {
69
- return this.state.methodIDs;
70
- }
71
-
72
- decodeMethod(data) {
73
- const methodID = data.slice(2, 10);
74
- const abiItem = this.state.methodIDs[methodID];
75
- if (abiItem) {
76
- const parameters = abiItem.inputs.map((item) => item.type);
77
- const decoded = AbiCoder.defaultAbiCoder().decode(parameters, Buffer.from(data.slice(10), "hex"));
78
-
79
- const returnValueData = {
80
- name: abiItem.name,
81
- params: [],
82
- };
83
-
84
- for (const [i, parameter] of decoded.entries()) {
85
- let parsedParameter = parameter;
86
- const isUint = abiItem.inputs[i].type.indexOf("uint") === 0;
87
- const isInt = abiItem.inputs[i].type.indexOf("int") === 0;
88
- const isAddress = abiItem.inputs[i].type.indexOf("address") === 0;
89
-
90
- if (isUint || isInt) {
91
- const isArray = Array.isArray(parameter);
92
- if (isArray) {
93
- parsedParameter = parameter.map((value) => new BN(value.toString(16), "hex").toString());
94
- } else {
95
- parsedParameter = new BN(parameter.toString(16), "hex").toString();
96
- }
97
- }
98
-
99
- // Addresses returned by web3 are randomly cased so we need to standardize and lowercase all
100
- if (isAddress) {
101
- const isArray = Array.isArray(parameter);
102
-
103
- if (isArray) {
104
- parsedParameter = parameter.map((_) => _.toLowerCase());
105
- } else {
106
- parsedParameter = parameter.toLowerCase();
107
- }
108
- }
109
-
110
- returnValueData.params.push({
111
- name: abiItem.inputs[i].name,
112
- value: parsedParameter,
113
- type: abiItem.inputs[i].type,
114
- });
115
- }
116
-
117
- return returnValueData;
118
- }
119
- return undefined;
120
- }
121
-
122
- decodeLogs(logs) {
123
- return logs
124
- .filter((log) => log.topics.length > 0)
125
- .map((logItem) => {
126
- const methodID = logItem.topics[0].slice(2);
127
- const method = this.state.methodIDs[methodID];
128
- if (method) {
129
- const logData = logItem.data;
130
- const decodedParameters = [];
131
- let dataIndex = 0;
132
- let topicsIndex = 1;
133
-
134
- const dataTypes = [];
135
- method.inputs.map((input) => {
136
- if (!input.indexed) {
137
- dataTypes.push(input.type);
138
- }
139
- return undefined;
140
- });
141
-
142
- const decodedData = AbiCoder.defaultAbiCoder().decode(dataTypes, logData.slice(2));
143
-
144
- // Loop topic and data to get the params
145
- method.inputs.map((parameter) => {
146
- const decodedP = {
147
- name: parameter.name,
148
- type: parameter.type,
149
- value: "",
150
- };
151
-
152
- if (parameter.indexed) {
153
- decodedP.value = logItem.topics[topicsIndex];
154
- topicsIndex += 1;
155
- } else {
156
- decodedP.value = decodedData[dataIndex];
157
- dataIndex += 1;
158
- }
159
-
160
- if (parameter.type === "address") {
161
- decodedP.value = decodedP.value.toLowerCase();
162
- // 42 because len(0x) + 40
163
- if (decodedP.value.length > 42) {
164
- const toRemove = decodedP.value.length - 42;
165
- const temporary = [...decodedP.value];
166
- temporary.splice(2, toRemove);
167
- decodedP.value = temporary.join("");
168
- }
169
- }
170
-
171
- if (parameter.type === "uint256" || parameter.type === "uint8" || parameter.type === "int") {
172
- // ensure to remove leading 0x for hex numbers
173
- if (typeof decodedP.value === "string" && decodedP.value.startsWith("0x")) {
174
- decodedP.value = new BN(decodedP.value.slice(2), 16).toString(10);
175
- } else {
176
- decodedP.value = new BN(decodedP.value).toString(10);
177
- }
178
- }
179
-
180
- decodedParameters.push(decodedP);
181
- return undefined;
182
- });
183
-
184
- return {
185
- name: method.name,
186
- events: decodedParameters,
187
- address: logItem.address,
188
- };
189
- }
190
- return undefined;
191
- });
192
- }
193
- }
194
-
195
- export default AbiDecoder;