@dynamic-labs/ethereum 0.17.9 → 0.17.11

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/CHANGELOG.md CHANGED
@@ -1,4 +1,18 @@
1
1
 
2
+ ### [0.17.11](https://github.com/dynamic-labs/DynamicAuth/compare/v0.17.10...v0.17.11) (2023-06-26)
3
+
4
+
5
+ ### Bug Fixes
6
+
7
+ * multiple improvements for WC2 ([#2465](https://github.com/dynamic-labs/DynamicAuth/issues/2465)) ([7d5d7bd](https://github.com/dynamic-labs/DynamicAuth/commit/7d5d7bdcf2dd01ef3810e2fddd46d56a40effa95)), closes [#2458](https://github.com/dynamic-labs/DynamicAuth/issues/2458)
8
+
9
+ ### [0.17.10](https://github.com/dynamic-labs/DynamicAuth/compare/v0.17.9...v0.17.10) (2023-06-23)
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * use getAuthTokenValue in initExpirationTime ([#2425](https://github.com/dynamic-labs/DynamicAuth/issues/2425)) ([b7e23df](https://github.com/dynamic-labs/DynamicAuth/commit/b7e23df15eb2c40213900ec61d55860ec7aa43f0)), closes [#2423](https://github.com/dynamic-labs/DynamicAuth/issues/2423) [#2422](https://github.com/dynamic-labs/DynamicAuth/issues/2422)
15
+
2
16
  ### [0.17.9](https://github.com/dynamic-labs/DynamicAuth/compare/v0.17.8...v0.17.9) (2023-06-21)
3
17
 
4
18
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynamic-labs/ethereum",
3
- "version": "0.17.9",
3
+ "version": "0.17.11",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/dynamic-labs/DynamicAuth.git",
@@ -30,12 +30,13 @@
30
30
  "@walletconnect/ethereum-provider": "1.8.0",
31
31
  "@walletconnect/universal-provider": "2.8.0",
32
32
  "ethers": "5.7.2",
33
+ "eventemitter3": "5.0.1",
33
34
  "buffer": "6.0.3",
34
- "@dynamic-labs/rpc-providers": "0.17.9",
35
- "@dynamic-labs/types": "0.17.9",
36
- "@dynamic-labs/utils": "0.17.9",
37
- "@dynamic-labs/wallet-book": "0.17.9",
38
- "@dynamic-labs/wallet-connector-core": "0.17.9"
35
+ "@dynamic-labs/rpc-providers": "0.17.11",
36
+ "@dynamic-labs/types": "0.17.11",
37
+ "@dynamic-labs/utils": "0.17.11",
38
+ "@dynamic-labs/wallet-book": "0.17.11",
39
+ "@dynamic-labs/wallet-connector-core": "0.17.11"
39
40
  },
40
41
  "peerDependencies": {}
41
42
  }
package/src/index.cjs CHANGED
@@ -4,13 +4,13 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  require('./polyfills.cjs');
6
6
  var index = require('./injected/index.cjs');
7
- require('@walletconnect/universal-provider');
7
+ require('./walletConnect/walletConnectV2.cjs');
8
+ require('@walletconnect/ethereum-provider');
8
9
  require('ethers');
9
10
  require('@dynamic-labs/wallet-connector-core');
10
11
  require('@dynamic-labs/wallet-book');
11
12
  require('@dynamic-labs/utils');
12
13
  var EthWalletConnector = require('./EthWalletConnector.cjs');
13
- require('@walletconnect/ethereum-provider');
14
14
  var constants = require('./constants.cjs');
15
15
  require('@walletconnect/client');
16
16
  var fetchWalletConnectWallets = require('./walletConnect/fetchWalletConnectWallets.cjs');
package/src/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import './polyfills.js';
2
2
  import { injectedWallets } from './injected/index.js';
3
3
  export { injectedWallets } from './injected/index.js';
4
- import '@walletconnect/universal-provider';
4
+ import './walletConnect/walletConnectV2.js';
5
+ import '@walletconnect/ethereum-provider';
5
6
  import 'ethers';
6
7
  import '@dynamic-labs/wallet-connector-core';
7
8
  import '@dynamic-labs/wallet-book';
8
9
  import '@dynamic-labs/utils';
9
10
  export { EthWalletConnector } from './EthWalletConnector.js';
10
- import '@walletconnect/ethereum-provider';
11
11
  export { INFURA_ID } from './constants.js';
12
12
  import '@walletconnect/client';
13
13
  import { fetchWalletConnectWallets, getWalletConnectConnector } from './walletConnect/fetchWalletConnectWallets.js';
@@ -0,0 +1 @@
1
+ export declare const isString: (value: unknown) => value is string;
@@ -0,0 +1 @@
1
+ export declare const last: <T = unknown>(array: T[]) => T | undefined;
@@ -0,0 +1,22 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var walletConnectorCore = require('@dynamic-labs/wallet-connector-core');
6
+
7
+ const parseIntSafe = (value, radix = 10) => {
8
+ try {
9
+ const int = parseInt(String(value), radix);
10
+ if (isNaN(int)) {
11
+ walletConnectorCore.logger.error(`Error parsing ${value}`);
12
+ return undefined;
13
+ }
14
+ return int;
15
+ }
16
+ catch (e) {
17
+ walletConnectorCore.logger.error(`Error parsing ${value} to int: ${e}`);
18
+ }
19
+ return undefined;
20
+ };
21
+
22
+ exports.parseIntSafe = parseIntSafe;
@@ -0,0 +1 @@
1
+ export declare const parseIntSafe: (value: string | number, radix?: number) => number | undefined;
@@ -0,0 +1,18 @@
1
+ import { logger } from '@dynamic-labs/wallet-connector-core';
2
+
3
+ const parseIntSafe = (value, radix = 10) => {
4
+ try {
5
+ const int = parseInt(String(value), radix);
6
+ if (isNaN(int)) {
7
+ logger.error(`Error parsing ${value}`);
8
+ return undefined;
9
+ }
10
+ return int;
11
+ }
12
+ catch (e) {
13
+ logger.error(`Error parsing ${value} to int: ${e}`);
14
+ }
15
+ return undefined;
16
+ };
17
+
18
+ export { parseIntSafe };
@@ -5,21 +5,27 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var _tslib = require('../../_virtual/_tslib.cjs');
6
6
  var Provider = require('@walletconnect/universal-provider');
7
7
  var ethers = require('ethers');
8
+ var EventEmitter = require('eventemitter3');
8
9
  var walletConnectorCore = require('@dynamic-labs/wallet-connector-core');
9
10
  var walletBook = require('@dynamic-labs/wallet-book');
10
11
  var utils = require('@dynamic-labs/utils');
11
12
  var EthWalletConnector = require('../EthWalletConnector.cjs');
13
+ var parseIntSafe = require('../utils/parseIntSafe.cjs');
12
14
 
13
15
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
14
16
 
15
17
  var Provider__default = /*#__PURE__*/_interopDefaultLegacy(Provider);
18
+ var EventEmitter__default = /*#__PURE__*/_interopDefaultLegacy(EventEmitter);
16
19
 
20
+ const activeAccountKey = (walletName) => `dynamic-wc2-active-account-${walletName}`;
17
21
  const sessionTopicKey = (walletName) => `dynamic-wc2-session-topic-${walletName}`;
22
+ const ee = new EventEmitter__default["default"]();
18
23
  class WalletConnectV2 extends EthWalletConnector.EthWalletConnector {
19
24
  constructor(opts) {
20
25
  super(opts);
21
26
  this.supportedChains = ['EVM', 'ETH'];
22
27
  this.connectedChain = 'EVM';
28
+ this.isInitialized = false;
23
29
  this.canConnectViaQrCode = true;
24
30
  this.isWalletConnect = true;
25
31
  this.name = opts.walletName;
@@ -35,24 +41,39 @@ class WalletConnectV2 extends EthWalletConnector.EthWalletConnector {
35
41
  if (provider === null || provider === void 0 ? void 0 : provider.uri) {
36
42
  return;
37
43
  }
38
- yield provider.connect({
44
+ const defaultChain = 1;
45
+ provider
46
+ .connect({
39
47
  namespaces: {
48
+ eip155: {
49
+ chains: [`eip155:${defaultChain}`],
50
+ events: ['chainChanged', 'accountsChanged'],
51
+ methods: ['personal_sign', 'eth_sendTransaction'],
52
+ rpcMap: this.evmNetworkRpcMap(),
53
+ },
54
+ },
55
+ optionalNamespaces: {
40
56
  eip155: {
41
57
  chains: this.evmNetworks
42
- // filtering out Palm for now since it causes Trust to crash
43
- .filter((network) => network.chainId !== 11297108109)
58
+ // Filters out mainnet which is required and palm that crashes Trust Wallet
59
+ .filter((network) => network.chainId !== 11297108109 &&
60
+ network.chainId !== defaultChain)
44
61
  .map((network) => `eip155:${network.chainId}`),
45
- events: ['chainChanged', 'accountsChanged'],
62
+ events: [],
46
63
  methods: [
47
- 'eth_sendTransaction',
64
+ 'eth_signTypedData',
48
65
  'eth_signTransaction',
49
66
  'eth_sign',
50
67
  'personal_sign',
51
- 'eth_signTypedData',
68
+ 'eth_sendTransaction',
52
69
  ],
53
70
  rpcMap: this.evmNetworkRpcMap(),
54
71
  },
55
72
  },
73
+ })
74
+ .catch((e) => {
75
+ walletConnectorCore.logger.error(e);
76
+ ee.emit('walletconnect_connection_failed');
56
77
  });
57
78
  });
58
79
  }
@@ -80,11 +101,34 @@ class WalletConnectV2 extends EthWalletConnector.EthWalletConnector {
80
101
  return _tslib.__awaiter(this, void 0, void 0, function* () {
81
102
  yield this.initProvider();
82
103
  yield this.initConnection();
104
+ this.isInitialized = true;
83
105
  });
84
106
  }
85
107
  get sessionTopicKey() {
86
108
  return sessionTopicKey(this.key);
87
109
  }
110
+ get activeAccountKey() {
111
+ return activeAccountKey(this.key);
112
+ }
113
+ get activeAccount() {
114
+ if (this._activeAccount) {
115
+ return this._activeAccount;
116
+ }
117
+ const account = localStorage.getItem(this.activeAccountKey);
118
+ if (!account) {
119
+ return undefined;
120
+ }
121
+ this._activeAccount = account;
122
+ return account;
123
+ }
124
+ set activeAccount(account) {
125
+ if (!account) {
126
+ localStorage.removeItem(this.activeAccountKey);
127
+ return;
128
+ }
129
+ localStorage.setItem(this.activeAccountKey, account);
130
+ this._activeAccount = account;
131
+ }
88
132
  supportsNetworkSwitching() {
89
133
  return true;
90
134
  }
@@ -100,18 +144,22 @@ class WalletConnectV2 extends EthWalletConnector.EthWalletConnector {
100
144
  }
101
145
  const { name, data } = params.event;
102
146
  if (name === 'chainChanged') {
103
- if (typeof data !== 'string') {
147
+ const chainId = parseIntSafe.parseIntSafe(data);
148
+ if (chainId === undefined) {
104
149
  walletConnectorCore.logger.debug(`received unexpected data for chainChanged: ${data} with type ${typeof data}}`);
105
150
  return;
106
151
  }
107
- (_a = listeners.onChainChange) === null || _a === void 0 ? void 0 : _a.call(listeners, data);
152
+ (_a = listeners.onChainChange) === null || _a === void 0 ? void 0 : _a.call(listeners, String(chainId));
108
153
  }
109
154
  else if (name === 'accountsChanged') {
110
- if (typeof data !== 'string' || !Array.isArray(data)) {
155
+ if (!Array.isArray(data)) {
111
156
  walletConnectorCore.logger.debug(`received unexpected data for accountsChanged: ${data} with type ${typeof data}}`);
112
157
  return;
113
158
  }
114
- (_b = listeners.onAccountChange) === null || _b === void 0 ? void 0 : _b.call(listeners, data);
159
+ // eslint-disable-next-line prefer-destructuring
160
+ const account = data[0].split(':')[2];
161
+ this.activeAccount = account;
162
+ (_b = listeners.onAccountChange) === null || _b === void 0 ? void 0 : _b.call(listeners, [account]);
115
163
  }
116
164
  });
117
165
  WalletConnectV2.provider.client.on('session_delete', () => _tslib.__awaiter(this, void 0, void 0, function* () {
@@ -148,15 +196,19 @@ class WalletConnectV2 extends EthWalletConnector.EthWalletConnector {
148
196
  return new ethers.ethers.providers.Web3Provider(WalletConnectV2.provider, 'any');
149
197
  }
150
198
  fetchPublicAddress(opts) {
199
+ var _a, _b;
151
200
  return _tslib.__awaiter(this, void 0, void 0, function* () {
152
- if (this.session) {
153
- return this.session.namespaces.eip155.accounts[0].split(':')[2];
154
- }
155
- if (!WalletConnectV2.provider) {
156
- throw new utils.DynamicError('No provider found');
201
+ if (this.activeAccount) {
202
+ return this.activeAccount;
157
203
  }
158
- if (!WalletConnectV2.provider.uri) {
159
- throw new utils.DynamicError('No uri found');
204
+ if (!WalletConnectV2.provider || !((_a = WalletConnectV2.provider) === null || _a === void 0 ? void 0 : _a.uri)) {
205
+ walletConnectorCore.logger.debug('No WC2 provider found, re-initializing...');
206
+ yield this.endSession();
207
+ yield this.init();
208
+ if (!WalletConnectV2.provider || !((_b = WalletConnectV2.provider) === null || _b === void 0 ? void 0 : _b.uri)) {
209
+ walletConnectorCore.logger.debug('No WC2 provider found, escaping and throwing error');
210
+ throw new utils.DynamicError('No provider found');
211
+ }
160
212
  }
161
213
  const metadata = walletBook.getWalletBookWallet(this.name);
162
214
  walletConnectorCore.performPlatformSpecificConnectionMethod(WalletConnectV2.provider.uri, metadata, {
@@ -168,13 +220,21 @@ class WalletConnectV2 extends EthWalletConnector.EthWalletConnector {
168
220
  reject(new utils.DynamicError('No provider found'));
169
221
  return;
170
222
  }
223
+ ee.on('walletconnect_connection_failed', () => {
224
+ const error = new utils.DynamicError('Connection rejected. Please try again.');
225
+ error.code = 'connection_rejected';
226
+ reject(error);
227
+ });
171
228
  WalletConnectV2.provider.on('connect', ({ session }) => {
172
229
  if (!session) {
173
230
  reject(new utils.DynamicError('No session found'));
174
231
  }
175
232
  this.session = session;
176
233
  localStorage.setItem(this.sessionTopicKey, session.topic);
177
- resolve(this.session.namespaces.eip155.accounts[0].split(':')[2]);
234
+ // eslint-disable-next-line prefer-destructuring
235
+ this.activeAccount =
236
+ this.session.namespaces.eip155.accounts[0].split(':')[2];
237
+ resolve(this.activeAccount);
178
238
  });
179
239
  });
180
240
  });
@@ -194,13 +254,25 @@ class WalletConnectV2 extends EthWalletConnector.EthWalletConnector {
194
254
  const deepLink = walletConnectorCore.getDeepLink({ metadata, mode: 'regular' });
195
255
  window.location.href = deepLink;
196
256
  }
197
- // eslint-disable-next-line prefer-destructuring
198
- const address = this.session.namespaces.eip155.accounts[0].split(':')[2];
199
257
  const web3Provider = this.getWeb3Provider();
200
- return web3Provider.send('personal_sign', [
258
+ const response = web3Provider.send('personal_sign', [
201
259
  walletConnectorCore.utf8ToHex(messageToSign, true),
202
- address,
260
+ this.activeAccount,
203
261
  ]);
262
+ try {
263
+ // A terrible hack to get MM to sign the message when it is on the wrong chain
264
+ // Since MM supports only one chain at a time, it just hangs when we call
265
+ // to sign, and it is not on Mainnet. For some magical reason,
266
+ // when we attempt to call again it just works.
267
+ if (this.key === 'metamask') {
268
+ yield this.promiseWithTimeout(7000, response);
269
+ }
270
+ }
271
+ catch (e) {
272
+ walletConnectorCore.logger.debug('metmask failed to sign message');
273
+ throw e;
274
+ }
275
+ return response;
204
276
  });
205
277
  }
206
278
  endSession() {
@@ -216,12 +288,22 @@ class WalletConnectV2 extends EthWalletConnector.EthWalletConnector {
216
288
  WalletConnectV2.provider.uri = undefined;
217
289
  localStorage.removeItem(this.sessionTopicKey);
218
290
  this.session = undefined;
291
+ this.activeAccount = undefined;
219
292
  }
220
293
  catch (e) {
221
294
  walletConnectorCore.logger.debug(e);
222
295
  }
223
296
  });
224
297
  }
298
+ getNetwork() {
299
+ const _super = Object.create(null, {
300
+ getNetwork: { get: () => super.getNetwork }
301
+ });
302
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
303
+ yield this.initProvider();
304
+ return _super.getNetwork.call(this);
305
+ });
306
+ }
225
307
  providerSwitchNetwork({ network, provider, }) {
226
308
  const _super = Object.create(null, {
227
309
  providerSwitchNetwork: { get: () => super.providerSwitchNetwork }
@@ -244,14 +326,46 @@ class WalletConnectV2 extends EthWalletConnector.EthWalletConnector {
244
326
  });
245
327
  }
246
328
  getConnectedAccounts() {
329
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
330
+ yield this.initProvider();
331
+ this.refreshSession();
332
+ this.isInitialized = true;
333
+ if (!this.activeAccount) {
334
+ return [];
335
+ }
336
+ return [this.activeAccount];
337
+ });
338
+ }
339
+ getSupportedNetworks() {
247
340
  return _tslib.__awaiter(this, void 0, void 0, function* () {
248
341
  yield this.initProvider();
249
342
  this.refreshSession();
250
343
  if (!this.session) {
251
344
  return [];
252
345
  }
253
- return [this.session.namespaces.eip155.accounts[0].split(':')[2]];
346
+ const chains = [];
347
+ // Some wallet (i.e ZenGo) use namespaces.account to list supported chains
348
+ // while others use keys within the namespaces object
349
+ Object.keys(this.session.namespaces).forEach((key) => {
350
+ if (key.startsWith('eip155:')) {
351
+ chains.push(key.split(':')[1]);
352
+ }
353
+ });
354
+ this.session.namespaces.eip155.accounts.forEach((account) => chains.push(account.split(':')[1]));
355
+ return chains.length ? chains : undefined;
356
+ });
357
+ }
358
+ // a HACK for MM to sign message when the selected chain is not mainnet
359
+ promiseWithTimeout(ms, promise) {
360
+ // Create a promise that rejects in <ms> milliseconds
361
+ const timeout = new Promise((_, reject) => {
362
+ const id = setTimeout(() => {
363
+ clearTimeout(id);
364
+ reject(new utils.DynamicError(undefined, 'metamask_timeout'));
365
+ }, ms);
254
366
  });
367
+ // Returns a race between our timeout and the passed in promise
368
+ return Promise.race([promise, timeout]);
255
369
  }
256
370
  }
257
371
 
@@ -12,6 +12,8 @@ export declare class WalletConnectV2 extends EthWalletConnector {
12
12
  connectedChain: Chain;
13
13
  name: string;
14
14
  session: SessionTypes.Struct | undefined;
15
+ _activeAccount: string | undefined;
16
+ isInitialized: boolean;
15
17
  canConnectViaQrCode: boolean;
16
18
  isWalletConnect: boolean;
17
19
  private static provider;
@@ -22,6 +24,9 @@ export declare class WalletConnectV2 extends EthWalletConnector {
22
24
  private refreshSession;
23
25
  init(): Promise<void>;
24
26
  get sessionTopicKey(): string;
27
+ get activeAccountKey(): string;
28
+ get activeAccount(): string | undefined;
29
+ set activeAccount(account: string | undefined);
25
30
  supportsNetworkSwitching(): boolean;
26
31
  setupEventListeners(listeners: WalletEventListeners): void;
27
32
  teardownEventListeners(): void;
@@ -30,9 +35,12 @@ export declare class WalletConnectV2 extends EthWalletConnector {
30
35
  fetchPublicAddress(opts?: FetchPublicAddressOpts): Promise<string | undefined>;
31
36
  signMessage(messageToSign: string): Promise<string | undefined>;
32
37
  endSession(): Promise<void>;
38
+ getNetwork(): Promise<number | undefined>;
33
39
  providerSwitchNetwork({ network, provider, }: {
34
40
  network: EvmNetwork;
35
41
  provider: ethers.providers.Web3Provider;
36
42
  }): Promise<void>;
37
43
  getConnectedAccounts(): Promise<string[]>;
44
+ getSupportedNetworks(): Promise<string[] | undefined>;
45
+ private promiseWithTimeout;
38
46
  }
@@ -1,17 +1,22 @@
1
1
  import { __awaiter } from '../../_virtual/_tslib.js';
2
2
  import Provider from '@walletconnect/universal-provider';
3
3
  import { ethers } from 'ethers';
4
+ import EventEmitter from 'eventemitter3';
4
5
  import { logger, getDeepLink, performPlatformSpecificConnectionMethod, utf8ToHex } from '@dynamic-labs/wallet-connector-core';
5
6
  import { getWalletBookWallet } from '@dynamic-labs/wallet-book';
6
7
  import { DynamicError, isMobile } from '@dynamic-labs/utils';
7
8
  import { EthWalletConnector } from '../EthWalletConnector.js';
9
+ import { parseIntSafe } from '../utils/parseIntSafe.js';
8
10
 
11
+ const activeAccountKey = (walletName) => `dynamic-wc2-active-account-${walletName}`;
9
12
  const sessionTopicKey = (walletName) => `dynamic-wc2-session-topic-${walletName}`;
13
+ const ee = new EventEmitter();
10
14
  class WalletConnectV2 extends EthWalletConnector {
11
15
  constructor(opts) {
12
16
  super(opts);
13
17
  this.supportedChains = ['EVM', 'ETH'];
14
18
  this.connectedChain = 'EVM';
19
+ this.isInitialized = false;
15
20
  this.canConnectViaQrCode = true;
16
21
  this.isWalletConnect = true;
17
22
  this.name = opts.walletName;
@@ -27,24 +32,39 @@ class WalletConnectV2 extends EthWalletConnector {
27
32
  if (provider === null || provider === void 0 ? void 0 : provider.uri) {
28
33
  return;
29
34
  }
30
- yield provider.connect({
35
+ const defaultChain = 1;
36
+ provider
37
+ .connect({
31
38
  namespaces: {
39
+ eip155: {
40
+ chains: [`eip155:${defaultChain}`],
41
+ events: ['chainChanged', 'accountsChanged'],
42
+ methods: ['personal_sign', 'eth_sendTransaction'],
43
+ rpcMap: this.evmNetworkRpcMap(),
44
+ },
45
+ },
46
+ optionalNamespaces: {
32
47
  eip155: {
33
48
  chains: this.evmNetworks
34
- // filtering out Palm for now since it causes Trust to crash
35
- .filter((network) => network.chainId !== 11297108109)
49
+ // Filters out mainnet which is required and palm that crashes Trust Wallet
50
+ .filter((network) => network.chainId !== 11297108109 &&
51
+ network.chainId !== defaultChain)
36
52
  .map((network) => `eip155:${network.chainId}`),
37
- events: ['chainChanged', 'accountsChanged'],
53
+ events: [],
38
54
  methods: [
39
- 'eth_sendTransaction',
55
+ 'eth_signTypedData',
40
56
  'eth_signTransaction',
41
57
  'eth_sign',
42
58
  'personal_sign',
43
- 'eth_signTypedData',
59
+ 'eth_sendTransaction',
44
60
  ],
45
61
  rpcMap: this.evmNetworkRpcMap(),
46
62
  },
47
63
  },
64
+ })
65
+ .catch((e) => {
66
+ logger.error(e);
67
+ ee.emit('walletconnect_connection_failed');
48
68
  });
49
69
  });
50
70
  }
@@ -72,11 +92,34 @@ class WalletConnectV2 extends EthWalletConnector {
72
92
  return __awaiter(this, void 0, void 0, function* () {
73
93
  yield this.initProvider();
74
94
  yield this.initConnection();
95
+ this.isInitialized = true;
75
96
  });
76
97
  }
77
98
  get sessionTopicKey() {
78
99
  return sessionTopicKey(this.key);
79
100
  }
101
+ get activeAccountKey() {
102
+ return activeAccountKey(this.key);
103
+ }
104
+ get activeAccount() {
105
+ if (this._activeAccount) {
106
+ return this._activeAccount;
107
+ }
108
+ const account = localStorage.getItem(this.activeAccountKey);
109
+ if (!account) {
110
+ return undefined;
111
+ }
112
+ this._activeAccount = account;
113
+ return account;
114
+ }
115
+ set activeAccount(account) {
116
+ if (!account) {
117
+ localStorage.removeItem(this.activeAccountKey);
118
+ return;
119
+ }
120
+ localStorage.setItem(this.activeAccountKey, account);
121
+ this._activeAccount = account;
122
+ }
80
123
  supportsNetworkSwitching() {
81
124
  return true;
82
125
  }
@@ -92,18 +135,22 @@ class WalletConnectV2 extends EthWalletConnector {
92
135
  }
93
136
  const { name, data } = params.event;
94
137
  if (name === 'chainChanged') {
95
- if (typeof data !== 'string') {
138
+ const chainId = parseIntSafe(data);
139
+ if (chainId === undefined) {
96
140
  logger.debug(`received unexpected data for chainChanged: ${data} with type ${typeof data}}`);
97
141
  return;
98
142
  }
99
- (_a = listeners.onChainChange) === null || _a === void 0 ? void 0 : _a.call(listeners, data);
143
+ (_a = listeners.onChainChange) === null || _a === void 0 ? void 0 : _a.call(listeners, String(chainId));
100
144
  }
101
145
  else if (name === 'accountsChanged') {
102
- if (typeof data !== 'string' || !Array.isArray(data)) {
146
+ if (!Array.isArray(data)) {
103
147
  logger.debug(`received unexpected data for accountsChanged: ${data} with type ${typeof data}}`);
104
148
  return;
105
149
  }
106
- (_b = listeners.onAccountChange) === null || _b === void 0 ? void 0 : _b.call(listeners, data);
150
+ // eslint-disable-next-line prefer-destructuring
151
+ const account = data[0].split(':')[2];
152
+ this.activeAccount = account;
153
+ (_b = listeners.onAccountChange) === null || _b === void 0 ? void 0 : _b.call(listeners, [account]);
107
154
  }
108
155
  });
109
156
  WalletConnectV2.provider.client.on('session_delete', () => __awaiter(this, void 0, void 0, function* () {
@@ -140,15 +187,19 @@ class WalletConnectV2 extends EthWalletConnector {
140
187
  return new ethers.providers.Web3Provider(WalletConnectV2.provider, 'any');
141
188
  }
142
189
  fetchPublicAddress(opts) {
190
+ var _a, _b;
143
191
  return __awaiter(this, void 0, void 0, function* () {
144
- if (this.session) {
145
- return this.session.namespaces.eip155.accounts[0].split(':')[2];
146
- }
147
- if (!WalletConnectV2.provider) {
148
- throw new DynamicError('No provider found');
192
+ if (this.activeAccount) {
193
+ return this.activeAccount;
149
194
  }
150
- if (!WalletConnectV2.provider.uri) {
151
- throw new DynamicError('No uri found');
195
+ if (!WalletConnectV2.provider || !((_a = WalletConnectV2.provider) === null || _a === void 0 ? void 0 : _a.uri)) {
196
+ logger.debug('No WC2 provider found, re-initializing...');
197
+ yield this.endSession();
198
+ yield this.init();
199
+ if (!WalletConnectV2.provider || !((_b = WalletConnectV2.provider) === null || _b === void 0 ? void 0 : _b.uri)) {
200
+ logger.debug('No WC2 provider found, escaping and throwing error');
201
+ throw new DynamicError('No provider found');
202
+ }
152
203
  }
153
204
  const metadata = getWalletBookWallet(this.name);
154
205
  performPlatformSpecificConnectionMethod(WalletConnectV2.provider.uri, metadata, {
@@ -160,13 +211,21 @@ class WalletConnectV2 extends EthWalletConnector {
160
211
  reject(new DynamicError('No provider found'));
161
212
  return;
162
213
  }
214
+ ee.on('walletconnect_connection_failed', () => {
215
+ const error = new DynamicError('Connection rejected. Please try again.');
216
+ error.code = 'connection_rejected';
217
+ reject(error);
218
+ });
163
219
  WalletConnectV2.provider.on('connect', ({ session }) => {
164
220
  if (!session) {
165
221
  reject(new DynamicError('No session found'));
166
222
  }
167
223
  this.session = session;
168
224
  localStorage.setItem(this.sessionTopicKey, session.topic);
169
- resolve(this.session.namespaces.eip155.accounts[0].split(':')[2]);
225
+ // eslint-disable-next-line prefer-destructuring
226
+ this.activeAccount =
227
+ this.session.namespaces.eip155.accounts[0].split(':')[2];
228
+ resolve(this.activeAccount);
170
229
  });
171
230
  });
172
231
  });
@@ -186,13 +245,25 @@ class WalletConnectV2 extends EthWalletConnector {
186
245
  const deepLink = getDeepLink({ metadata, mode: 'regular' });
187
246
  window.location.href = deepLink;
188
247
  }
189
- // eslint-disable-next-line prefer-destructuring
190
- const address = this.session.namespaces.eip155.accounts[0].split(':')[2];
191
248
  const web3Provider = this.getWeb3Provider();
192
- return web3Provider.send('personal_sign', [
249
+ const response = web3Provider.send('personal_sign', [
193
250
  utf8ToHex(messageToSign, true),
194
- address,
251
+ this.activeAccount,
195
252
  ]);
253
+ try {
254
+ // A terrible hack to get MM to sign the message when it is on the wrong chain
255
+ // Since MM supports only one chain at a time, it just hangs when we call
256
+ // to sign, and it is not on Mainnet. For some magical reason,
257
+ // when we attempt to call again it just works.
258
+ if (this.key === 'metamask') {
259
+ yield this.promiseWithTimeout(7000, response);
260
+ }
261
+ }
262
+ catch (e) {
263
+ logger.debug('metmask failed to sign message');
264
+ throw e;
265
+ }
266
+ return response;
196
267
  });
197
268
  }
198
269
  endSession() {
@@ -208,12 +279,22 @@ class WalletConnectV2 extends EthWalletConnector {
208
279
  WalletConnectV2.provider.uri = undefined;
209
280
  localStorage.removeItem(this.sessionTopicKey);
210
281
  this.session = undefined;
282
+ this.activeAccount = undefined;
211
283
  }
212
284
  catch (e) {
213
285
  logger.debug(e);
214
286
  }
215
287
  });
216
288
  }
289
+ getNetwork() {
290
+ const _super = Object.create(null, {
291
+ getNetwork: { get: () => super.getNetwork }
292
+ });
293
+ return __awaiter(this, void 0, void 0, function* () {
294
+ yield this.initProvider();
295
+ return _super.getNetwork.call(this);
296
+ });
297
+ }
217
298
  providerSwitchNetwork({ network, provider, }) {
218
299
  const _super = Object.create(null, {
219
300
  providerSwitchNetwork: { get: () => super.providerSwitchNetwork }
@@ -236,14 +317,46 @@ class WalletConnectV2 extends EthWalletConnector {
236
317
  });
237
318
  }
238
319
  getConnectedAccounts() {
320
+ return __awaiter(this, void 0, void 0, function* () {
321
+ yield this.initProvider();
322
+ this.refreshSession();
323
+ this.isInitialized = true;
324
+ if (!this.activeAccount) {
325
+ return [];
326
+ }
327
+ return [this.activeAccount];
328
+ });
329
+ }
330
+ getSupportedNetworks() {
239
331
  return __awaiter(this, void 0, void 0, function* () {
240
332
  yield this.initProvider();
241
333
  this.refreshSession();
242
334
  if (!this.session) {
243
335
  return [];
244
336
  }
245
- return [this.session.namespaces.eip155.accounts[0].split(':')[2]];
337
+ const chains = [];
338
+ // Some wallet (i.e ZenGo) use namespaces.account to list supported chains
339
+ // while others use keys within the namespaces object
340
+ Object.keys(this.session.namespaces).forEach((key) => {
341
+ if (key.startsWith('eip155:')) {
342
+ chains.push(key.split(':')[1]);
343
+ }
344
+ });
345
+ this.session.namespaces.eip155.accounts.forEach((account) => chains.push(account.split(':')[1]));
346
+ return chains.length ? chains : undefined;
347
+ });
348
+ }
349
+ // a HACK for MM to sign message when the selected chain is not mainnet
350
+ promiseWithTimeout(ms, promise) {
351
+ // Create a promise that rejects in <ms> milliseconds
352
+ const timeout = new Promise((_, reject) => {
353
+ const id = setTimeout(() => {
354
+ clearTimeout(id);
355
+ reject(new DynamicError(undefined, 'metamask_timeout'));
356
+ }, ms);
246
357
  });
358
+ // Returns a race between our timeout and the passed in promise
359
+ return Promise.race([promise, timeout]);
247
360
  }
248
361
  }
249
362