@subwallet/extension-base 1.1.6-1 → 1.1.6-3

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.
@@ -1533,6 +1533,7 @@ export interface KoniRequestSignatures {
1533
1533
  'pri(chainService.upsertChain)': [_NetworkUpsertParams, boolean];
1534
1534
  'pri(chainService.enableChains)': [EnableMultiChainParams, boolean];
1535
1535
  'pri(chainService.enableChain)': [EnableChainParams, boolean];
1536
+ 'pri(chainService.reconnectChain)': [string, boolean];
1536
1537
  'pri(chainService.disableChains)': [string[], boolean];
1537
1538
  'pri(chainService.disableChain)': [string, boolean];
1538
1539
  'pri(chainService.removeChain)': [string, boolean];
@@ -1424,19 +1424,19 @@ class KoniExtension {
1424
1424
  const cb = (0, _subscriptions.createSubscription)(id, port);
1425
1425
  const historySubject = await this.#koniState.historyService.getHistorySubject();
1426
1426
  const subscription = historySubject.subscribe(histories => {
1427
- const addresses = _uiKeyring.keyring.getAccounts().map(a => a.address.toLowerCase());
1427
+ const addresses = _uiKeyring.keyring.getAccounts().map(a => a.address);
1428
1428
 
1429
1429
  // Re-filter
1430
- cb(histories.filter(item => addresses.includes(item.address.toLowerCase())));
1430
+ cb(histories.filter(item => addresses.some(address => (0, _utils2.isSameAddress)(item.address, address))));
1431
1431
  });
1432
1432
  this.createUnsubscriptionHandle(id, subscription.unsubscribe);
1433
1433
  port.onDisconnect.addListener(() => {
1434
1434
  this.cancelSubscription(id);
1435
1435
  });
1436
- const addresses = _uiKeyring.keyring.getAccounts().map(a => a.address.toLowerCase());
1436
+ const addresses = _uiKeyring.keyring.getAccounts().map(a => a.address);
1437
1437
 
1438
1438
  // Re-filter
1439
- return historySubject.getValue().filter(item => addresses.includes(item.address.toLowerCase()));
1439
+ return historySubject.getValue().filter(item => addresses.some(address => (0, _utils2.isSameAddress)(item.address, address)));
1440
1440
  }
1441
1441
 
1442
1442
  // Save address to contact
@@ -1734,6 +1734,9 @@ class KoniExtension {
1734
1734
  } = _ref43;
1735
1735
  return await this.#koniState.enableChain(chainSlug, enableTokens);
1736
1736
  }
1737
+ async reconnectChain(chainSlug) {
1738
+ return this.#koniState.chainService.reconnectChain(chainSlug);
1739
+ }
1737
1740
  async validateNetwork(_ref44) {
1738
1741
  let {
1739
1742
  existedChainSlug,
@@ -3710,6 +3713,8 @@ class KoniExtension {
3710
3713
  return this.getSupportedSmartContractTypes();
3711
3714
  case 'pri(chainService.enableChain)':
3712
3715
  return await this.enableChain(request);
3716
+ case 'pri(chainService.reconnectChain)':
3717
+ return await this.reconnectChain(request);
3713
3718
  case 'pri(chainService.disableChain)':
3714
3719
  return await this.disableChain(request);
3715
3720
  case 'pri(chainService.removeChain)':
@@ -13,6 +13,6 @@ const packageInfo = {
13
13
  name: '@subwallet/extension-base',
14
14
  path: typeof __dirname === 'string' ? __dirname : 'auto',
15
15
  type: 'cjs',
16
- version: '1.1.6-1'
16
+ version: '1.1.6-3'
17
17
  };
18
18
  exports.packageInfo = packageInfo;
@@ -3,18 +3,18 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.SHORT_RETRY_TIME = exports.LONG_RETRY_TIME = exports.FIRST_RECONNECT_TIME = exports.AbstractChainHandler = void 0;
6
+ exports.SHORT_RETRY_TIME = exports.FIRST_RECONNECT_TIME = exports.AbstractChainHandler = void 0;
7
+ var _types = require("@subwallet/extension-base/services/chain-service/types");
7
8
  var _rxjs = require("rxjs");
8
9
  // Copyright 2019-2022 @subwallet/extension-base authors & contributors
9
10
  // SPDX-License-Identifier: Apache-2.0
10
11
 
11
- const SHORT_RECOVER_RETRY = 3;
12
+ const MAX_RECOVER_RETRY = 6;
12
13
  const FIRST_RECONNECT_TIME = 3000;
13
14
  exports.FIRST_RECONNECT_TIME = FIRST_RECONNECT_TIME;
14
- const SHORT_RETRY_TIME = 15000;
15
+ const SHORT_RETRY_TIME = 20000;
16
+ // export const LONG_RETRY_TIME = 60000;
15
17
  exports.SHORT_RETRY_TIME = SHORT_RETRY_TIME;
16
- const LONG_RETRY_TIME = 60000;
17
- exports.LONG_RETRY_TIME = LONG_RETRY_TIME;
18
18
  class AbstractChainHandler {
19
19
  apiStateMapSubject = new _rxjs.BehaviorSubject({});
20
20
  // Recover retry times
@@ -24,20 +24,26 @@ class AbstractChainHandler {
24
24
  this.parent = parent;
25
25
  this.recoverMap = {};
26
26
  }
27
- handleConnect(chain, isConnected) {
27
+ handleConnection(chain, newStatus) {
28
+ let forceRecover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
28
29
  const currentMap = this.apiStateMapSubject.getValue();
29
- const currentStatus = currentMap[chain];
30
+ const oldStatus = currentMap[chain];
30
31
 
31
32
  // Update api state
32
- if (currentStatus !== isConnected) {
33
+ if (oldStatus !== newStatus) {
33
34
  this.apiStateMapSubject.next({
34
35
  ...currentMap,
35
- [chain]: isConnected
36
+ [chain]: newStatus
36
37
  });
37
38
  }
38
39
 
40
+ // Reset retry when connected is successful
41
+ if (newStatus === _types._ChainConnectionStatus.CONNECTED) {
42
+ this.cancelRecover(chain);
43
+ }
44
+
39
45
  // Handle connection change
40
- if (!isConnected) {
46
+ if ((!this.isRecovering(chain) || forceRecover) && newStatus === _types._ChainConnectionStatus.DISCONNECTED) {
41
47
  this.handleRecover(chain);
42
48
  }
43
49
  }
@@ -57,8 +63,13 @@ class AbstractChainHandler {
57
63
  };
58
64
  clearTimeout(retryRecord.timeout);
59
65
  const retryTimes = retryRecord.retryTimes;
66
+ if (retryTimes >= MAX_RECOVER_RETRY) {
67
+ this.handleConnection(chain, _types._ChainConnectionStatus.UNSTABLE);
68
+ this.cancelRecover(chain); // Need manual recover
69
+ }
70
+
60
71
  // Slow down recover frequency if increasing recover times
61
- const retryTimeout = retryTimes === 0 ? FIRST_RECONNECT_TIME : retryTimes >= SHORT_RECOVER_RETRY ? LONG_RETRY_TIME : SHORT_RETRY_TIME;
72
+ const retryTimeout = retryTimes === 0 ? FIRST_RECONNECT_TIME : SHORT_RETRY_TIME;
62
73
 
63
74
  // Recover api after retry timeout
64
75
  const timeout = setTimeout(() => {
@@ -77,6 +88,9 @@ class AbstractChainHandler {
77
88
  timeout
78
89
  };
79
90
  }
91
+ isRecovering(chain) {
92
+ return !!this.recoverMap[chain];
93
+ }
80
94
  cancelRecover(chain) {
81
95
  const retryRecord = this.recoverMap[chain];
82
96
  if (retryRecord) {
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.EvmApi = void 0;
8
8
  require("@polkadot/types-augment");
9
+ var _types = require("@subwallet/extension-base/services/chain-service/types");
9
10
  var _promise = require("@subwallet/extension-base/utils/promise");
10
11
  var _rxjs = require("rxjs");
11
12
  var _web = _interopRequireDefault(require("web3"));
@@ -15,15 +16,23 @@ var _web = _interopRequireDefault(require("web3"));
15
16
  class EvmApi {
16
17
  apiRetry = 0;
17
18
  isApiConnectedSubject = new _rxjs.BehaviorSubject(false);
19
+ connectionStatusSubject = new _rxjs.BehaviorSubject(_types._ChainConnectionStatus.DISCONNECTED);
18
20
  isApiReady = false;
19
21
  isApiReadyOnce = false;
20
22
  get isApiConnected() {
21
23
  return this.isApiConnectedSubject.getValue();
22
24
  }
23
- updateConnectedStatus(isConnected) {
25
+ get connectionStatus() {
26
+ return this.connectionStatusSubject.getValue();
27
+ }
28
+ updateConnectionStatus(status) {
29
+ const isConnected = status === _types._ChainConnectionStatus.CONNECTED;
24
30
  if (isConnected !== this.isApiConnectedSubject.value) {
25
31
  this.isApiConnectedSubject.next(isConnected);
26
32
  }
33
+ if (status !== this.connectionStatusSubject.value) {
34
+ this.connectionStatusSubject.next(status);
35
+ }
27
36
  }
28
37
  get isReady() {
29
38
  return this.isReadyHandler.promise;
@@ -80,6 +89,7 @@ class EvmApi {
80
89
  // For websocket provider, connect it
81
90
  const wsProvider = this.provider;
82
91
  wsProvider.connect && wsProvider.connect();
92
+ this.updateConnectionStatus(_types._ChainConnectionStatus.CONNECTING);
83
93
  // Check if api is ready
84
94
  this.api.eth.net.isListening().then(() => {
85
95
  this.isApiReadyOnce = true;
@@ -88,7 +98,7 @@ class EvmApi {
88
98
  this.isApiReadyOnce = false;
89
99
  this.isApiReady = false;
90
100
  this.isReadyHandler.reject(error);
91
- this.updateConnectedStatus(false);
101
+ this.updateConnectionStatus(_types._ChainConnectionStatus.DISCONNECTED);
92
102
  console.warn(`Can not connect to ${this.chainSlug} (EVM) at ${this.apiUrl}`);
93
103
  });
94
104
 
@@ -102,7 +112,7 @@ class EvmApi {
102
112
  // For websocket provider, disconnect it
103
113
  const wsProvider = this.provider;
104
114
  wsProvider.disconnect && wsProvider.disconnect();
105
- this.updateConnectedStatus(false);
115
+ this.updateConnectionStatus(_types._ChainConnectionStatus.DISCONNECTED);
106
116
  return Promise.resolve();
107
117
  }
108
118
  destroy() {
@@ -117,10 +127,10 @@ class EvmApi {
117
127
  this.isReadyHandler.resolve(this);
118
128
  }
119
129
  }
120
- this.updateConnectedStatus(true);
130
+ this.updateConnectionStatus(_types._ChainConnectionStatus.CONNECTED);
121
131
  }
122
132
  onDisconnect() {
123
- this.updateConnectedStatus(false);
133
+ this.updateConnectionStatus(_types._ChainConnectionStatus.DISCONNECTED);
124
134
  if (this.isApiConnected) {
125
135
  console.warn(`Disconnected from ${this.chainSlug} of ${this.apiUrl} (EVM)`);
126
136
  this.isApiReady = false;
@@ -46,8 +46,8 @@ class EvmChainHandler extends _AbstractChainHandler.AbstractChainHandler {
46
46
  const apiObject = new _EvmApi2.EvmApi(chainSlug, apiUrl, {
47
47
  providerName
48
48
  });
49
- apiObject.isApiConnectedSubject.subscribe(this.handleConnect.bind(this, chainSlug));
50
- apiObject.isApiConnectedSubject.subscribe(onUpdateStatus);
49
+ apiObject.connectionStatusSubject.subscribe(this.handleConnection.bind(this, chainSlug));
50
+ apiObject.connectionStatusSubject.subscribe(onUpdateStatus);
51
51
  return Promise.resolve(apiObject);
52
52
  }
53
53
  async recoverApi(chainSlug) {
@@ -10,6 +10,7 @@ var _types = require("@oak-foundation/types");
10
10
  var _constants = require("@subwallet/extension-base/services/chain-service/constants");
11
11
  var _lightClient = require("@subwallet/extension-base/services/chain-service/handler/light-client");
12
12
  var _SubstrateChainHandler = require("@subwallet/extension-base/services/chain-service/handler/SubstrateChainHandler");
13
+ var _types2 = require("@subwallet/extension-base/services/chain-service/types");
13
14
  var _promise = require("@subwallet/extension-base/utils/promise");
14
15
  var _availJsSdk = require("avail-js-sdk");
15
16
  var _rxjs = require("rxjs");
@@ -26,13 +27,22 @@ class SubstrateApi {
26
27
  isApiReady = false;
27
28
  isApiReadyOnce = false;
28
29
  isApiConnectedSubject = new _rxjs.BehaviorSubject(false);
30
+ connectionStatusSubject = new _rxjs.BehaviorSubject(_types2._ChainConnectionStatus.DISCONNECTED);
29
31
  get isApiConnected() {
30
32
  return this.isApiConnectedSubject.getValue();
31
33
  }
32
- updateConnectedStatus(isConnected) {
34
+ substrateRetry = 0;
35
+ get connectionStatus() {
36
+ return this.connectionStatusSubject.getValue();
37
+ }
38
+ updateConnectionStatus(status) {
39
+ const isConnected = status === _types2._ChainConnectionStatus.CONNECTED;
33
40
  if (isConnected !== this.isApiConnectedSubject.value) {
34
41
  this.isApiConnectedSubject.next(isConnected);
35
42
  }
43
+ if (status !== this.connectionStatusSubject.value) {
44
+ this.connectionStatusSubject.next(status);
45
+ }
36
46
  }
37
47
  specName = '';
38
48
  specVersion = '';
@@ -60,12 +70,14 @@ class SubstrateApi {
60
70
  [`${metadata.genesisHash}-${metadata.specVersion}`]: metadata.hexValue
61
71
  };
62
72
  }
73
+ this.updateConnectionStatus(_types2._ChainConnectionStatus.CONNECTING);
74
+ let api;
63
75
  if (_constants._API_OPTIONS_CHAIN_GROUP.acala.includes(this.chainSlug)) {
64
- return new _api2.ApiPromise((0, _api.options)({
76
+ api = new _api2.ApiPromise((0, _api.options)({
65
77
  provider
66
78
  }));
67
79
  } else if (_constants._API_OPTIONS_CHAIN_GROUP.turing.includes(this.chainSlug)) {
68
- return new _api2.ApiPromise({
80
+ api = new _api2.ApiPromise({
69
81
  provider,
70
82
  rpc: _types.rpc,
71
83
  types: _types.types
@@ -78,8 +90,13 @@ class SubstrateApi {
78
90
  signedExtensions: _availJsSdk.spec.signedExtensions
79
91
  });
80
92
  } else {
81
- return new _api2.ApiPromise(apiOption);
93
+ api = new _api2.ApiPromise(apiOption);
82
94
  }
95
+ api.on('ready', this.onReady.bind(this));
96
+ api.on('connected', this.onConnect.bind(this));
97
+ api.on('disconnected', this.onDisconnect.bind(this));
98
+ api.on('error', this.onError.bind(this));
99
+ return api;
83
100
  }
84
101
  constructor(chainSlug, apiUrl) {
85
102
  let {
@@ -95,10 +112,6 @@ class SubstrateApi {
95
112
  this.provider = this.createProvider(apiUrl);
96
113
  this.api = externalApiPromise || this.createApi(this.provider);
97
114
  this.handleApiReady = (0, _promise.createPromiseHandler)();
98
- this.api.on('ready', this.onReady.bind(this));
99
- this.api.on('connected', this.onConnect.bind(this));
100
- this.api.on('disconnected', this.onDisconnect.bind(this));
101
- this.api.on('error', this.onError.bind(this));
102
115
  }
103
116
  get isReady() {
104
117
  return this.handleApiReady.promise;
@@ -120,17 +133,16 @@ class SubstrateApi {
120
133
  this.apiUrl = apiUrl;
121
134
  this.provider = this.createProvider(apiUrl);
122
135
  this.api = this.createApi(this.provider);
123
- this.api.on('ready', this.onReady.bind(this));
124
- this.api.on('connected', this.onConnect.bind(this));
125
- this.api.on('disconnected', this.onDisconnect.bind(this));
126
- this.api.on('error', this.onError.bind(this));
127
136
  }
128
137
  connect() {
129
138
  if (this.api.isConnected) {
130
- this.updateConnectedStatus(true);
139
+ this.updateConnectionStatus(_types2._ChainConnectionStatus.CONNECTED);
131
140
  } else {
141
+ this.updateConnectionStatus(_types2._ChainConnectionStatus.CONNECTING);
132
142
  this.api.connect().then(() => {
133
- this.updateConnectedStatus(true);
143
+ this.api.isReady.then(() => {
144
+ this.updateConnectionStatus(_types2._ChainConnectionStatus.CONNECTED);
145
+ }).catch(console.error);
134
146
  }).catch(console.error);
135
147
  }
136
148
  }
@@ -140,7 +152,7 @@ class SubstrateApi {
140
152
  } catch (e) {
141
153
  console.error(e);
142
154
  }
143
- this.updateConnectedStatus(false);
155
+ this.updateConnectionStatus(_types2._ChainConnectionStatus.DISCONNECTED);
144
156
  }
145
157
  async recoverConnect() {
146
158
  await this.disconnect();
@@ -162,7 +174,8 @@ class SubstrateApi {
162
174
  });
163
175
  }
164
176
  onConnect() {
165
- this.updateConnectedStatus(true);
177
+ this.updateConnectionStatus(_types2._ChainConnectionStatus.CONNECTED);
178
+ this.substrateRetry = 0;
166
179
  console.log(`Connected to ${this.chainSlug || ''} at ${this.apiUrl}`);
167
180
  if (this.isApiReadyOnce) {
168
181
  this.handleApiReady.resolve(this);
@@ -171,8 +184,14 @@ class SubstrateApi {
171
184
  onDisconnect() {
172
185
  this.isApiReady = false;
173
186
  console.log(`Disconnected from ${this.chainSlug} at ${this.apiUrl}`);
174
- this.updateConnectedStatus(false);
187
+ this.updateConnectionStatus(_types2._ChainConnectionStatus.DISCONNECTED);
175
188
  this.handleApiReady = (0, _promise.createPromiseHandler)();
189
+ this.substrateRetry += 1;
190
+ if (this.substrateRetry > 9) {
191
+ this.disconnect().then(() => {
192
+ this.updateConnectionStatus(_types2._ChainConnectionStatus.UNSTABLE);
193
+ }).catch(console.error);
194
+ }
176
195
  }
177
196
  onError(e) {
178
197
  console.warn(`${this.chainSlug} connection got error`, e);
@@ -41,12 +41,12 @@ class SubstrateChainHandler extends _AbstractChainHandler.AbstractChainHandler {
41
41
 
42
42
  // Not found substrateInterface mean it active with evm interface
43
43
  if (api) {
44
- api === null || api === void 0 ? void 0 : api.connect();
44
+ api.connect();
45
45
  if (!api.useLightClient) {
46
46
  // Manual fire handle connect to avoid some chain can not reconnect
47
47
  setTimeout(() => {
48
- this.handleConnect(chain, api.isApiConnected);
49
- }, _AbstractChainHandler.SHORT_RETRY_TIME);
48
+ this.handleConnection(chain, api.connectionStatus);
49
+ }, 10000);
50
50
  }
51
51
  }
52
52
  }
@@ -202,8 +202,8 @@ class SubstrateChainHandler extends _AbstractChainHandler.AbstractChainHandler {
202
202
  metadata,
203
203
  externalApiPromise
204
204
  });
205
- apiObject.isApiConnectedSubject.subscribe(this.handleConnect.bind(this, chainSlug));
206
- onUpdateStatus && apiObject.isApiConnectedSubject.subscribe(onUpdateStatus);
205
+ apiObject.connectionStatusSubject.subscribe(this.handleConnection.bind(this, chainSlug));
206
+ onUpdateStatus && apiObject.connectionStatusSubject.subscribe(onUpdateStatus);
207
207
 
208
208
  // Update metadata to database with async methods
209
209
  apiObject.isReady.then(api => {
@@ -395,7 +395,7 @@ class ChainService {
395
395
  this.dataMap.assetRefMap = latestAssetRefMap;
396
396
  await this.initChains();
397
397
  this.chainInfoMapSubject.next(this.getChainInfoMap());
398
- this.chainStateMapSubject.next(this.getChainStateMap());
398
+ this.updateChainStateMapSubscription();
399
399
  this.assetRegistrySubject.next(this.getAssetRegistry());
400
400
  this.xcmRefMapSubject.next(this.dataMap.assetRefMap);
401
401
  await this.initApis();
@@ -423,14 +423,14 @@ class ChainService {
423
423
  endpoint,
424
424
  providerName
425
425
  } = this.getChainCurrentProviderByKey(chainInfo.slug);
426
- const onUpdateStatus = isConnected => {
426
+ const onUpdateStatus = status => {
427
427
  const currentStatus = this.getChainStateByKey(chainInfo.slug).connectionStatus;
428
- const newStatus = isConnected ? _types3._ChainConnectionStatus.CONNECTED : _types3._ChainConnectionStatus.DISCONNECTED;
429
428
 
430
429
  // Avoid unnecessary update in case disable chain
431
- if (currentStatus !== newStatus) {
432
- this.setChainConnectionStatus(chainInfo.slug, newStatus);
433
- this.chainStateMapSubject.next(this.getChainStateMap());
430
+ if (currentStatus !== status) {
431
+ console.log(chainInfo.name, currentStatus, status);
432
+ this.setChainConnectionStatus(chainInfo.slug, status);
433
+ this.updateChainStateMapSubscription();
434
434
  }
435
435
  };
436
436
  if (chainInfo.substrateInfo !== null && chainInfo.substrateInfo !== undefined) {
@@ -515,6 +515,12 @@ class ChainService {
515
515
  needUpdate && this.updateChainStateMapSubscription();
516
516
  return needUpdate;
517
517
  }
518
+ async reconnectChain(chain) {
519
+ var _this$getSubstrateApi, _this$getEvmApi;
520
+ await ((_this$getSubstrateApi = this.getSubstrateApi(chain)) === null || _this$getSubstrateApi === void 0 ? void 0 : _this$getSubstrateApi.recoverConnect());
521
+ await ((_this$getEvmApi = this.getEvmApi(chain)) === null || _this$getEvmApi === void 0 ? void 0 : _this$getEvmApi.recoverConnect());
522
+ return true;
523
+ }
518
524
  disableChain(chainSlug) {
519
525
  const chainInfo = this.getChainInfoByKey(chainSlug);
520
526
  const chainStateMap = this.getChainStateMap();
@@ -124,6 +124,7 @@ export default class KoniExtension {
124
124
  private removeCustomChain;
125
125
  private disableChain;
126
126
  private enableChain;
127
+ private reconnectChain;
127
128
  private validateNetwork;
128
129
  private resetDefaultNetwork;
129
130
  private recoverDotSamaApi;
@@ -27,7 +27,7 @@ import { EXTENSION_REQUEST_URL } from '@subwallet/extension-base/services/reques
27
27
  import { DEFAULT_AUTO_LOCK_TIME } from '@subwallet/extension-base/services/setting-service/constants';
28
28
  import { WALLET_CONNECT_EIP155_NAMESPACE } from '@subwallet/extension-base/services/wallet-connect-service/constants';
29
29
  import { isProposalExpired, isSupportWalletConnectChain, isSupportWalletConnectNamespace } from '@subwallet/extension-base/services/wallet-connect-service/helpers';
30
- import { reformatAddress, uniqueStringArray } from '@subwallet/extension-base/utils';
30
+ import { isSameAddress, reformatAddress, uniqueStringArray } from '@subwallet/extension-base/utils';
31
31
  import { convertSubjectInfoToAddresses } from '@subwallet/extension-base/utils/address';
32
32
  import { createTransactionFromRLP, signatureToHex } from '@subwallet/extension-base/utils/eth';
33
33
  import { parseContractInput, parseEvmRlp } from '@subwallet/extension-base/utils/eth/parseTransaction';
@@ -1372,19 +1372,19 @@ export default class KoniExtension {
1372
1372
  const cb = createSubscription(id, port);
1373
1373
  const historySubject = await this.#koniState.historyService.getHistorySubject();
1374
1374
  const subscription = historySubject.subscribe(histories => {
1375
- const addresses = keyring.getAccounts().map(a => a.address.toLowerCase());
1375
+ const addresses = keyring.getAccounts().map(a => a.address);
1376
1376
 
1377
1377
  // Re-filter
1378
- cb(histories.filter(item => addresses.includes(item.address.toLowerCase())));
1378
+ cb(histories.filter(item => addresses.some(address => isSameAddress(item.address, address))));
1379
1379
  });
1380
1380
  this.createUnsubscriptionHandle(id, subscription.unsubscribe);
1381
1381
  port.onDisconnect.addListener(() => {
1382
1382
  this.cancelSubscription(id);
1383
1383
  });
1384
- const addresses = keyring.getAccounts().map(a => a.address.toLowerCase());
1384
+ const addresses = keyring.getAccounts().map(a => a.address);
1385
1385
 
1386
1386
  // Re-filter
1387
- return historySubject.getValue().filter(item => addresses.includes(item.address.toLowerCase()));
1387
+ return historySubject.getValue().filter(item => addresses.some(address => isSameAddress(item.address, address)));
1388
1388
  }
1389
1389
 
1390
1390
  // Save address to contact
@@ -1681,6 +1681,9 @@ export default class KoniExtension {
1681
1681
  }) {
1682
1682
  return await this.#koniState.enableChain(chainSlug, enableTokens);
1683
1683
  }
1684
+ async reconnectChain(chainSlug) {
1685
+ return this.#koniState.chainService.reconnectChain(chainSlug);
1686
+ }
1684
1687
  async validateNetwork({
1685
1688
  existedChainSlug,
1686
1689
  provider
@@ -3611,6 +3614,8 @@ export default class KoniExtension {
3611
3614
  return this.getSupportedSmartContractTypes();
3612
3615
  case 'pri(chainService.enableChain)':
3613
3616
  return await this.enableChain(request);
3617
+ case 'pri(chainService.reconnectChain)':
3618
+ return await this.reconnectChain(request);
3614
3619
  case 'pri(chainService.disableChain)':
3615
3620
  return await this.disableChain(request);
3616
3621
  case 'pri(chainService.removeChain)':
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "./cjs/detectPackage.js"
18
18
  ],
19
19
  "type": "module",
20
- "version": "1.1.6-1",
20
+ "version": "1.1.6-3",
21
21
  "main": "./cjs/index.js",
22
22
  "module": "./index.js",
23
23
  "types": "./index.d.ts",
@@ -1188,11 +1188,11 @@
1188
1188
  "@reduxjs/toolkit": "^1.9.1",
1189
1189
  "@sora-substrate/type-definitions": "^1.17.7",
1190
1190
  "@substrate/connect": "^0.7.26",
1191
- "@subwallet/chain-list": "0.2.9-beta.1",
1192
- "@subwallet/extension-base": "^1.1.6-1",
1193
- "@subwallet/extension-chains": "^1.1.6-1",
1194
- "@subwallet/extension-dapp": "^1.1.6-1",
1195
- "@subwallet/extension-inject": "^1.1.6-1",
1191
+ "@subwallet/chain-list": "0.2.9",
1192
+ "@subwallet/extension-base": "^1.1.6-3",
1193
+ "@subwallet/extension-chains": "^1.1.6-3",
1194
+ "@subwallet/extension-dapp": "^1.1.6-3",
1195
+ "@subwallet/extension-inject": "^1.1.6-3",
1196
1196
  "@subwallet/keyring": "^0.0.10",
1197
1197
  "@subwallet/ui-keyring": "^0.0.10",
1198
1198
  "@walletconnect/sign-client": "^2.8.4",
package/packageInfo.js CHANGED
@@ -7,5 +7,5 @@ export const packageInfo = {
7
7
  name: '@subwallet/extension-base',
8
8
  path: (import.meta && import.meta.url) ? new URL(import.meta.url).pathname.substring(0, new URL(import.meta.url).pathname.lastIndexOf('/') + 1) : 'auto',
9
9
  type: 'esm',
10
- version: '1.1.6-1'
10
+ version: '1.1.6-3'
11
11
  };
@@ -1,18 +1,17 @@
1
1
  /// <reference types="node" />
2
2
  import { ChainService } from '@subwallet/extension-base/services/chain-service';
3
3
  import { _ApiOptions } from '@subwallet/extension-base/services/chain-service/handler/types';
4
- import { _ChainBaseApi } from '@subwallet/extension-base/services/chain-service/types';
4
+ import { _ChainBaseApi, _ChainConnectionStatus } from '@subwallet/extension-base/services/chain-service/types';
5
5
  import { BehaviorSubject } from 'rxjs';
6
6
  export declare const FIRST_RECONNECT_TIME = 3000;
7
- export declare const SHORT_RETRY_TIME = 15000;
8
- export declare const LONG_RETRY_TIME = 60000;
7
+ export declare const SHORT_RETRY_TIME = 20000;
9
8
  interface RetryObject {
10
9
  retryTimes: number;
11
10
  timeout?: NodeJS.Timer;
12
11
  }
13
12
  export declare abstract class AbstractChainHandler {
14
13
  protected parent?: ChainService | undefined;
15
- readonly apiStateMapSubject: BehaviorSubject<Record<string, boolean>>;
14
+ readonly apiStateMapSubject: BehaviorSubject<Record<string, _ChainConnectionStatus>>;
16
15
  protected recoverMap: Record<string, RetryObject>;
17
16
  protected isSleeping: boolean;
18
17
  protected constructor(parent?: ChainService | undefined);
@@ -21,8 +20,9 @@ export declare abstract class AbstractChainHandler {
21
20
  abstract recoverApi(chainSlug: string): void;
22
21
  abstract sleep(): Promise<void>;
23
22
  abstract wakeUp(): Promise<void>;
24
- handleConnect(chain: string, isConnected: boolean): void;
23
+ handleConnection(chain: string, newStatus: _ChainConnectionStatus, forceRecover?: boolean): void;
25
24
  protected handleRecover(chain: string): void;
25
+ protected isRecovering(chain: string): boolean;
26
26
  protected cancelRecover(chain: string): void;
27
27
  cancelAllRecover(): void;
28
28
  }
@@ -1,11 +1,13 @@
1
1
  // Copyright 2019-2022 @subwallet/extension-base authors & contributors
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
+ import { _ChainConnectionStatus } from '@subwallet/extension-base/services/chain-service/types';
4
5
  import { BehaviorSubject } from 'rxjs';
5
- const SHORT_RECOVER_RETRY = 3;
6
+ const MAX_RECOVER_RETRY = 6;
6
7
  export const FIRST_RECONNECT_TIME = 3000;
7
- export const SHORT_RETRY_TIME = 15000;
8
- export const LONG_RETRY_TIME = 60000;
8
+ export const SHORT_RETRY_TIME = 20000;
9
+ // export const LONG_RETRY_TIME = 60000;
10
+
9
11
  export class AbstractChainHandler {
10
12
  apiStateMapSubject = new BehaviorSubject({});
11
13
  // Recover retry times
@@ -15,20 +17,25 @@ export class AbstractChainHandler {
15
17
  this.parent = parent;
16
18
  this.recoverMap = {};
17
19
  }
18
- handleConnect(chain, isConnected) {
20
+ handleConnection(chain, newStatus, forceRecover = false) {
19
21
  const currentMap = this.apiStateMapSubject.getValue();
20
- const currentStatus = currentMap[chain];
22
+ const oldStatus = currentMap[chain];
21
23
 
22
24
  // Update api state
23
- if (currentStatus !== isConnected) {
25
+ if (oldStatus !== newStatus) {
24
26
  this.apiStateMapSubject.next({
25
27
  ...currentMap,
26
- [chain]: isConnected
28
+ [chain]: newStatus
27
29
  });
28
30
  }
29
31
 
32
+ // Reset retry when connected is successful
33
+ if (newStatus === _ChainConnectionStatus.CONNECTED) {
34
+ this.cancelRecover(chain);
35
+ }
36
+
30
37
  // Handle connection change
31
- if (!isConnected) {
38
+ if ((!this.isRecovering(chain) || forceRecover) && newStatus === _ChainConnectionStatus.DISCONNECTED) {
32
39
  this.handleRecover(chain);
33
40
  }
34
41
  }
@@ -48,8 +55,13 @@ export class AbstractChainHandler {
48
55
  };
49
56
  clearTimeout(retryRecord.timeout);
50
57
  const retryTimes = retryRecord.retryTimes;
58
+ if (retryTimes >= MAX_RECOVER_RETRY) {
59
+ this.handleConnection(chain, _ChainConnectionStatus.UNSTABLE);
60
+ this.cancelRecover(chain); // Need manual recover
61
+ }
62
+
51
63
  // Slow down recover frequency if increasing recover times
52
- const retryTimeout = retryTimes === 0 ? FIRST_RECONNECT_TIME : retryTimes >= SHORT_RECOVER_RETRY ? LONG_RETRY_TIME : SHORT_RETRY_TIME;
64
+ const retryTimeout = retryTimes === 0 ? FIRST_RECONNECT_TIME : SHORT_RETRY_TIME;
53
65
 
54
66
  // Recover api after retry timeout
55
67
  const timeout = setTimeout(() => {
@@ -68,6 +80,9 @@ export class AbstractChainHandler {
68
80
  timeout
69
81
  };
70
82
  }
83
+ isRecovering(chain) {
84
+ return !!this.recoverMap[chain];
85
+ }
71
86
  cancelRecover(chain) {
72
87
  const retryRecord = this.recoverMap[chain];
73
88
  if (retryRecord) {
@@ -1,7 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import '@polkadot/types-augment';
3
3
  import { _ApiOptions } from '@subwallet/extension-base/services/chain-service/handler/types';
4
- import { _EvmApi } from '@subwallet/extension-base/services/chain-service/types';
4
+ import { _ChainConnectionStatus, _EvmApi } from '@subwallet/extension-base/services/chain-service/types';
5
5
  import { PromiseHandler } from '@subwallet/extension-base/utils/promise';
6
6
  import { BehaviorSubject } from 'rxjs';
7
7
  import Web3 from 'web3';
@@ -14,13 +14,15 @@ export declare class EvmApi implements _EvmApi {
14
14
  apiError?: string;
15
15
  apiRetry: number;
16
16
  readonly isApiConnectedSubject: BehaviorSubject<boolean>;
17
+ readonly connectionStatusSubject: BehaviorSubject<_ChainConnectionStatus>;
17
18
  isApiReady: boolean;
18
19
  isApiReadyOnce: boolean;
19
20
  isReadyHandler: PromiseHandler<_EvmApi>;
20
21
  intervalCheckApi: NodeJS.Timer;
21
22
  providerName: string;
22
23
  get isApiConnected(): boolean;
23
- private updateConnectedStatus;
24
+ get connectionStatus(): _ChainConnectionStatus;
25
+ private updateConnectionStatus;
24
26
  get isReady(): Promise<_EvmApi>;
25
27
  updateApiUrl(apiUrl: string): Promise<void>;
26
28
  recoverConnect(): Promise<void>;
@@ -2,21 +2,30 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
4
  import '@polkadot/types-augment';
5
+ import { _ChainConnectionStatus } from '@subwallet/extension-base/services/chain-service/types';
5
6
  import { createPromiseHandler } from '@subwallet/extension-base/utils/promise';
6
7
  import { BehaviorSubject } from 'rxjs';
7
8
  import Web3 from 'web3';
8
9
  export class EvmApi {
9
10
  apiRetry = 0;
10
11
  isApiConnectedSubject = new BehaviorSubject(false);
12
+ connectionStatusSubject = new BehaviorSubject(_ChainConnectionStatus.DISCONNECTED);
11
13
  isApiReady = false;
12
14
  isApiReadyOnce = false;
13
15
  get isApiConnected() {
14
16
  return this.isApiConnectedSubject.getValue();
15
17
  }
16
- updateConnectedStatus(isConnected) {
18
+ get connectionStatus() {
19
+ return this.connectionStatusSubject.getValue();
20
+ }
21
+ updateConnectionStatus(status) {
22
+ const isConnected = status === _ChainConnectionStatus.CONNECTED;
17
23
  if (isConnected !== this.isApiConnectedSubject.value) {
18
24
  this.isApiConnectedSubject.next(isConnected);
19
25
  }
26
+ if (status !== this.connectionStatusSubject.value) {
27
+ this.connectionStatusSubject.next(status);
28
+ }
20
29
  }
21
30
  get isReady() {
22
31
  return this.isReadyHandler.promise;
@@ -72,6 +81,7 @@ export class EvmApi {
72
81
  // For websocket provider, connect it
73
82
  const wsProvider = this.provider;
74
83
  wsProvider.connect && wsProvider.connect();
84
+ this.updateConnectionStatus(_ChainConnectionStatus.CONNECTING);
75
85
  // Check if api is ready
76
86
  this.api.eth.net.isListening().then(() => {
77
87
  this.isApiReadyOnce = true;
@@ -80,7 +90,7 @@ export class EvmApi {
80
90
  this.isApiReadyOnce = false;
81
91
  this.isApiReady = false;
82
92
  this.isReadyHandler.reject(error);
83
- this.updateConnectedStatus(false);
93
+ this.updateConnectionStatus(_ChainConnectionStatus.DISCONNECTED);
84
94
  console.warn(`Can not connect to ${this.chainSlug} (EVM) at ${this.apiUrl}`);
85
95
  });
86
96
 
@@ -94,7 +104,7 @@ export class EvmApi {
94
104
  // For websocket provider, disconnect it
95
105
  const wsProvider = this.provider;
96
106
  wsProvider.disconnect && wsProvider.disconnect();
97
- this.updateConnectedStatus(false);
107
+ this.updateConnectionStatus(_ChainConnectionStatus.DISCONNECTED);
98
108
  return Promise.resolve();
99
109
  }
100
110
  destroy() {
@@ -109,10 +119,10 @@ export class EvmApi {
109
119
  this.isReadyHandler.resolve(this);
110
120
  }
111
121
  }
112
- this.updateConnectedStatus(true);
122
+ this.updateConnectionStatus(_ChainConnectionStatus.CONNECTED);
113
123
  }
114
124
  onDisconnect() {
115
- this.updateConnectedStatus(false);
125
+ this.updateConnectionStatus(_ChainConnectionStatus.DISCONNECTED);
116
126
  if (this.isApiConnected) {
117
127
  console.warn(`Disconnected from ${this.chainSlug} of ${this.apiUrl} (EVM)`);
118
128
  this.isApiReady = false;
@@ -39,8 +39,8 @@ export class EvmChainHandler extends AbstractChainHandler {
39
39
  const apiObject = new EvmApi(chainSlug, apiUrl, {
40
40
  providerName
41
41
  });
42
- apiObject.isApiConnectedSubject.subscribe(this.handleConnect.bind(this, chainSlug));
43
- apiObject.isApiConnectedSubject.subscribe(onUpdateStatus);
42
+ apiObject.connectionStatusSubject.subscribe(this.handleConnection.bind(this, chainSlug));
43
+ apiObject.connectionStatusSubject.subscribe(onUpdateStatus);
44
44
  return Promise.resolve(apiObject);
45
45
  }
46
46
  async recoverApi(chainSlug) {
@@ -1,7 +1,7 @@
1
1
  import '@polkadot/types-augment';
2
2
  import { MetadataItem } from '@subwallet/extension-base/background/KoniTypes';
3
3
  import { _ApiOptions } from '@subwallet/extension-base/services/chain-service/handler/types';
4
- import { _SubstrateApi, _SubstrateDefaultFormatBalance } from '@subwallet/extension-base/services/chain-service/types';
4
+ import { _ChainConnectionStatus, _SubstrateApi, _SubstrateDefaultFormatBalance } from '@subwallet/extension-base/services/chain-service/types';
5
5
  import { BehaviorSubject } from 'rxjs';
6
6
  import { ApiPromise } from '@polkadot/api';
7
7
  import { SubmittableExtrinsicFunction } from '@polkadot/api/promise/types';
@@ -20,8 +20,11 @@ export declare class SubstrateApi implements _SubstrateApi {
20
20
  apiError?: string;
21
21
  private handleApiReady;
22
22
  readonly isApiConnectedSubject: BehaviorSubject<boolean>;
23
+ readonly connectionStatusSubject: BehaviorSubject<_ChainConnectionStatus>;
23
24
  get isApiConnected(): boolean;
24
- private updateConnectedStatus;
25
+ substrateRetry: number;
26
+ get connectionStatus(): _ChainConnectionStatus;
27
+ private updateConnectionStatus;
25
28
  apiDefaultTx?: SubmittableExtrinsicFunction;
26
29
  apiDefaultTxSudo?: SubmittableExtrinsicFunction;
27
30
  defaultFormatBalance?: _SubstrateDefaultFormatBalance;
@@ -7,6 +7,7 @@ import { rpc as oakRpc, types as oakTypes } from '@oak-foundation/types';
7
7
  import { _API_OPTIONS_CHAIN_GROUP, API_AUTO_CONNECT_MS, API_CONNECT_TIMEOUT } from '@subwallet/extension-base/services/chain-service/constants';
8
8
  import { getSubstrateConnectProvider } from '@subwallet/extension-base/services/chain-service/handler/light-client';
9
9
  import { DEFAULT_AUX } from '@subwallet/extension-base/services/chain-service/handler/SubstrateChainHandler';
10
+ import { _ChainConnectionStatus } from '@subwallet/extension-base/services/chain-service/types';
10
11
  import { createPromiseHandler } from '@subwallet/extension-base/utils/promise';
11
12
  import { spec as availSpec } from 'avail-js-sdk';
12
13
  import { BehaviorSubject } from 'rxjs';
@@ -20,13 +21,22 @@ export class SubstrateApi {
20
21
  isApiReady = false;
21
22
  isApiReadyOnce = false;
22
23
  isApiConnectedSubject = new BehaviorSubject(false);
24
+ connectionStatusSubject = new BehaviorSubject(_ChainConnectionStatus.DISCONNECTED);
23
25
  get isApiConnected() {
24
26
  return this.isApiConnectedSubject.getValue();
25
27
  }
26
- updateConnectedStatus(isConnected) {
28
+ substrateRetry = 0;
29
+ get connectionStatus() {
30
+ return this.connectionStatusSubject.getValue();
31
+ }
32
+ updateConnectionStatus(status) {
33
+ const isConnected = status === _ChainConnectionStatus.CONNECTED;
27
34
  if (isConnected !== this.isApiConnectedSubject.value) {
28
35
  this.isApiConnectedSubject.next(isConnected);
29
36
  }
37
+ if (status !== this.connectionStatusSubject.value) {
38
+ this.connectionStatusSubject.next(status);
39
+ }
30
40
  }
31
41
  specName = '';
32
42
  specVersion = '';
@@ -54,12 +64,14 @@ export class SubstrateApi {
54
64
  [`${metadata.genesisHash}-${metadata.specVersion}`]: metadata.hexValue
55
65
  };
56
66
  }
67
+ this.updateConnectionStatus(_ChainConnectionStatus.CONNECTING);
68
+ let api;
57
69
  if (_API_OPTIONS_CHAIN_GROUP.acala.includes(this.chainSlug)) {
58
- return new ApiPromise(acalaOptions({
70
+ api = new ApiPromise(acalaOptions({
59
71
  provider
60
72
  }));
61
73
  } else if (_API_OPTIONS_CHAIN_GROUP.turing.includes(this.chainSlug)) {
62
- return new ApiPromise({
74
+ api = new ApiPromise({
63
75
  provider,
64
76
  rpc: oakRpc,
65
77
  types: oakTypes
@@ -72,8 +84,13 @@ export class SubstrateApi {
72
84
  signedExtensions: availSpec.signedExtensions
73
85
  });
74
86
  } else {
75
- return new ApiPromise(apiOption);
87
+ api = new ApiPromise(apiOption);
76
88
  }
89
+ api.on('ready', this.onReady.bind(this));
90
+ api.on('connected', this.onConnect.bind(this));
91
+ api.on('disconnected', this.onDisconnect.bind(this));
92
+ api.on('error', this.onError.bind(this));
93
+ return api;
77
94
  }
78
95
  constructor(chainSlug, apiUrl, {
79
96
  externalApiPromise,
@@ -88,10 +105,6 @@ export class SubstrateApi {
88
105
  this.provider = this.createProvider(apiUrl);
89
106
  this.api = externalApiPromise || this.createApi(this.provider);
90
107
  this.handleApiReady = createPromiseHandler();
91
- this.api.on('ready', this.onReady.bind(this));
92
- this.api.on('connected', this.onConnect.bind(this));
93
- this.api.on('disconnected', this.onDisconnect.bind(this));
94
- this.api.on('error', this.onError.bind(this));
95
108
  }
96
109
  get isReady() {
97
110
  return this.handleApiReady.promise;
@@ -113,17 +126,16 @@ export class SubstrateApi {
113
126
  this.apiUrl = apiUrl;
114
127
  this.provider = this.createProvider(apiUrl);
115
128
  this.api = this.createApi(this.provider);
116
- this.api.on('ready', this.onReady.bind(this));
117
- this.api.on('connected', this.onConnect.bind(this));
118
- this.api.on('disconnected', this.onDisconnect.bind(this));
119
- this.api.on('error', this.onError.bind(this));
120
129
  }
121
130
  connect() {
122
131
  if (this.api.isConnected) {
123
- this.updateConnectedStatus(true);
132
+ this.updateConnectionStatus(_ChainConnectionStatus.CONNECTED);
124
133
  } else {
134
+ this.updateConnectionStatus(_ChainConnectionStatus.CONNECTING);
125
135
  this.api.connect().then(() => {
126
- this.updateConnectedStatus(true);
136
+ this.api.isReady.then(() => {
137
+ this.updateConnectionStatus(_ChainConnectionStatus.CONNECTED);
138
+ }).catch(console.error);
127
139
  }).catch(console.error);
128
140
  }
129
141
  }
@@ -133,7 +145,7 @@ export class SubstrateApi {
133
145
  } catch (e) {
134
146
  console.error(e);
135
147
  }
136
- this.updateConnectedStatus(false);
148
+ this.updateConnectionStatus(_ChainConnectionStatus.DISCONNECTED);
137
149
  }
138
150
  async recoverConnect() {
139
151
  await this.disconnect();
@@ -155,7 +167,8 @@ export class SubstrateApi {
155
167
  });
156
168
  }
157
169
  onConnect() {
158
- this.updateConnectedStatus(true);
170
+ this.updateConnectionStatus(_ChainConnectionStatus.CONNECTED);
171
+ this.substrateRetry = 0;
159
172
  console.log(`Connected to ${this.chainSlug || ''} at ${this.apiUrl}`);
160
173
  if (this.isApiReadyOnce) {
161
174
  this.handleApiReady.resolve(this);
@@ -164,8 +177,14 @@ export class SubstrateApi {
164
177
  onDisconnect() {
165
178
  this.isApiReady = false;
166
179
  console.log(`Disconnected from ${this.chainSlug} at ${this.apiUrl}`);
167
- this.updateConnectedStatus(false);
180
+ this.updateConnectionStatus(_ChainConnectionStatus.DISCONNECTED);
168
181
  this.handleApiReady = createPromiseHandler();
182
+ this.substrateRetry += 1;
183
+ if (this.substrateRetry > 9) {
184
+ this.disconnect().then(() => {
185
+ this.updateConnectionStatus(_ChainConnectionStatus.UNSTABLE);
186
+ }).catch(console.error);
187
+ }
169
188
  }
170
189
  onError(e) {
171
190
  console.warn(`${this.chainSlug} connection got error`, e);
@@ -3,7 +3,7 @@
3
3
 
4
4
  import { _AssetType } from '@subwallet/chain-list/types';
5
5
  import { getDefaultWeightV2 } from '@subwallet/extension-base/koni/api/tokens/wasm/utils';
6
- import { AbstractChainHandler, SHORT_RETRY_TIME } from '@subwallet/extension-base/services/chain-service/handler/AbstractChainHandler';
6
+ import { AbstractChainHandler } from '@subwallet/extension-base/services/chain-service/handler/AbstractChainHandler';
7
7
  import { SubstrateApi } from '@subwallet/extension-base/services/chain-service/handler/SubstrateApi';
8
8
  import { ContractPromise } from '@polkadot/api-contract';
9
9
  import { BN } from '@polkadot/util';
@@ -34,12 +34,12 @@ export class SubstrateChainHandler extends AbstractChainHandler {
34
34
 
35
35
  // Not found substrateInterface mean it active with evm interface
36
36
  if (api) {
37
- api === null || api === void 0 ? void 0 : api.connect();
37
+ api.connect();
38
38
  if (!api.useLightClient) {
39
39
  // Manual fire handle connect to avoid some chain can not reconnect
40
40
  setTimeout(() => {
41
- this.handleConnect(chain, api.isApiConnected);
42
- }, SHORT_RETRY_TIME);
41
+ this.handleConnection(chain, api.connectionStatus);
42
+ }, 10000);
43
43
  }
44
44
  }
45
45
  }
@@ -194,8 +194,8 @@ export class SubstrateChainHandler extends AbstractChainHandler {
194
194
  metadata,
195
195
  externalApiPromise
196
196
  });
197
- apiObject.isApiConnectedSubject.subscribe(this.handleConnect.bind(this, chainSlug));
198
- onUpdateStatus && apiObject.isApiConnectedSubject.subscribe(onUpdateStatus);
197
+ apiObject.connectionStatusSubject.subscribe(this.handleConnection.bind(this, chainSlug));
198
+ onUpdateStatus && apiObject.connectionStatusSubject.subscribe(onUpdateStatus);
199
199
 
200
200
  // Update metadata to database with async methods
201
201
  apiObject.isReady.then(api => {
@@ -1,4 +1,5 @@
1
1
  import { MetadataItem } from '@subwallet/extension-base/background/KoniTypes';
2
+ import { _ChainConnectionStatus } from '@subwallet/extension-base/services/chain-service/types';
2
3
  import { ApiPromise } from '@polkadot/api';
3
4
  export interface _EvmChainSpec {
4
5
  evmChainId: number;
@@ -19,7 +20,7 @@ export interface _SubstrateChainSpec {
19
20
  export interface _ApiOptions {
20
21
  providerName?: string;
21
22
  metadata?: MetadataItem;
22
- onUpdateStatus?: (isConnected: boolean) => void;
23
+ onUpdateStatus?: (status: _ChainConnectionStatus) => void;
23
24
  externalApiPromise?: ApiPromise;
24
25
  }
25
26
  export declare enum _CHAIN_VALIDATION_ERROR {
@@ -73,6 +73,7 @@ export declare class ChainService {
73
73
  private destroyApiForChain;
74
74
  enableChain(chainSlug: string): Promise<boolean>;
75
75
  enableChains(chainSlugs: string[]): Promise<boolean>;
76
+ reconnectChain(chain: string): Promise<boolean>;
76
77
  disableChain(chainSlug: string): boolean;
77
78
  private checkExistedPredefinedChain;
78
79
  private fetchLatestData;
@@ -381,7 +381,7 @@ export class ChainService {
381
381
  this.dataMap.assetRefMap = latestAssetRefMap;
382
382
  await this.initChains();
383
383
  this.chainInfoMapSubject.next(this.getChainInfoMap());
384
- this.chainStateMapSubject.next(this.getChainStateMap());
384
+ this.updateChainStateMapSubscription();
385
385
  this.assetRegistrySubject.next(this.getAssetRegistry());
386
386
  this.xcmRefMapSubject.next(this.dataMap.assetRefMap);
387
387
  await this.initApis();
@@ -407,14 +407,14 @@ export class ChainService {
407
407
  endpoint,
408
408
  providerName
409
409
  } = this.getChainCurrentProviderByKey(chainInfo.slug);
410
- const onUpdateStatus = isConnected => {
410
+ const onUpdateStatus = status => {
411
411
  const currentStatus = this.getChainStateByKey(chainInfo.slug).connectionStatus;
412
- const newStatus = isConnected ? _ChainConnectionStatus.CONNECTED : _ChainConnectionStatus.DISCONNECTED;
413
412
 
414
413
  // Avoid unnecessary update in case disable chain
415
- if (currentStatus !== newStatus) {
416
- this.setChainConnectionStatus(chainInfo.slug, newStatus);
417
- this.chainStateMapSubject.next(this.getChainStateMap());
414
+ if (currentStatus !== status) {
415
+ console.log(chainInfo.name, currentStatus, status);
416
+ this.setChainConnectionStatus(chainInfo.slug, status);
417
+ this.updateChainStateMapSubscription();
418
418
  }
419
419
  };
420
420
  if (chainInfo.substrateInfo !== null && chainInfo.substrateInfo !== undefined) {
@@ -499,6 +499,12 @@ export class ChainService {
499
499
  needUpdate && this.updateChainStateMapSubscription();
500
500
  return needUpdate;
501
501
  }
502
+ async reconnectChain(chain) {
503
+ var _this$getSubstrateApi, _this$getEvmApi;
504
+ await ((_this$getSubstrateApi = this.getSubstrateApi(chain)) === null || _this$getSubstrateApi === void 0 ? void 0 : _this$getSubstrateApi.recoverConnect());
505
+ await ((_this$getEvmApi = this.getEvmApi(chain)) === null || _this$getEvmApi === void 0 ? void 0 : _this$getEvmApi.recoverConnect());
506
+ return true;
507
+ }
502
508
  disableChain(chainSlug) {
503
509
  const chainInfo = this.getChainInfoByKey(chainSlug);
504
510
  const chainStateMap = this.getChainStateMap();
@@ -38,6 +38,7 @@ export interface _ChainBaseApi {
38
38
  isApiConnectedSubject: BehaviorSubject<boolean>;
39
39
  isApiReadyOnce: boolean;
40
40
  isApiConnected: boolean;
41
+ connectionStatus: _ChainConnectionStatus;
41
42
  updateApiUrl: (apiUrl: string) => Promise<void>;
42
43
  connect: () => void;
43
44
  disconnect: () => Promise<void>;