@dynamic-labs/ethereum 0.18.0-RC.7 → 0.18.0-RC.9

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,48 @@
1
1
 
2
+ ## [0.18.0-RC.9](https://github.com/dynamic-labs/DynamicAuth/compare/v0.18.0-RC.8...v0.18.0-RC.9) (2023-07-04)
3
+
4
+
5
+ ### Features
6
+
7
+ * add Network Not Supported prompt to connect-only & show prompt before sign in connect-sign mode ([#2474](https://github.com/dynamic-labs/DynamicAuth/issues/2474)) ([8d5bfa9](https://github.com/dynamic-labs/DynamicAuth/commit/8d5bfa97ca4da50e06ce258a38a63e7407a795f6))
8
+ * **DYN-2602:** add ability to unlink connected wallet ([#2494](https://github.com/dynamic-labs/DynamicAuth/issues/2494)) ([389861b](https://github.com/dynamic-labs/DynamicAuth/commit/389861bc0281baec379b1593e529cef3467f3326))
9
+ * **DYN-2604:** add chainId property to walletsByChain object ([#2405](https://github.com/dynamic-labs/DynamicAuth/issues/2405)) ([d9b42f7](https://github.com/dynamic-labs/DynamicAuth/commit/d9b42f7b1d53dac1ed0228ecb5e56a44c6abd8d2))
10
+ * **DynamicAuthLayout:** show connected wallet progress ([#2567](https://github.com/dynamic-labs/DynamicAuth/issues/2567)) ([a20ff6f](https://github.com/dynamic-labs/DynamicAuth/commit/a20ff6f32b360ccc699d2a271c7a96751ae87d29))
11
+ * **DynamicBridgeFlow:** add bridge flow ([#2543](https://github.com/dynamic-labs/DynamicAuth/issues/2543)) ([79c4c87](https://github.com/dynamic-labs/DynamicAuth/commit/79c4c870d47a0c853c292a8d913bd9be9e209a15))
12
+
13
+
14
+ ### Bug Fixes
15
+
16
+ * don't force required chain to eth in case is not enabled ([#2537](https://github.com/dynamic-labs/DynamicAuth/issues/2537)) ([b01d6c9](https://github.com/dynamic-labs/DynamicAuth/commit/b01d6c9e91e9971e82739c5a2c900de4768f977c))
17
+ * log out if there's any session sync issue ([#2545](https://github.com/dynamic-labs/DynamicAuth/issues/2545)) ([29972fa](https://github.com/dynamic-labs/DynamicAuth/commit/29972fad1067f5550a61f6e2cd9adcaf811fd268))
18
+ * persist chain to WalletConnect session when changed in wallet ([#2556](https://github.com/dynamic-labs/DynamicAuth/issues/2556)) ([fc9ec35](https://github.com/dynamic-labs/DynamicAuth/commit/fc9ec3501de1e3235adee4df95b296dc22cce23e))
19
+ * WC2 sign-message on non-selected chain ([#2544](https://github.com/dynamic-labs/DynamicAuth/issues/2544)) ([48a4384](https://github.com/dynamic-labs/DynamicAuth/commit/48a4384f77c29775e0c28ed335956cfbd6f89ca3))
20
+ * **wcv2:** add eth_signTypedData_v4 to optional methods ([#2527](https://github.com/dynamic-labs/DynamicAuth/issues/2527)) ([b99474b](https://github.com/dynamic-labs/DynamicAuth/commit/b99474b81b083134762be0fe9554a6f049b3edda))
21
+ * **wcv2:** allow getWeb3Provider to wait to provider init ([#2523](https://github.com/dynamic-labs/DynamicAuth/issues/2523)) ([d9c7fee](https://github.com/dynamic-labs/DynamicAuth/commit/d9c7fee10d2a6c766043515e19829fd7e3d5b2ef))
22
+
23
+ ## [0.18.0-RC.8](https://github.com/dynamic-labs/DynamicAuth/compare/v0.18.0-RC.7...v0.18.0-RC.8) (2023-06-29)
24
+
25
+
26
+ ### Features
27
+
28
+ * add support for custom walletconnect v1 bridge ([#2487](https://github.com/dynamic-labs/DynamicAuth/issues/2487)) ([5b0ca2e](https://github.com/dynamic-labs/DynamicAuth/commit/5b0ca2e4e8aa241ed13e4f38346c31da8479a6c4))
29
+ * **DYN-2623:** improve error message on sign cancellation for wallets ([#2493](https://github.com/dynamic-labs/DynamicAuth/issues/2493)) ([081c515](https://github.com/dynamic-labs/DynamicAuth/commit/081c515c9d28d6fa4c0eaac388ee421a7b23144b))
30
+
31
+
32
+ ### Bug Fixes
33
+
34
+ * clearing the activeAccount value ([#2469](https://github.com/dynamic-labs/DynamicAuth/issues/2469)) ([ff75bde](https://github.com/dynamic-labs/DynamicAuth/commit/ff75bde938a4178541568b79754f773607b9d87f))
35
+ * don't initialize provider if it's already initialized ([#2490](https://github.com/dynamic-labs/DynamicAuth/issues/2490)) ([878d38f](https://github.com/dynamic-labs/DynamicAuth/commit/878d38f5c8d7d7448c65e58b25cefd9f3518217e))
36
+ * more wcv2 improvements ([#2475](https://github.com/dynamic-labs/DynamicAuth/issues/2475)) ([13baa84](https://github.com/dynamic-labs/DynamicAuth/commit/13baa84218d6259d02df7d8c387b40dc3cb11ce5)), closes [#2469](https://github.com/dynamic-labs/DynamicAuth/issues/2469) [#2470](https://github.com/dynamic-labs/DynamicAuth/issues/2470) [#2471](https://github.com/dynamic-labs/DynamicAuth/issues/2471) [#2477](https://github.com/dynamic-labs/DynamicAuth/issues/2477) [#2479](https://github.com/dynamic-labs/DynamicAuth/issues/2479) [#2471](https://github.com/dynamic-labs/DynamicAuth/issues/2471) [#2476](https://github.com/dynamic-labs/DynamicAuth/issues/2476)
37
+ * multiple improvements for WC2 ([#2458](https://github.com/dynamic-labs/DynamicAuth/issues/2458)) ([0813af2](https://github.com/dynamic-labs/DynamicAuth/commit/0813af2aafa8019868117084efe8ae147ac24581))
38
+ * revert changes since latest wcv2 improvements ([#2473](https://github.com/dynamic-labs/DynamicAuth/issues/2473)) ([3375371](https://github.com/dynamic-labs/DynamicAuth/commit/337537101a13d67b860748b62f172eba01d0b461)), closes [#2471](https://github.com/dynamic-labs/DynamicAuth/issues/2471) [#2470](https://github.com/dynamic-labs/DynamicAuth/issues/2470) [#2469](https://github.com/dynamic-labs/DynamicAuth/issues/2469)
39
+ * sync issue within connect-only mode ([#2496](https://github.com/dynamic-labs/DynamicAuth/issues/2496)) ([44af274](https://github.com/dynamic-labs/DynamicAuth/commit/44af274618c30fe65ec95739cd16a8ddde08e34e))
40
+ * typo in terms of service ([#2401](https://github.com/dynamic-labs/DynamicAuth/issues/2401)) ([5b195e5](https://github.com/dynamic-labs/DynamicAuth/commit/5b195e54479d9a88bd017fc45f2f2455d1caedc4))
41
+ * **wc_v1_bridget:** disable WC v2 when WC v1 bridge is set ([#2505](https://github.com/dynamic-labs/DynamicAuth/issues/2505)) ([b3f0a68](https://github.com/dynamic-labs/DynamicAuth/commit/b3f0a6895095bb37c635984fc970b52446e04f56))
42
+ * wc2 android improvements ([#2488](https://github.com/dynamic-labs/DynamicAuth/issues/2488)) ([f60ef9c](https://github.com/dynamic-labs/DynamicAuth/commit/f60ef9c1dd672f78199eee40edbe2707c043e1b5))
43
+ * **wcv2:** make sure to clear active account when ending session ([#2471](https://github.com/dynamic-labs/DynamicAuth/issues/2471)) ([b766df3](https://github.com/dynamic-labs/DynamicAuth/commit/b766df39a7e4dabc54fda9131b7bd9b53895cf2f))
44
+ * **wcv2:** use native or universal link when signing message ([#2502](https://github.com/dynamic-labs/DynamicAuth/issues/2502)) ([6e3e3fb](https://github.com/dynamic-labs/DynamicAuth/commit/6e3e3fbb58fb9e3eb314e6631ac2123237f41e8c))
45
+
2
46
  ## [0.18.0-RC.7](https://github.com/dynamic-labs/DynamicAuth/compare/v0.18.0-RC.6...v0.18.0-RC.7) (2023-06-23)
3
47
 
4
48
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynamic-labs/ethereum",
3
- "version": "0.18.0-RC.7",
3
+ "version": "0.18.0-RC.9",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/dynamic-labs/DynamicAuth.git",
@@ -28,14 +28,15 @@
28
28
  "dependencies": {
29
29
  "@walletconnect/client": "1.8.0",
30
30
  "@walletconnect/ethereum-provider": "1.8.0",
31
- "@walletconnect/universal-provider": "2.8.0",
31
+ "@walletconnect/universal-provider": "2.8.3",
32
32
  "ethers": "5.7.2",
33
+ "eventemitter3": "5.0.1",
33
34
  "buffer": "6.0.3",
34
- "@dynamic-labs/rpc-providers": "0.18.0-RC.7",
35
- "@dynamic-labs/types": "0.18.0-RC.7",
36
- "@dynamic-labs/utils": "0.18.0-RC.7",
37
- "@dynamic-labs/wallet-book": "0.18.0-RC.7",
38
- "@dynamic-labs/wallet-connector-core": "0.18.0-RC.7"
35
+ "@dynamic-labs/rpc-providers": "0.18.0-RC.9",
36
+ "@dynamic-labs/types": "0.18.0-RC.9",
37
+ "@dynamic-labs/utils": "0.18.0-RC.9",
38
+ "@dynamic-labs/wallet-book": "0.18.0-RC.9",
39
+ "@dynamic-labs/wallet-connector-core": "0.18.0-RC.9"
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 };
@@ -12,12 +12,12 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
12
12
 
13
13
  var Client__default = /*#__PURE__*/_interopDefaultLegacy(Client);
14
14
 
15
- const initClient = (name, settings) => {
15
+ const initClient = (name, bridge, settings) => {
16
16
  const storageId = `walletconnect-${name}`;
17
17
  const session = localStorage.getItem(storageId);
18
18
  const clientArgs = session
19
19
  ? { session: JSON.parse(session), storageId }
20
- : { bridge: 'https://bridge.walletconnect.org', storageId };
20
+ : { bridge, storageId };
21
21
  return new Client__default["default"](Object.assign(Object.assign({}, clientArgs), settings));
22
22
  };
23
23
  /**
@@ -2,7 +2,7 @@ import Client from '@walletconnect/client';
2
2
  import { ethers } from 'ethers';
3
3
  import { FetchPublicAddressOpts, PayloadParams, WalletEventListeners } from '@dynamic-labs/wallet-connector-core';
4
4
  import { WalletSchema } from '@dynamic-labs/wallet-book';
5
- export declare const initClient: (name: string, settings?: any) => Client;
5
+ export declare const initClient: (name: string, bridge: string, settings?: any) => Client;
6
6
  /**
7
7
  * Attach event handlers to WalletConnect events.
8
8
  */
@@ -4,12 +4,12 @@ import { Contract, ethers } from 'ethers';
4
4
  import { isSameAddress, logger, performPlatformSpecificConnectionMethod, getDeepLink } from '@dynamic-labs/wallet-connector-core';
5
5
  import { isMobile } from '@dynamic-labs/utils';
6
6
 
7
- const initClient = (name, settings) => {
7
+ const initClient = (name, bridge, settings) => {
8
8
  const storageId = `walletconnect-${name}`;
9
9
  const session = localStorage.getItem(storageId);
10
10
  const clientArgs = session
11
11
  ? { session: JSON.parse(session), storageId }
12
- : { bridge: 'https://bridge.walletconnect.org', storageId };
12
+ : { bridge, storageId };
13
13
  return new Client(Object.assign(Object.assign({}, clientArgs), settings));
14
14
  };
15
15
  /**
@@ -18,20 +18,24 @@ var WalletConnectProvider__default = /*#__PURE__*/_interopDefaultLegacy(WalletCo
18
18
 
19
19
  class WalletConnect extends EthWalletConnector.EthWalletConnector {
20
20
  constructor(_a) {
21
- var { walletName } = _a, props = _tslib.__rest(_a, ["walletName"]);
21
+ var { walletConnectV1Bridge, walletName } = _a, props = _tslib.__rest(_a, ["walletConnectV1Bridge", "walletName"]);
22
22
  super(props);
23
23
  this.supportedChains = ['EVM', 'ETH'];
24
24
  this.connectedChain = 'EVM';
25
+ this.bridge = 'https://bridge.walletconnect.org';
25
26
  this.canConnectViaQrCode = true;
26
27
  this.isWalletConnect = true;
27
28
  this.switchNetworkOnlyFromWallet = false;
28
29
  this.name = walletName;
30
+ if (walletConnectV1Bridge) {
31
+ this.bridge = walletConnectV1Bridge;
32
+ }
29
33
  }
30
34
  getClient() {
31
35
  if (this.client) {
32
36
  return this.client;
33
37
  }
34
- this.client = client.initClient(walletConnectorCore.normalizeWalletName(this.name), this.clientOptions);
38
+ this.client = client.initClient(walletConnectorCore.normalizeWalletName(this.name), this.bridge, this.clientOptions);
35
39
  return this.client;
36
40
  }
37
41
  supportsNetworkSwitching() {
@@ -135,6 +139,12 @@ class WalletConnect extends EthWalletConnector.EthWalletConnector {
135
139
  return client.accounts;
136
140
  });
137
141
  }
142
+ getSession() {
143
+ var _a;
144
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
145
+ return (_a = this.client) === null || _a === void 0 ? void 0 : _a.session;
146
+ });
147
+ }
138
148
  }
139
149
 
140
150
  exports.WalletConnect = WalletConnect;
@@ -3,19 +3,34 @@ import { ethers } from 'ethers';
3
3
  import { Chain, FetchPublicAddressOpts, WalletEventListeners } from '@dynamic-labs/wallet-connector-core';
4
4
  import { EvmNetwork } from '@dynamic-labs/types';
5
5
  import { EthWalletConnector, EthWalletConnectorOpts } from '../EthWalletConnector';
6
+ type ConnectorSession = {
7
+ connected: boolean;
8
+ accounts: string[];
9
+ chainId: number;
10
+ bridge: string;
11
+ key: string;
12
+ clientId: string;
13
+ clientMeta: any;
14
+ peerId: string;
15
+ peerMeta: any;
16
+ handshakeId: number;
17
+ handshakeTopic: string;
18
+ };
6
19
  export type WalletConnectOpts = EthWalletConnectorOpts & {
20
+ walletConnectV1Bridge: string;
7
21
  walletName: string;
8
22
  };
9
23
  export declare class WalletConnect extends EthWalletConnector {
10
24
  supportedChains: Chain[];
11
25
  connectedChain: Chain;
12
26
  name: string;
27
+ bridge: string;
13
28
  canConnectViaQrCode: boolean;
14
29
  isWalletConnect: boolean;
15
30
  switchNetworkOnlyFromWallet: boolean;
16
31
  client?: Client;
17
32
  clientOptions?: any;
18
- constructor({ walletName, ...props }: WalletConnectOpts);
33
+ constructor({ walletConnectV1Bridge, walletName, ...props }: WalletConnectOpts);
19
34
  getClient(): Client;
20
35
  supportsNetworkSwitching(): boolean;
21
36
  setupEventListeners(listeners: WalletEventListeners): void;
@@ -30,4 +45,6 @@ export declare class WalletConnect extends EthWalletConnector {
30
45
  provider: ethers.providers.Web3Provider;
31
46
  }): Promise<void>;
32
47
  getConnectedAccounts(): Promise<string[]>;
48
+ getSession(): Promise<ConnectorSession | undefined>;
33
49
  }
50
+ export {};
@@ -10,20 +10,24 @@ import { initClient, setupWalletConnectEventListeners, teardownWalletConnectEven
10
10
 
11
11
  class WalletConnect extends EthWalletConnector {
12
12
  constructor(_a) {
13
- var { walletName } = _a, props = __rest(_a, ["walletName"]);
13
+ var { walletConnectV1Bridge, walletName } = _a, props = __rest(_a, ["walletConnectV1Bridge", "walletName"]);
14
14
  super(props);
15
15
  this.supportedChains = ['EVM', 'ETH'];
16
16
  this.connectedChain = 'EVM';
17
+ this.bridge = 'https://bridge.walletconnect.org';
17
18
  this.canConnectViaQrCode = true;
18
19
  this.isWalletConnect = true;
19
20
  this.switchNetworkOnlyFromWallet = false;
20
21
  this.name = walletName;
22
+ if (walletConnectV1Bridge) {
23
+ this.bridge = walletConnectV1Bridge;
24
+ }
21
25
  }
22
26
  getClient() {
23
27
  if (this.client) {
24
28
  return this.client;
25
29
  }
26
- this.client = initClient(normalizeWalletName(this.name), this.clientOptions);
30
+ this.client = initClient(normalizeWalletName(this.name), this.bridge, this.clientOptions);
27
31
  return this.client;
28
32
  }
29
33
  supportsNetworkSwitching() {
@@ -127,6 +131,12 @@ class WalletConnect extends EthWalletConnector {
127
131
  return client.accounts;
128
132
  });
129
133
  }
134
+ getSession() {
135
+ var _a;
136
+ return __awaiter(this, void 0, void 0, function* () {
137
+ return (_a = this.client) === null || _a === void 0 ? void 0 : _a.session;
138
+ });
139
+ }
130
140
  }
131
141
 
132
142
  export { WalletConnect };
@@ -5,27 +5,34 @@ 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;
26
32
  this.projectId = opts.projectId;
27
33
  }
28
34
  initConnection() {
35
+ var _a;
29
36
  return _tslib.__awaiter(this, void 0, void 0, function* () {
30
37
  const { provider } = WalletConnectV2;
31
38
  if (!provider) {
@@ -35,44 +42,73 @@ class WalletConnectV2 extends EthWalletConnector.EthWalletConnector {
35
42
  if (provider === null || provider === void 0 ? void 0 : provider.uri) {
36
43
  return;
37
44
  }
38
- yield provider.connect({
45
+ const defaultChain = ((_a = this.evmNetworks) === null || _a === void 0 ? void 0 : _a.length)
46
+ ? this.evmNetworks[0].chainId
47
+ : 1;
48
+ provider
49
+ .connect({
39
50
  namespaces: {
51
+ eip155: {
52
+ chains: [`eip155:${defaultChain}`],
53
+ events: ['chainChanged', 'accountsChanged'],
54
+ methods: ['personal_sign', 'eth_sendTransaction'],
55
+ rpcMap: this.evmNetworkRpcMap(),
56
+ },
57
+ },
58
+ optionalNamespaces: {
40
59
  eip155: {
41
60
  chains: this.evmNetworks
42
- // filtering out Palm for now since it causes Trust to crash
43
- .filter((network) => network.chainId !== 11297108109)
61
+ // Filters out mainnet which is required and palm that crashes Trust Wallet
62
+ .filter((network) => network.chainId !== 11297108109 &&
63
+ network.chainId !== defaultChain)
44
64
  .map((network) => `eip155:${network.chainId}`),
45
- events: ['chainChanged', 'accountsChanged'],
65
+ events: [],
46
66
  methods: [
47
- 'eth_sendTransaction',
67
+ 'eth_signTypedData',
48
68
  'eth_signTransaction',
49
69
  'eth_sign',
50
70
  'personal_sign',
51
- 'eth_signTypedData',
71
+ 'eth_sendTransaction',
72
+ 'eth_signTypedData_v4',
52
73
  ],
53
74
  rpcMap: this.evmNetworkRpcMap(),
54
75
  },
55
76
  },
77
+ })
78
+ .catch((e) => {
79
+ walletConnectorCore.logger.error(e);
80
+ ee.emit('walletconnect_connection_failed');
81
+ });
82
+ });
83
+ }
84
+ createInitProviderPromise() {
85
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
86
+ const provider = yield Provider__default["default"].init({
87
+ logger: walletConnectorCore.logger.logLevel.toLowerCase() === 'debug' ? 'debug' : undefined,
88
+ projectId: this.projectId,
56
89
  });
90
+ WalletConnectV2.provider = provider;
57
91
  });
58
92
  }
59
93
  initProvider() {
60
94
  return _tslib.__awaiter(this, void 0, void 0, function* () {
61
- let { provider } = WalletConnectV2;
95
+ const { provider } = WalletConnectV2;
62
96
  if (!provider) {
63
- provider = yield Provider__default["default"].init({
64
- projectId: this.projectId,
65
- });
66
- WalletConnectV2.provider = provider;
97
+ if (this.initializePromise === undefined) {
98
+ this.initializePromise = this.createInitProviderPromise();
99
+ }
100
+ yield this.initializePromise;
67
101
  }
68
102
  });
69
103
  }
70
104
  refreshSession() {
71
- var _a, _b, _c, _d;
105
+ var _a, _b, _c, _d, _e;
72
106
  if ((_b = (_a = WalletConnectV2.provider) === null || _a === void 0 ? void 0 : _a.session) === null || _b === void 0 ? void 0 : _b.topic) {
73
107
  if (localStorage.getItem(this.sessionTopicKey) ===
74
108
  ((_d = (_c = WalletConnectV2.provider) === null || _c === void 0 ? void 0 : _c.session) === null || _d === void 0 ? void 0 : _d.topic)) {
75
109
  this.session = WalletConnectV2.provider.session;
110
+ this.activeAccount =
111
+ (_e = localStorage.getItem(this.activeAccountKey)) !== null && _e !== void 0 ? _e : undefined;
76
112
  }
77
113
  }
78
114
  }
@@ -80,11 +116,15 @@ class WalletConnectV2 extends EthWalletConnector.EthWalletConnector {
80
116
  return _tslib.__awaiter(this, void 0, void 0, function* () {
81
117
  yield this.initProvider();
82
118
  yield this.initConnection();
119
+ this.isInitialized = true;
83
120
  });
84
121
  }
85
122
  get sessionTopicKey() {
86
123
  return sessionTopicKey(this.key);
87
124
  }
125
+ get activeAccountKey() {
126
+ return activeAccountKey(this.key);
127
+ }
88
128
  supportsNetworkSwitching() {
89
129
  return true;
90
130
  }
@@ -100,23 +140,30 @@ class WalletConnectV2 extends EthWalletConnector.EthWalletConnector {
100
140
  }
101
141
  const { name, data } = params.event;
102
142
  if (name === 'chainChanged') {
103
- if (typeof data !== 'string') {
143
+ const chainId = parseIntSafe.parseIntSafe(data);
144
+ if (chainId === undefined) {
104
145
  walletConnectorCore.logger.debug(`received unexpected data for chainChanged: ${data} with type ${typeof data}}`);
105
146
  return;
106
147
  }
107
- (_a = listeners.onChainChange) === null || _a === void 0 ? void 0 : _a.call(listeners, data);
148
+ (_a = listeners.onChainChange) === null || _a === void 0 ? void 0 : _a.call(listeners, String(chainId));
149
+ // When a user switches network from their wallet, we need the provider to change network
150
+ // such that any future calls to `getNetwork` will return the correct network
151
+ this.switchNetwork({ networkChainId: chainId });
108
152
  }
109
153
  else if (name === 'accountsChanged') {
110
- if (typeof data !== 'string' || !Array.isArray(data)) {
154
+ if (!Array.isArray(data)) {
111
155
  walletConnectorCore.logger.debug(`received unexpected data for accountsChanged: ${data} with type ${typeof data}}`);
112
156
  return;
113
157
  }
114
- (_b = listeners.onAccountChange) === null || _b === void 0 ? void 0 : _b.call(listeners, data);
158
+ // eslint-disable-next-line prefer-destructuring
159
+ const account = data[0].split(':')[2];
160
+ this.setActiveAccount(account);
161
+ (_b = listeners.onAccountChange) === null || _b === void 0 ? void 0 : _b.call(listeners, [account]);
115
162
  }
116
163
  });
117
164
  WalletConnectV2.provider.client.on('session_delete', () => _tslib.__awaiter(this, void 0, void 0, function* () {
118
165
  var _a;
119
- localStorage.removeItem(this.sessionTopicKey);
166
+ this.endSession();
120
167
  yield ((_a = listeners.onDisconnect) === null || _a === void 0 ? void 0 : _a.call(listeners));
121
168
  }));
122
169
  }
@@ -127,36 +174,32 @@ class WalletConnectV2 extends EthWalletConnector.EthWalletConnector {
127
174
  WalletConnectV2.provider.client.removeAllListeners('session_event');
128
175
  WalletConnectV2.provider.client.removeAllListeners('session_delete');
129
176
  }
130
- getDeepLink() {
131
- var _a, _b;
132
- if (!((_a = WalletConnectV2.provider) === null || _a === void 0 ? void 0 : _a.uri))
133
- return;
134
- const wallet = walletBook.getWalletBookWallet(this.walletBook, this.name);
135
- if (!utils.isMobile() && !((_b = wallet.desktop) === null || _b === void 0 ? void 0 : _b.native)) {
136
- return undefined;
137
- }
138
- return walletConnectorCore.getDeepLink({
139
- metadata: wallet,
140
- mode: 'regular',
141
- uri: WalletConnectV2.provider.uri,
142
- });
143
- }
144
177
  getWeb3Provider() {
145
178
  if (!WalletConnectV2.provider) {
146
- throw new Error('No provider found');
179
+ return;
147
180
  }
148
181
  return new ethers.ethers.providers.Web3Provider(WalletConnectV2.provider, 'any');
149
182
  }
150
183
  fetchPublicAddress(opts) {
184
+ var _a, _b;
151
185
  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');
186
+ if (this.activeAccount) {
187
+ return this.activeAccount;
157
188
  }
158
- if (!WalletConnectV2.provider.uri) {
159
- throw new utils.DynamicError('No uri found');
189
+ if (!WalletConnectV2.provider || !((_a = WalletConnectV2.provider) === null || _a === void 0 ? void 0 : _a.uri)) {
190
+ walletConnectorCore.logger.debug('No WC2 provider found, re-initializing...');
191
+ yield this.endSession();
192
+ yield this.init();
193
+ // sleep 1 s to wait for connect call to finish
194
+ // the connect call isn't await-ed because it only resolves once
195
+ // the connection is established, but we need to wait for it to
196
+ // finish setting up the connection URI and making it available
197
+ // on the provider
198
+ yield new Promise((resolve) => setTimeout(resolve, 1000));
199
+ if (!WalletConnectV2.provider || !((_b = WalletConnectV2.provider) === null || _b === void 0 ? void 0 : _b.uri)) {
200
+ walletConnectorCore.logger.debug('No WC2 provider found, escaping and throwing error');
201
+ throw new utils.DynamicError('No provider found');
202
+ }
160
203
  }
161
204
  const metadata = walletBook.getWalletBookWallet(this.walletBook, this.name);
162
205
  walletConnectorCore.performPlatformSpecificConnectionMethod(WalletConnectV2.provider.uri, metadata, {
@@ -168,18 +211,56 @@ class WalletConnectV2 extends EthWalletConnector.EthWalletConnector {
168
211
  reject(new utils.DynamicError('No provider found'));
169
212
  return;
170
213
  }
214
+ ee.on('walletconnect_connection_failed', () => {
215
+ const error = new utils.DynamicError('Connection rejected. Please try again.');
216
+ error.code = 'connection_rejected';
217
+ if (WalletConnectV2.provider) {
218
+ WalletConnectV2.provider.uri = undefined;
219
+ }
220
+ reject(error);
221
+ });
171
222
  WalletConnectV2.provider.on('connect', ({ session }) => {
172
223
  if (!session) {
173
224
  reject(new utils.DynamicError('No session found'));
174
225
  }
175
- this.session = session;
176
- localStorage.setItem(this.sessionTopicKey, session.topic);
177
- resolve(this.session.namespaces.eip155.accounts[0].split(':')[2]);
226
+ this.setSession(session);
227
+ this.setActiveAccount(session.namespaces.eip155.accounts[0].split(':')[2]);
228
+ resolve(this.activeAccount);
229
+ });
230
+ });
231
+ });
232
+ }
233
+ /**
234
+ * WalletConnect V2 will fail to send the sign message request if the chainId
235
+ * is not the same as the one in the session. This method will wait for the
236
+ * chainId to change and then retry the sign message request.
237
+ *
238
+ * Otherwise it will just return the result of the sign message request.
239
+ *
240
+ * @param signMessageFn - Function to sign message with provider
241
+ * @param messageToSign - Message to sign
242
+ * @returns
243
+ */
244
+ waitForSignMessage(signMessageFn, messageToSign) {
245
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
246
+ const raceConditionPromise = new Promise((resolve) => {
247
+ // Create listener for chain change event
248
+ this.setupEventListeners({
249
+ onChainChange: () => _tslib.__awaiter(this, void 0, void 0, function* () {
250
+ resolve({ success: false });
251
+ }),
178
252
  });
253
+ signMessageFn(messageToSign).then((result) => resolve({ signedMessage: result, success: true }));
179
254
  });
255
+ const signedMessageResult = yield raceConditionPromise;
256
+ if (signedMessageResult.success === false) {
257
+ return signMessageFn(messageToSign);
258
+ }
259
+ return signedMessageResult.signedMessage;
180
260
  });
181
261
  }
182
262
  signMessage(messageToSign) {
263
+ var _a, _b;
183
264
  return _tslib.__awaiter(this, void 0, void 0, function* () {
184
265
  if (!this.session) {
185
266
  throw new utils.DynamicError('no session');
@@ -189,39 +270,67 @@ class WalletConnectV2 extends EthWalletConnector.EthWalletConnector {
189
270
  }
190
271
  const metadata = walletBook.getWalletBookWallet(this.walletBook, this.name);
191
272
  if (utils.isMobile()) {
192
- // for sign message, no uri is needed because the uri encodes connection details,
193
- // and at this point we are already connected
194
- const deepLink = walletConnectorCore.getDeepLink({ metadata, mode: 'regular' });
273
+ const deepLink = ((_a = metadata['mobile']) === null || _a === void 0 ? void 0 : _a.native) || ((_b = metadata['mobile']) === null || _b === void 0 ? void 0 : _b.universal) || '';
195
274
  window.location.href = deepLink;
196
275
  }
197
- // eslint-disable-next-line prefer-destructuring
198
- const address = this.session.namespaces.eip155.accounts[0].split(':')[2];
199
276
  const web3Provider = this.getWeb3Provider();
200
- return web3Provider.send('personal_sign', [
201
- walletConnectorCore.utf8ToHex(messageToSign, true),
202
- address,
203
- ]);
277
+ if (!web3Provider) {
278
+ throw new utils.DynamicError('No web3 provider found');
279
+ }
280
+ const signMessageFn = (messageToSign) => _tslib.__awaiter(this, void 0, void 0, function* () {
281
+ return web3Provider.send('personal_sign', [
282
+ walletConnectorCore.utf8ToHex(messageToSign, true),
283
+ this.activeAccount,
284
+ ]);
285
+ });
286
+ const response = yield this.waitForSignMessage(signMessageFn, messageToSign);
287
+ return response;
204
288
  });
205
289
  }
290
+ clearActiveAccount() {
291
+ localStorage.removeItem(this.activeAccountKey);
292
+ this.activeAccount = undefined;
293
+ }
294
+ clearSession() {
295
+ localStorage.removeItem(this.sessionTopicKey);
296
+ this.session = undefined;
297
+ }
298
+ setActiveAccount(account) {
299
+ localStorage.setItem(this.activeAccountKey, account);
300
+ this.activeAccount = account;
301
+ }
302
+ setSession(session) {
303
+ localStorage.setItem(this.sessionTopicKey, session.topic);
304
+ this.session = session;
305
+ }
206
306
  endSession() {
307
+ var _a;
207
308
  return _tslib.__awaiter(this, void 0, void 0, function* () {
208
- if (!this.session) {
209
- return;
210
- }
211
- if (!WalletConnectV2.provider) {
309
+ this.clearActiveAccount();
310
+ this.clearSession();
311
+ if (!((_a = WalletConnectV2.provider) === null || _a === void 0 ? void 0 : _a.session)) {
212
312
  return;
213
313
  }
214
314
  try {
215
315
  yield WalletConnectV2.provider.disconnect();
216
- WalletConnectV2.provider.uri = undefined;
217
- localStorage.removeItem(this.sessionTopicKey);
218
- this.session = undefined;
316
+ // We must unset provider on logout so that a new session can be established
317
+ // If we don't then the provider will still have the old session and will hang
318
+ WalletConnectV2.provider = undefined;
219
319
  }
220
320
  catch (e) {
221
321
  walletConnectorCore.logger.debug(e);
222
322
  }
223
323
  });
224
324
  }
325
+ getNetwork() {
326
+ const _super = Object.create(null, {
327
+ getNetwork: { get: () => super.getNetwork }
328
+ });
329
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
330
+ yield this.initProvider();
331
+ return _super.getNetwork.call(this);
332
+ });
333
+ }
225
334
  providerSwitchNetwork({ network, provider, }) {
226
335
  const _super = Object.create(null, {
227
336
  providerSwitchNetwork: { get: () => super.providerSwitchNetwork }
@@ -244,13 +353,33 @@ class WalletConnectV2 extends EthWalletConnector.EthWalletConnector {
244
353
  });
245
354
  }
246
355
  getConnectedAccounts() {
356
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
357
+ yield this.initProvider();
358
+ this.refreshSession();
359
+ this.isInitialized = true;
360
+ if (!this.activeAccount) {
361
+ return [];
362
+ }
363
+ return [this.activeAccount];
364
+ });
365
+ }
366
+ getSupportedNetworks() {
247
367
  return _tslib.__awaiter(this, void 0, void 0, function* () {
248
368
  yield this.initProvider();
249
369
  this.refreshSession();
250
370
  if (!this.session) {
251
371
  return [];
252
372
  }
253
- return [this.session.namespaces.eip155.accounts[0].split(':')[2]];
373
+ const chains = [];
374
+ // Some wallet (i.e ZenGo) use namespaces.account to list supported chains
375
+ // while others use keys within the namespaces object
376
+ Object.keys(this.session.namespaces).forEach((key) => {
377
+ if (key.startsWith('eip155:')) {
378
+ chains.push(key.split(':')[1]);
379
+ }
380
+ });
381
+ this.session.namespaces.eip155.accounts.forEach((account) => chains.push(account.split(':')[1]));
382
+ return chains.length ? chains : undefined;
254
383
  });
255
384
  }
256
385
  }
@@ -12,27 +12,49 @@ 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;
17
+ initializePromise: Promise<void> | undefined;
15
18
  canConnectViaQrCode: boolean;
16
19
  isWalletConnect: boolean;
17
20
  private static provider;
18
21
  private projectId?;
19
22
  constructor(opts: WalletConnectorV2Opts);
20
23
  private initConnection;
24
+ private createInitProviderPromise;
21
25
  private initProvider;
22
26
  private refreshSession;
23
27
  init(): Promise<void>;
24
28
  get sessionTopicKey(): string;
29
+ get activeAccountKey(): string;
25
30
  supportsNetworkSwitching(): boolean;
26
31
  setupEventListeners(listeners: WalletEventListeners): void;
27
32
  teardownEventListeners(): void;
28
- getDeepLink(): string | undefined;
29
- getWeb3Provider(): ethers.providers.Web3Provider;
33
+ getWeb3Provider(): ethers.providers.Web3Provider | undefined;
30
34
  fetchPublicAddress(opts?: FetchPublicAddressOpts): Promise<string | undefined>;
35
+ /**
36
+ * WalletConnect V2 will fail to send the sign message request if the chainId
37
+ * is not the same as the one in the session. This method will wait for the
38
+ * chainId to change and then retry the sign message request.
39
+ *
40
+ * Otherwise it will just return the result of the sign message request.
41
+ *
42
+ * @param signMessageFn - Function to sign message with provider
43
+ * @param messageToSign - Message to sign
44
+ * @returns
45
+ */
46
+ protected waitForSignMessage(signMessageFn: (messageToSign: string) => Promise<string | undefined>, messageToSign: string): Promise<string | undefined>;
31
47
  signMessage(messageToSign: string): Promise<string | undefined>;
48
+ private clearActiveAccount;
49
+ private clearSession;
50
+ private setActiveAccount;
51
+ private setSession;
32
52
  endSession(): Promise<void>;
53
+ getNetwork(): Promise<number | undefined>;
33
54
  providerSwitchNetwork({ network, provider, }: {
34
55
  network: EvmNetwork;
35
56
  provider: ethers.providers.Web3Provider;
36
57
  }): Promise<void>;
37
58
  getConnectedAccounts(): Promise<string[]>;
59
+ getSupportedNetworks(): Promise<string[] | undefined>;
38
60
  }
@@ -1,23 +1,29 @@
1
1
  import { __awaiter } from '../../_virtual/_tslib.js';
2
2
  import Provider from '@walletconnect/universal-provider';
3
3
  import { ethers } from 'ethers';
4
- import { logger, getDeepLink, performPlatformSpecificConnectionMethod, utf8ToHex } from '@dynamic-labs/wallet-connector-core';
4
+ import EventEmitter from 'eventemitter3';
5
+ import { logger, 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;
18
23
  this.projectId = opts.projectId;
19
24
  }
20
25
  initConnection() {
26
+ var _a;
21
27
  return __awaiter(this, void 0, void 0, function* () {
22
28
  const { provider } = WalletConnectV2;
23
29
  if (!provider) {
@@ -27,44 +33,73 @@ class WalletConnectV2 extends EthWalletConnector {
27
33
  if (provider === null || provider === void 0 ? void 0 : provider.uri) {
28
34
  return;
29
35
  }
30
- yield provider.connect({
36
+ const defaultChain = ((_a = this.evmNetworks) === null || _a === void 0 ? void 0 : _a.length)
37
+ ? this.evmNetworks[0].chainId
38
+ : 1;
39
+ provider
40
+ .connect({
31
41
  namespaces: {
42
+ eip155: {
43
+ chains: [`eip155:${defaultChain}`],
44
+ events: ['chainChanged', 'accountsChanged'],
45
+ methods: ['personal_sign', 'eth_sendTransaction'],
46
+ rpcMap: this.evmNetworkRpcMap(),
47
+ },
48
+ },
49
+ optionalNamespaces: {
32
50
  eip155: {
33
51
  chains: this.evmNetworks
34
- // filtering out Palm for now since it causes Trust to crash
35
- .filter((network) => network.chainId !== 11297108109)
52
+ // Filters out mainnet which is required and palm that crashes Trust Wallet
53
+ .filter((network) => network.chainId !== 11297108109 &&
54
+ network.chainId !== defaultChain)
36
55
  .map((network) => `eip155:${network.chainId}`),
37
- events: ['chainChanged', 'accountsChanged'],
56
+ events: [],
38
57
  methods: [
39
- 'eth_sendTransaction',
58
+ 'eth_signTypedData',
40
59
  'eth_signTransaction',
41
60
  'eth_sign',
42
61
  'personal_sign',
43
- 'eth_signTypedData',
62
+ 'eth_sendTransaction',
63
+ 'eth_signTypedData_v4',
44
64
  ],
45
65
  rpcMap: this.evmNetworkRpcMap(),
46
66
  },
47
67
  },
68
+ })
69
+ .catch((e) => {
70
+ logger.error(e);
71
+ ee.emit('walletconnect_connection_failed');
72
+ });
73
+ });
74
+ }
75
+ createInitProviderPromise() {
76
+ return __awaiter(this, void 0, void 0, function* () {
77
+ const provider = yield Provider.init({
78
+ logger: logger.logLevel.toLowerCase() === 'debug' ? 'debug' : undefined,
79
+ projectId: this.projectId,
48
80
  });
81
+ WalletConnectV2.provider = provider;
49
82
  });
50
83
  }
51
84
  initProvider() {
52
85
  return __awaiter(this, void 0, void 0, function* () {
53
- let { provider } = WalletConnectV2;
86
+ const { provider } = WalletConnectV2;
54
87
  if (!provider) {
55
- provider = yield Provider.init({
56
- projectId: this.projectId,
57
- });
58
- WalletConnectV2.provider = provider;
88
+ if (this.initializePromise === undefined) {
89
+ this.initializePromise = this.createInitProviderPromise();
90
+ }
91
+ yield this.initializePromise;
59
92
  }
60
93
  });
61
94
  }
62
95
  refreshSession() {
63
- var _a, _b, _c, _d;
96
+ var _a, _b, _c, _d, _e;
64
97
  if ((_b = (_a = WalletConnectV2.provider) === null || _a === void 0 ? void 0 : _a.session) === null || _b === void 0 ? void 0 : _b.topic) {
65
98
  if (localStorage.getItem(this.sessionTopicKey) ===
66
99
  ((_d = (_c = WalletConnectV2.provider) === null || _c === void 0 ? void 0 : _c.session) === null || _d === void 0 ? void 0 : _d.topic)) {
67
100
  this.session = WalletConnectV2.provider.session;
101
+ this.activeAccount =
102
+ (_e = localStorage.getItem(this.activeAccountKey)) !== null && _e !== void 0 ? _e : undefined;
68
103
  }
69
104
  }
70
105
  }
@@ -72,11 +107,15 @@ class WalletConnectV2 extends EthWalletConnector {
72
107
  return __awaiter(this, void 0, void 0, function* () {
73
108
  yield this.initProvider();
74
109
  yield this.initConnection();
110
+ this.isInitialized = true;
75
111
  });
76
112
  }
77
113
  get sessionTopicKey() {
78
114
  return sessionTopicKey(this.key);
79
115
  }
116
+ get activeAccountKey() {
117
+ return activeAccountKey(this.key);
118
+ }
80
119
  supportsNetworkSwitching() {
81
120
  return true;
82
121
  }
@@ -92,23 +131,30 @@ class WalletConnectV2 extends EthWalletConnector {
92
131
  }
93
132
  const { name, data } = params.event;
94
133
  if (name === 'chainChanged') {
95
- if (typeof data !== 'string') {
134
+ const chainId = parseIntSafe(data);
135
+ if (chainId === undefined) {
96
136
  logger.debug(`received unexpected data for chainChanged: ${data} with type ${typeof data}}`);
97
137
  return;
98
138
  }
99
- (_a = listeners.onChainChange) === null || _a === void 0 ? void 0 : _a.call(listeners, data);
139
+ (_a = listeners.onChainChange) === null || _a === void 0 ? void 0 : _a.call(listeners, String(chainId));
140
+ // When a user switches network from their wallet, we need the provider to change network
141
+ // such that any future calls to `getNetwork` will return the correct network
142
+ this.switchNetwork({ networkChainId: chainId });
100
143
  }
101
144
  else if (name === 'accountsChanged') {
102
- if (typeof data !== 'string' || !Array.isArray(data)) {
145
+ if (!Array.isArray(data)) {
103
146
  logger.debug(`received unexpected data for accountsChanged: ${data} with type ${typeof data}}`);
104
147
  return;
105
148
  }
106
- (_b = listeners.onAccountChange) === null || _b === void 0 ? void 0 : _b.call(listeners, data);
149
+ // eslint-disable-next-line prefer-destructuring
150
+ const account = data[0].split(':')[2];
151
+ this.setActiveAccount(account);
152
+ (_b = listeners.onAccountChange) === null || _b === void 0 ? void 0 : _b.call(listeners, [account]);
107
153
  }
108
154
  });
109
155
  WalletConnectV2.provider.client.on('session_delete', () => __awaiter(this, void 0, void 0, function* () {
110
156
  var _a;
111
- localStorage.removeItem(this.sessionTopicKey);
157
+ this.endSession();
112
158
  yield ((_a = listeners.onDisconnect) === null || _a === void 0 ? void 0 : _a.call(listeners));
113
159
  }));
114
160
  }
@@ -119,36 +165,32 @@ class WalletConnectV2 extends EthWalletConnector {
119
165
  WalletConnectV2.provider.client.removeAllListeners('session_event');
120
166
  WalletConnectV2.provider.client.removeAllListeners('session_delete');
121
167
  }
122
- getDeepLink() {
123
- var _a, _b;
124
- if (!((_a = WalletConnectV2.provider) === null || _a === void 0 ? void 0 : _a.uri))
125
- return;
126
- const wallet = getWalletBookWallet(this.walletBook, this.name);
127
- if (!isMobile() && !((_b = wallet.desktop) === null || _b === void 0 ? void 0 : _b.native)) {
128
- return undefined;
129
- }
130
- return getDeepLink({
131
- metadata: wallet,
132
- mode: 'regular',
133
- uri: WalletConnectV2.provider.uri,
134
- });
135
- }
136
168
  getWeb3Provider() {
137
169
  if (!WalletConnectV2.provider) {
138
- throw new Error('No provider found');
170
+ return;
139
171
  }
140
172
  return new ethers.providers.Web3Provider(WalletConnectV2.provider, 'any');
141
173
  }
142
174
  fetchPublicAddress(opts) {
175
+ var _a, _b;
143
176
  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');
177
+ if (this.activeAccount) {
178
+ return this.activeAccount;
149
179
  }
150
- if (!WalletConnectV2.provider.uri) {
151
- throw new DynamicError('No uri found');
180
+ if (!WalletConnectV2.provider || !((_a = WalletConnectV2.provider) === null || _a === void 0 ? void 0 : _a.uri)) {
181
+ logger.debug('No WC2 provider found, re-initializing...');
182
+ yield this.endSession();
183
+ yield this.init();
184
+ // sleep 1 s to wait for connect call to finish
185
+ // the connect call isn't await-ed because it only resolves once
186
+ // the connection is established, but we need to wait for it to
187
+ // finish setting up the connection URI and making it available
188
+ // on the provider
189
+ yield new Promise((resolve) => setTimeout(resolve, 1000));
190
+ if (!WalletConnectV2.provider || !((_b = WalletConnectV2.provider) === null || _b === void 0 ? void 0 : _b.uri)) {
191
+ logger.debug('No WC2 provider found, escaping and throwing error');
192
+ throw new DynamicError('No provider found');
193
+ }
152
194
  }
153
195
  const metadata = getWalletBookWallet(this.walletBook, this.name);
154
196
  performPlatformSpecificConnectionMethod(WalletConnectV2.provider.uri, metadata, {
@@ -160,18 +202,56 @@ class WalletConnectV2 extends EthWalletConnector {
160
202
  reject(new DynamicError('No provider found'));
161
203
  return;
162
204
  }
205
+ ee.on('walletconnect_connection_failed', () => {
206
+ const error = new DynamicError('Connection rejected. Please try again.');
207
+ error.code = 'connection_rejected';
208
+ if (WalletConnectV2.provider) {
209
+ WalletConnectV2.provider.uri = undefined;
210
+ }
211
+ reject(error);
212
+ });
163
213
  WalletConnectV2.provider.on('connect', ({ session }) => {
164
214
  if (!session) {
165
215
  reject(new DynamicError('No session found'));
166
216
  }
167
- this.session = session;
168
- localStorage.setItem(this.sessionTopicKey, session.topic);
169
- resolve(this.session.namespaces.eip155.accounts[0].split(':')[2]);
217
+ this.setSession(session);
218
+ this.setActiveAccount(session.namespaces.eip155.accounts[0].split(':')[2]);
219
+ resolve(this.activeAccount);
220
+ });
221
+ });
222
+ });
223
+ }
224
+ /**
225
+ * WalletConnect V2 will fail to send the sign message request if the chainId
226
+ * is not the same as the one in the session. This method will wait for the
227
+ * chainId to change and then retry the sign message request.
228
+ *
229
+ * Otherwise it will just return the result of the sign message request.
230
+ *
231
+ * @param signMessageFn - Function to sign message with provider
232
+ * @param messageToSign - Message to sign
233
+ * @returns
234
+ */
235
+ waitForSignMessage(signMessageFn, messageToSign) {
236
+ return __awaiter(this, void 0, void 0, function* () {
237
+ const raceConditionPromise = new Promise((resolve) => {
238
+ // Create listener for chain change event
239
+ this.setupEventListeners({
240
+ onChainChange: () => __awaiter(this, void 0, void 0, function* () {
241
+ resolve({ success: false });
242
+ }),
170
243
  });
244
+ signMessageFn(messageToSign).then((result) => resolve({ signedMessage: result, success: true }));
171
245
  });
246
+ const signedMessageResult = yield raceConditionPromise;
247
+ if (signedMessageResult.success === false) {
248
+ return signMessageFn(messageToSign);
249
+ }
250
+ return signedMessageResult.signedMessage;
172
251
  });
173
252
  }
174
253
  signMessage(messageToSign) {
254
+ var _a, _b;
175
255
  return __awaiter(this, void 0, void 0, function* () {
176
256
  if (!this.session) {
177
257
  throw new DynamicError('no session');
@@ -181,39 +261,67 @@ class WalletConnectV2 extends EthWalletConnector {
181
261
  }
182
262
  const metadata = getWalletBookWallet(this.walletBook, this.name);
183
263
  if (isMobile()) {
184
- // for sign message, no uri is needed because the uri encodes connection details,
185
- // and at this point we are already connected
186
- const deepLink = getDeepLink({ metadata, mode: 'regular' });
264
+ const deepLink = ((_a = metadata['mobile']) === null || _a === void 0 ? void 0 : _a.native) || ((_b = metadata['mobile']) === null || _b === void 0 ? void 0 : _b.universal) || '';
187
265
  window.location.href = deepLink;
188
266
  }
189
- // eslint-disable-next-line prefer-destructuring
190
- const address = this.session.namespaces.eip155.accounts[0].split(':')[2];
191
267
  const web3Provider = this.getWeb3Provider();
192
- return web3Provider.send('personal_sign', [
193
- utf8ToHex(messageToSign, true),
194
- address,
195
- ]);
268
+ if (!web3Provider) {
269
+ throw new DynamicError('No web3 provider found');
270
+ }
271
+ const signMessageFn = (messageToSign) => __awaiter(this, void 0, void 0, function* () {
272
+ return web3Provider.send('personal_sign', [
273
+ utf8ToHex(messageToSign, true),
274
+ this.activeAccount,
275
+ ]);
276
+ });
277
+ const response = yield this.waitForSignMessage(signMessageFn, messageToSign);
278
+ return response;
196
279
  });
197
280
  }
281
+ clearActiveAccount() {
282
+ localStorage.removeItem(this.activeAccountKey);
283
+ this.activeAccount = undefined;
284
+ }
285
+ clearSession() {
286
+ localStorage.removeItem(this.sessionTopicKey);
287
+ this.session = undefined;
288
+ }
289
+ setActiveAccount(account) {
290
+ localStorage.setItem(this.activeAccountKey, account);
291
+ this.activeAccount = account;
292
+ }
293
+ setSession(session) {
294
+ localStorage.setItem(this.sessionTopicKey, session.topic);
295
+ this.session = session;
296
+ }
198
297
  endSession() {
298
+ var _a;
199
299
  return __awaiter(this, void 0, void 0, function* () {
200
- if (!this.session) {
201
- return;
202
- }
203
- if (!WalletConnectV2.provider) {
300
+ this.clearActiveAccount();
301
+ this.clearSession();
302
+ if (!((_a = WalletConnectV2.provider) === null || _a === void 0 ? void 0 : _a.session)) {
204
303
  return;
205
304
  }
206
305
  try {
207
306
  yield WalletConnectV2.provider.disconnect();
208
- WalletConnectV2.provider.uri = undefined;
209
- localStorage.removeItem(this.sessionTopicKey);
210
- this.session = undefined;
307
+ // We must unset provider on logout so that a new session can be established
308
+ // If we don't then the provider will still have the old session and will hang
309
+ WalletConnectV2.provider = undefined;
211
310
  }
212
311
  catch (e) {
213
312
  logger.debug(e);
214
313
  }
215
314
  });
216
315
  }
316
+ getNetwork() {
317
+ const _super = Object.create(null, {
318
+ getNetwork: { get: () => super.getNetwork }
319
+ });
320
+ return __awaiter(this, void 0, void 0, function* () {
321
+ yield this.initProvider();
322
+ return _super.getNetwork.call(this);
323
+ });
324
+ }
217
325
  providerSwitchNetwork({ network, provider, }) {
218
326
  const _super = Object.create(null, {
219
327
  providerSwitchNetwork: { get: () => super.providerSwitchNetwork }
@@ -236,13 +344,33 @@ class WalletConnectV2 extends EthWalletConnector {
236
344
  });
237
345
  }
238
346
  getConnectedAccounts() {
347
+ return __awaiter(this, void 0, void 0, function* () {
348
+ yield this.initProvider();
349
+ this.refreshSession();
350
+ this.isInitialized = true;
351
+ if (!this.activeAccount) {
352
+ return [];
353
+ }
354
+ return [this.activeAccount];
355
+ });
356
+ }
357
+ getSupportedNetworks() {
239
358
  return __awaiter(this, void 0, void 0, function* () {
240
359
  yield this.initProvider();
241
360
  this.refreshSession();
242
361
  if (!this.session) {
243
362
  return [];
244
363
  }
245
- return [this.session.namespaces.eip155.accounts[0].split(':')[2]];
364
+ const chains = [];
365
+ // Some wallet (i.e ZenGo) use namespaces.account to list supported chains
366
+ // while others use keys within the namespaces object
367
+ Object.keys(this.session.namespaces).forEach((key) => {
368
+ if (key.startsWith('eip155:')) {
369
+ chains.push(key.split(':')[1]);
370
+ }
371
+ });
372
+ this.session.namespaces.eip155.accounts.forEach((account) => chains.push(account.split(':')[1]));
373
+ return chains.length ? chains : undefined;
246
374
  });
247
375
  }
248
376
  }