@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.
- package/dist/ethereumControllers.cjs.js +26 -11
- package/dist/ethereumControllers.cjs.js.map +1 -1
- package/dist/ethereumControllers.esm.js +26 -11
- package/dist/ethereumControllers.esm.js.map +1 -1
- package/dist/ethereumControllers.umd.min.js +1 -1
- package/dist/ethereumControllers.umd.min.js.map +1 -1
- package/dist/types/Preferences/PreferencesController.d.ts +5 -0
- package/dist/types/utils/interfaces.d.ts +0 -1
- package/package.json +3 -3
- package/src/Preferences/PreferencesController.ts +17 -4
- package/src/utils/constants.ts +7 -7
- package/src/utils/interfaces.ts +0 -1
- package/dist/types/utils/abiDecoder.d.ts +0 -17
- package/src/utils/abiDecoder.ts +0 -195
|
@@ -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.
|
|
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.
|
|
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": "
|
|
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.
|
|
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.
|
|
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);
|
package/src/utils/constants.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
173
|
+
isTestnet: true,
|
|
174
174
|
},
|
|
175
175
|
};
|
|
176
176
|
|
package/src/utils/interfaces.ts
CHANGED
|
@@ -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;
|
package/src/utils/abiDecoder.ts
DELETED
|
@@ -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;
|