@dynamic-labs/starknet 1.4.14 → 1.4.16

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
+ ### [1.4.16](https://github.com/dynamic-labs/DynamicAuth/compare/v1.4.15...v1.4.16) (2024-07-25)
3
+
4
+
5
+ ### Bug Fixes
6
+
7
+ * improve network switch ux for metamask starknet snap ([#6376](https://github.com/dynamic-labs/DynamicAuth/issues/6376)) ([#6419](https://github.com/dynamic-labs/DynamicAuth/issues/6419)) ([4909806](https://github.com/dynamic-labs/DynamicAuth/commit/4909806ee5fa8a6a90d85f7e9c24b2bde6de5e75))
8
+
9
+ ### [1.4.15](https://github.com/dynamic-labs/DynamicAuth/compare/v1.4.14...v1.4.15) (2024-07-17)
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * re-establish connection to metamask starknet snap on page reload ([#6362](https://github.com/dynamic-labs/DynamicAuth/issues/6362)) ([176bd0e](https://github.com/dynamic-labs/DynamicAuth/commit/176bd0e096a523731e815b1e32961509db1e05d2))
15
+
2
16
  ### [1.4.14](https://github.com/dynamic-labs/DynamicAuth/compare/v1.4.13...v1.4.14) (2024-07-11)
3
17
 
4
18
  ### [1.4.13](https://github.com/dynamic-labs/DynamicAuth/compare/v1.4.12...v1.4.13) (2024-06-05)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynamic-labs/starknet",
3
- "version": "1.4.14",
3
+ "version": "1.4.16",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/dynamic-labs/DynamicAuth.git",
@@ -32,11 +32,12 @@
32
32
  "starknetkit": "1.1.3",
33
33
  "@dynamic-labs/sdk-api": "0.0.387",
34
34
  "@module-federation/runtime": "0.1.19",
35
- "@dynamic-labs/rpc-providers": "1.4.14",
36
- "@dynamic-labs/types": "1.4.14",
37
- "@dynamic-labs/utils": "1.4.14",
38
- "@dynamic-labs/wallet-book": "1.4.14",
39
- "@dynamic-labs/wallet-connector-core": "1.4.14"
35
+ "@dynamic-labs/logger": "1.4.16",
36
+ "@dynamic-labs/rpc-providers": "1.4.16",
37
+ "@dynamic-labs/types": "1.4.16",
38
+ "@dynamic-labs/utils": "1.4.16",
39
+ "@dynamic-labs/wallet-book": "1.4.16",
40
+ "@dynamic-labs/wallet-connector-core": "1.4.16"
40
41
  },
41
42
  "peerDependencies": {}
42
43
  }
@@ -25,13 +25,34 @@ function _interopNamespace(e) {
25
25
 
26
26
  var moduleFederation__namespace = /*#__PURE__*/_interopNamespace(moduleFederation);
27
27
 
28
- let metaMaskSnapWallet;
29
28
  /**
30
29
  *
31
30
  * @param {IEthereum} provider the metamask window provider object
32
31
  * @returns {StarknetWindowObject} the metamask provider wrapper formed into starknet window object
33
32
  */
34
33
  const createMetaMaskProviderWrapper = (provider) => {
34
+ let metaMaskSnapWallet;
35
+ // using @module-federation to load the get-starknet remoteEntry, as recommended
36
+ // by the starknet team. this file is a small wrapper around the metamask snap api
37
+ // to communicate with starknet, which we then wrap into a starknet window object
38
+ // and use in our starknet connector, just like braavos and argent
39
+ const initMetaMaskSnapWallet = () => _tslib.__awaiter(void 0, void 0, void 0, function* () {
40
+ if (!metaMaskSnapWallet) {
41
+ moduleFederation__namespace.init({
42
+ name: 'MetaMaskStarknetSnapWallet',
43
+ remotes: [
44
+ {
45
+ alias: 'MetaMaskStarknetSnapWallet',
46
+ entry: 'https://snaps.consensys.io/starknet/get-starknet/v1/remoteEntry.js',
47
+ name: 'MetaMaskStarknetSnapWallet',
48
+ },
49
+ ],
50
+ });
51
+ const result = yield moduleFederation__namespace.loadRemote('MetaMaskStarknetSnapWallet/index');
52
+ const { MetaMaskSnapWallet } = result;
53
+ metaMaskSnapWallet = new MetaMaskSnapWallet(provider, '*');
54
+ }
55
+ });
35
56
  const metaMaskProviderWrapper = {
36
57
  get account() {
37
58
  return metaMaskSnapWallet === null || metaMaskSnapWallet === void 0 ? void 0 : metaMaskSnapWallet.account;
@@ -40,21 +61,7 @@ const createMetaMaskProviderWrapper = (provider) => {
40
61
  return metaMaskSnapWallet === null || metaMaskSnapWallet === void 0 ? void 0 : metaMaskSnapWallet.chainId;
41
62
  },
42
63
  enable: () => _tslib.__awaiter(void 0, void 0, void 0, function* () {
43
- if (!metaMaskSnapWallet) {
44
- yield moduleFederation__namespace.init({
45
- name: 'MetaMaskStarknetSnapWallet',
46
- remotes: [
47
- {
48
- alias: 'MetaMaskStarknetSnapWallet',
49
- entry: 'https://snaps.consensys.io/starknet/get-starknet/v1/remoteEntry.js',
50
- name: 'MetaMaskStarknetSnapWallet',
51
- },
52
- ],
53
- });
54
- const result = yield moduleFederation__namespace.loadRemote('MetaMaskStarknetSnapWallet/index');
55
- const { MetaMaskSnapWallet } = result;
56
- metaMaskSnapWallet = new MetaMaskSnapWallet(provider, '*');
57
- }
64
+ yield initMetaMaskSnapWallet();
58
65
  if (!metaMaskSnapWallet) {
59
66
  return [];
60
67
  }
@@ -65,7 +72,11 @@ const createMetaMaskProviderWrapper = (provider) => {
65
72
  get isConnected() {
66
73
  return metaMaskSnapWallet === null || metaMaskSnapWallet === void 0 ? void 0 : metaMaskSnapWallet.isConnected;
67
74
  },
68
- isPreauthorized: () => { var _a; return (_a = metaMaskSnapWallet === null || metaMaskSnapWallet === void 0 ? void 0 : metaMaskSnapWallet.isPreauthorized()) !== null && _a !== void 0 ? _a : Promise.resolve(false); },
75
+ isPreauthorized: () => _tslib.__awaiter(void 0, void 0, void 0, function* () {
76
+ var _a;
77
+ yield initMetaMaskSnapWallet();
78
+ return (_a = (yield (metaMaskSnapWallet === null || metaMaskSnapWallet === void 0 ? void 0 : metaMaskSnapWallet.isPreauthorized()))) !== null && _a !== void 0 ? _a : false;
79
+ }),
69
80
  name: 'MetaMaskStarknetSnapWallet',
70
81
  off: (
71
82
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -1,13 +1,34 @@
1
1
  import { __awaiter } from '../../_virtual/_tslib.js';
2
2
  import * as moduleFederation from '@module-federation/runtime/dist/index.cjs.js';
3
3
 
4
- let metaMaskSnapWallet;
5
4
  /**
6
5
  *
7
6
  * @param {IEthereum} provider the metamask window provider object
8
7
  * @returns {StarknetWindowObject} the metamask provider wrapper formed into starknet window object
9
8
  */
10
9
  const createMetaMaskProviderWrapper = (provider) => {
10
+ let metaMaskSnapWallet;
11
+ // using @module-federation to load the get-starknet remoteEntry, as recommended
12
+ // by the starknet team. this file is a small wrapper around the metamask snap api
13
+ // to communicate with starknet, which we then wrap into a starknet window object
14
+ // and use in our starknet connector, just like braavos and argent
15
+ const initMetaMaskSnapWallet = () => __awaiter(void 0, void 0, void 0, function* () {
16
+ if (!metaMaskSnapWallet) {
17
+ moduleFederation.init({
18
+ name: 'MetaMaskStarknetSnapWallet',
19
+ remotes: [
20
+ {
21
+ alias: 'MetaMaskStarknetSnapWallet',
22
+ entry: 'https://snaps.consensys.io/starknet/get-starknet/v1/remoteEntry.js',
23
+ name: 'MetaMaskStarknetSnapWallet',
24
+ },
25
+ ],
26
+ });
27
+ const result = yield moduleFederation.loadRemote('MetaMaskStarknetSnapWallet/index');
28
+ const { MetaMaskSnapWallet } = result;
29
+ metaMaskSnapWallet = new MetaMaskSnapWallet(provider, '*');
30
+ }
31
+ });
11
32
  const metaMaskProviderWrapper = {
12
33
  get account() {
13
34
  return metaMaskSnapWallet === null || metaMaskSnapWallet === void 0 ? void 0 : metaMaskSnapWallet.account;
@@ -16,21 +37,7 @@ const createMetaMaskProviderWrapper = (provider) => {
16
37
  return metaMaskSnapWallet === null || metaMaskSnapWallet === void 0 ? void 0 : metaMaskSnapWallet.chainId;
17
38
  },
18
39
  enable: () => __awaiter(void 0, void 0, void 0, function* () {
19
- if (!metaMaskSnapWallet) {
20
- yield moduleFederation.init({
21
- name: 'MetaMaskStarknetSnapWallet',
22
- remotes: [
23
- {
24
- alias: 'MetaMaskStarknetSnapWallet',
25
- entry: 'https://snaps.consensys.io/starknet/get-starknet/v1/remoteEntry.js',
26
- name: 'MetaMaskStarknetSnapWallet',
27
- },
28
- ],
29
- });
30
- const result = yield moduleFederation.loadRemote('MetaMaskStarknetSnapWallet/index');
31
- const { MetaMaskSnapWallet } = result;
32
- metaMaskSnapWallet = new MetaMaskSnapWallet(provider, '*');
33
- }
40
+ yield initMetaMaskSnapWallet();
34
41
  if (!metaMaskSnapWallet) {
35
42
  return [];
36
43
  }
@@ -41,7 +48,11 @@ const createMetaMaskProviderWrapper = (provider) => {
41
48
  get isConnected() {
42
49
  return metaMaskSnapWallet === null || metaMaskSnapWallet === void 0 ? void 0 : metaMaskSnapWallet.isConnected;
43
50
  },
44
- isPreauthorized: () => { var _a; return (_a = metaMaskSnapWallet === null || metaMaskSnapWallet === void 0 ? void 0 : metaMaskSnapWallet.isPreauthorized()) !== null && _a !== void 0 ? _a : Promise.resolve(false); },
51
+ isPreauthorized: () => __awaiter(void 0, void 0, void 0, function* () {
52
+ var _a;
53
+ yield initMetaMaskSnapWallet();
54
+ return (_a = (yield (metaMaskSnapWallet === null || metaMaskSnapWallet === void 0 ? void 0 : metaMaskSnapWallet.isPreauthorized()))) !== null && _a !== void 0 ? _a : false;
55
+ }),
45
56
  name: 'MetaMaskStarknetSnapWallet',
46
57
  off: (
47
58
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -4,43 +4,106 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var _tslib = require('../../_virtual/_tslib.cjs');
6
6
  var utils = require('@dynamic-labs/utils');
7
+ var logger$1 = require('@dynamic-labs/logger');
7
8
  var starknetWalletConnector = require('../starknetWalletConnector.cjs');
8
9
  var starknetSnap = require('../utils/starknetSnap.cjs');
9
10
 
11
+ const logger = new logger$1.Logger('MetaMask Starknet Snap', logger$1.LogLevel.INFO);
10
12
  class MetaMask extends starknetWalletConnector["default"] {
11
13
  constructor(opts) {
12
14
  super('MetaMask Starknet', 'metamask_snap', opts);
13
15
  this.overrideKey = 'metamaskstarknet';
14
- this.canSetEventListeners = false;
15
- if (!window.starknet_metamask_snap) {
16
- const { providers } = utils.Eip6963ProviderSingleton.get();
17
- const metamaskProvider = providers.find((p) => ['io.metamask', 'io.metamask.flask'].includes(p.info.rdns));
18
- if (metamaskProvider) {
19
- window.starknet_metamask_snap = starknetSnap.createMetaMaskProviderWrapper(metamaskProvider.provider);
20
- }
16
+ const { providers } = utils.Eip6963ProviderSingleton.get();
17
+ const metamaskProvider = providers.find((p) => ['io.metamask', 'io.metamask.flask'].includes(p.info.rdns));
18
+ if (metamaskProvider) {
19
+ this.provider = metamaskProvider.provider;
20
+ }
21
+ if (!window.starknet_metamask_snap && metamaskProvider) {
22
+ window.starknet_metamask_snap = starknetSnap.createMetaMaskProviderWrapper(metamaskProvider.provider);
21
23
  }
22
24
  }
23
- getConnectedAccounts() {
25
+ getNetwork() {
24
26
  return _tslib.__awaiter(this, void 0, void 0, function* () {
25
- const wallet = this.getWallet();
26
- if (!wallet) {
27
- return [];
27
+ if (!this.provider) {
28
+ logger.error('[getNetwork] - No provider found, returning undefined');
29
+ return undefined;
28
30
  }
29
31
  try {
30
- yield this.reconnectIfNeeded(wallet);
32
+ logger.info('[getNetwork] - trying to fetch network using provider');
33
+ // we are using this method to get the network so that we always "see" the absolute
34
+ // active network in the companion site. when using the snap wrapper to get the network,
35
+ // we don't "see" the actual active network in the companion site – instead we see the
36
+ // network that was active at the time of the snap initialization
37
+ const result = yield this.provider.request({
38
+ method: 'wallet_invokeSnap',
39
+ params: {
40
+ request: {
41
+ method: 'starkNet_getCurrentNetwork',
42
+ params: {},
43
+ },
44
+ snapId: 'npm:@consensys/starknet-snap',
45
+ },
46
+ });
47
+ if (!('chainId' in result) || typeof result.chainId !== 'string') {
48
+ logger.error(`[getNetwork] - result.chainId should be a string, but got: ${
49
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
50
+ result.chainId}`);
51
+ return undefined;
52
+ }
53
+ if (result.chainId !== this.currentChainId) {
54
+ const resultChainName = this.mapChainIdToNetworkName(result.chainId);
55
+ const currentChainName = this.currentChainId
56
+ ? this.mapChainIdToNetworkName(this.currentChainId)
57
+ : undefined;
58
+ logger.info(`[getNetwork] - emitting chainChange event. got chainId: ${result.chainId} (${resultChainName}). current chainId: ${this.currentChainId} (${currentChainName})`);
59
+ this.emit('chainChange', { chain: result.chainId });
60
+ }
61
+ this.currentChainId = result.chainId;
62
+ return this.currentChainId;
31
63
  }
32
64
  catch (e) {
33
- return [];
65
+ logger.error('[getNetwork] - network fetch request failed, returning undefined', e);
66
+ return undefined;
34
67
  }
35
- const getSelectedAddress = () => wallet.selectedAddress
36
- ? Promise.resolve([wallet.selectedAddress])
37
- : Promise.reject();
38
- return utils.retryableFn(getSelectedAddress, {
39
- fallbackValue: [],
40
- maxRetries: 10,
41
- retryIntervalMs: 750,
42
- retryStrategy: 'timeout-and-rejection',
68
+ });
69
+ }
70
+ setupEventListeners() {
71
+ this.intervalId = setInterval(() => {
72
+ this.getNetwork().then((chainId) => {
73
+ if (!chainId) {
74
+ return;
75
+ }
76
+ const resultChainName = this.mapChainIdToNetworkName(chainId);
77
+ const currentChainName = this.currentChainId
78
+ ? this.mapChainIdToNetworkName(this.currentChainId)
79
+ : undefined;
80
+ logger.info(`[setupEventListeners] - got network: ${chainId} (${resultChainName}). current network: ${this.currentChainId} (${currentChainName})`);
81
+ if (chainId !== this.currentChainId) {
82
+ logger.info(`[setupEventListeners] - emitting chainChange event: ${chainId}`);
83
+ this.emit('chainChange', { chain: chainId });
84
+ this.currentChainId = chainId;
85
+ }
43
86
  });
87
+ }, 5000);
88
+ }
89
+ teardownEventListeners() {
90
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
91
+ clearInterval(this.intervalId);
92
+ });
93
+ }
94
+ getConnectedAccounts() {
95
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
96
+ const wallet = this.getWallet();
97
+ if (!wallet) {
98
+ return [];
99
+ }
100
+ const isProviderConnected = this.isProviderConnected();
101
+ const isPreauthorized = yield wallet.isPreauthorized();
102
+ const shouldReconnect = !isProviderConnected && isPreauthorized;
103
+ if (shouldReconnect) {
104
+ yield this.connect();
105
+ }
106
+ return wallet.selectedAddress ? [wallet.selectedAddress] : [];
44
107
  });
45
108
  }
46
109
  }
@@ -2,7 +2,12 @@ import { type WalletConnector } from '@dynamic-labs/wallet-connector-core';
2
2
  import StarknetProvider from '../starknetWalletConnector';
3
3
  export declare class MetaMask extends StarknetProvider implements WalletConnector {
4
4
  overrideKey: string;
5
- canSetEventListeners: boolean;
5
+ private currentChainId;
6
+ private intervalId;
7
+ private provider;
6
8
  constructor(opts: any);
9
+ getNetwork(): Promise<string | undefined>;
10
+ setupEventListeners(): void;
11
+ teardownEventListeners(): Promise<void>;
7
12
  getConnectedAccounts(): Promise<string[]>;
8
13
  }
@@ -1,42 +1,105 @@
1
1
  import { __awaiter } from '../../_virtual/_tslib.js';
2
- import { Eip6963ProviderSingleton, retryableFn } from '@dynamic-labs/utils';
2
+ import { Eip6963ProviderSingleton } from '@dynamic-labs/utils';
3
+ import { Logger, LogLevel } from '@dynamic-labs/logger';
3
4
  import StarknetWalletConnector from '../starknetWalletConnector.js';
4
5
  import { createMetaMaskProviderWrapper } from '../utils/starknetSnap.js';
5
6
 
7
+ const logger = new Logger('MetaMask Starknet Snap', LogLevel.INFO);
6
8
  class MetaMask extends StarknetWalletConnector {
7
9
  constructor(opts) {
8
10
  super('MetaMask Starknet', 'metamask_snap', opts);
9
11
  this.overrideKey = 'metamaskstarknet';
10
- this.canSetEventListeners = false;
11
- if (!window.starknet_metamask_snap) {
12
- const { providers } = Eip6963ProviderSingleton.get();
13
- const metamaskProvider = providers.find((p) => ['io.metamask', 'io.metamask.flask'].includes(p.info.rdns));
14
- if (metamaskProvider) {
15
- window.starknet_metamask_snap = createMetaMaskProviderWrapper(metamaskProvider.provider);
16
- }
12
+ const { providers } = Eip6963ProviderSingleton.get();
13
+ const metamaskProvider = providers.find((p) => ['io.metamask', 'io.metamask.flask'].includes(p.info.rdns));
14
+ if (metamaskProvider) {
15
+ this.provider = metamaskProvider.provider;
16
+ }
17
+ if (!window.starknet_metamask_snap && metamaskProvider) {
18
+ window.starknet_metamask_snap = createMetaMaskProviderWrapper(metamaskProvider.provider);
17
19
  }
18
20
  }
19
- getConnectedAccounts() {
21
+ getNetwork() {
20
22
  return __awaiter(this, void 0, void 0, function* () {
21
- const wallet = this.getWallet();
22
- if (!wallet) {
23
- return [];
23
+ if (!this.provider) {
24
+ logger.error('[getNetwork] - No provider found, returning undefined');
25
+ return undefined;
24
26
  }
25
27
  try {
26
- yield this.reconnectIfNeeded(wallet);
28
+ logger.info('[getNetwork] - trying to fetch network using provider');
29
+ // we are using this method to get the network so that we always "see" the absolute
30
+ // active network in the companion site. when using the snap wrapper to get the network,
31
+ // we don't "see" the actual active network in the companion site – instead we see the
32
+ // network that was active at the time of the snap initialization
33
+ const result = yield this.provider.request({
34
+ method: 'wallet_invokeSnap',
35
+ params: {
36
+ request: {
37
+ method: 'starkNet_getCurrentNetwork',
38
+ params: {},
39
+ },
40
+ snapId: 'npm:@consensys/starknet-snap',
41
+ },
42
+ });
43
+ if (!('chainId' in result) || typeof result.chainId !== 'string') {
44
+ logger.error(`[getNetwork] - result.chainId should be a string, but got: ${
45
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
46
+ result.chainId}`);
47
+ return undefined;
48
+ }
49
+ if (result.chainId !== this.currentChainId) {
50
+ const resultChainName = this.mapChainIdToNetworkName(result.chainId);
51
+ const currentChainName = this.currentChainId
52
+ ? this.mapChainIdToNetworkName(this.currentChainId)
53
+ : undefined;
54
+ logger.info(`[getNetwork] - emitting chainChange event. got chainId: ${result.chainId} (${resultChainName}). current chainId: ${this.currentChainId} (${currentChainName})`);
55
+ this.emit('chainChange', { chain: result.chainId });
56
+ }
57
+ this.currentChainId = result.chainId;
58
+ return this.currentChainId;
27
59
  }
28
60
  catch (e) {
29
- return [];
61
+ logger.error('[getNetwork] - network fetch request failed, returning undefined', e);
62
+ return undefined;
30
63
  }
31
- const getSelectedAddress = () => wallet.selectedAddress
32
- ? Promise.resolve([wallet.selectedAddress])
33
- : Promise.reject();
34
- return retryableFn(getSelectedAddress, {
35
- fallbackValue: [],
36
- maxRetries: 10,
37
- retryIntervalMs: 750,
38
- retryStrategy: 'timeout-and-rejection',
64
+ });
65
+ }
66
+ setupEventListeners() {
67
+ this.intervalId = setInterval(() => {
68
+ this.getNetwork().then((chainId) => {
69
+ if (!chainId) {
70
+ return;
71
+ }
72
+ const resultChainName = this.mapChainIdToNetworkName(chainId);
73
+ const currentChainName = this.currentChainId
74
+ ? this.mapChainIdToNetworkName(this.currentChainId)
75
+ : undefined;
76
+ logger.info(`[setupEventListeners] - got network: ${chainId} (${resultChainName}). current network: ${this.currentChainId} (${currentChainName})`);
77
+ if (chainId !== this.currentChainId) {
78
+ logger.info(`[setupEventListeners] - emitting chainChange event: ${chainId}`);
79
+ this.emit('chainChange', { chain: chainId });
80
+ this.currentChainId = chainId;
81
+ }
39
82
  });
83
+ }, 5000);
84
+ }
85
+ teardownEventListeners() {
86
+ return __awaiter(this, void 0, void 0, function* () {
87
+ clearInterval(this.intervalId);
88
+ });
89
+ }
90
+ getConnectedAccounts() {
91
+ return __awaiter(this, void 0, void 0, function* () {
92
+ const wallet = this.getWallet();
93
+ if (!wallet) {
94
+ return [];
95
+ }
96
+ const isProviderConnected = this.isProviderConnected();
97
+ const isPreauthorized = yield wallet.isPreauthorized();
98
+ const shouldReconnect = !isProviderConnected && isPreauthorized;
99
+ if (shouldReconnect) {
100
+ yield this.connect();
101
+ }
102
+ return wallet.selectedAddress ? [wallet.selectedAddress] : [];
40
103
  });
41
104
  }
42
105
  }