@subwallet/extension-base 1.1.22-0 → 1.1.24-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/background/KoniTypes.d.ts +21 -2
  2. package/cjs/koni/api/dotsama/balance.js +49 -0
  3. package/cjs/koni/api/dotsama/crowdloan.js +29 -3
  4. package/cjs/koni/api/dotsama/transfer.js +10 -3
  5. package/cjs/koni/api/staking/bonding/astar.js +9 -5
  6. package/cjs/koni/api/xcm/index.js +6 -1
  7. package/cjs/koni/api/xcm/polkadotXcm.js +1 -3
  8. package/cjs/koni/api/xcm/xTokens.js +1 -1
  9. package/cjs/koni/background/handlers/Extension.js +123 -96
  10. package/cjs/koni/background/handlers/Mobile.js +32 -0
  11. package/cjs/koni/background/handlers/State.js +15 -7
  12. package/cjs/koni/background/subscription.js +1 -1
  13. package/cjs/packageInfo.js +1 -1
  14. package/cjs/services/chain-service/constants.js +5 -2
  15. package/cjs/services/chain-service/index.js +18 -0
  16. package/cjs/services/history-service/helpers/subscan-extrinsic-parser-helper.js +53 -0
  17. package/cjs/services/history-service/index.js +78 -21
  18. package/cjs/services/history-service/subscan-history.js +107 -0
  19. package/cjs/services/storage-service/DatabaseService.js +40 -0
  20. package/cjs/services/subscan-service/index.js +109 -4
  21. package/cjs/services/subscan-service/subscan-chain-map.js +82 -8
  22. package/cjs/utils/index.js +10 -1
  23. package/koni/api/dotsama/balance.js +49 -0
  24. package/koni/api/dotsama/crowdloan.d.ts +2 -2
  25. package/koni/api/dotsama/crowdloan.js +29 -2
  26. package/koni/api/dotsama/transfer.js +10 -3
  27. package/koni/api/staking/bonding/astar.js +9 -5
  28. package/koni/api/xcm/index.js +6 -1
  29. package/koni/api/xcm/polkadotXcm.js +2 -4
  30. package/koni/api/xcm/xTokens.js +1 -1
  31. package/koni/background/handlers/Extension.d.ts +1 -0
  32. package/koni/background/handlers/Extension.js +26 -0
  33. package/koni/background/handlers/Mobile.d.ts +5 -1
  34. package/koni/background/handlers/Mobile.js +31 -0
  35. package/koni/background/handlers/State.d.ts +1 -0
  36. package/koni/background/handlers/State.js +17 -9
  37. package/koni/background/subscription.js +1 -1
  38. package/package.json +17 -6
  39. package/packageInfo.js +1 -1
  40. package/services/chain-service/constants.d.ts +2 -0
  41. package/services/chain-service/constants.js +5 -3
  42. package/services/chain-service/index.d.ts +1 -0
  43. package/services/chain-service/index.js +18 -0
  44. package/services/history-service/helpers/subscan-extrinsic-parser-helper.d.ts +6 -0
  45. package/services/history-service/helpers/subscan-extrinsic-parser-helper.js +44 -0
  46. package/services/history-service/index.d.ts +10 -6
  47. package/services/history-service/index.js +79 -22
  48. package/services/history-service/subscan-history.d.ts +5 -0
  49. package/services/history-service/subscan-history.js +100 -0
  50. package/services/storage-service/DatabaseService.d.ts +3 -0
  51. package/services/storage-service/DatabaseService.js +40 -0
  52. package/services/subscan-service/index.d.ts +10 -2
  53. package/services/subscan-service/index.js +105 -4
  54. package/services/subscan-service/subscan-chain-map.d.ts +9 -3
  55. package/services/subscan-service/subscan-chain-map.js +78 -5
  56. package/services/subscan-service/types.d.ts +146 -0
  57. package/utils/index.d.ts +1 -0
  58. package/utils/index.js +7 -0
@@ -1,6 +1,7 @@
1
1
  // Copyright 2019-2022 @subwallet/extension-koni authors & contributors
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
+ import { createPromiseHandler } from '@subwallet/extension-base/utils/promise';
4
5
  const DEFAULT_SERVICE_MAP = {
5
6
  subscription: {
6
7
  chainRegistry: true,
@@ -20,6 +21,7 @@ const DEFAULT_SERVICE_MAP = {
20
21
  export default class Mobile {
21
22
  // @ts-ignore
22
23
 
24
+ restoreHandler = createPromiseHandler();
23
25
  constructor(state) {
24
26
  this.state = state;
25
27
  }
@@ -92,6 +94,31 @@ export default class Mobile {
92
94
  restartSubscriptionServices(services) {
93
95
  console.log('restartSubscriptionServices');
94
96
  }
97
+ async mobileBackup() {
98
+ const indexedDB = await this.state.dbService.exportDB();
99
+ return {
100
+ storage: JSON.stringify(localStorage),
101
+ indexedDB
102
+ };
103
+ }
104
+ async mobileRestore({
105
+ indexedDB,
106
+ storage
107
+ }) {
108
+ if (storage) {
109
+ const storageData = JSON.parse(storage);
110
+ for (const key in storageData) {
111
+ localStorage.setItem(key, JSON.stringify(storageData[key]));
112
+ }
113
+ }
114
+ if (indexedDB) {
115
+ await this.state.dbService.importDB(indexedDB);
116
+ }
117
+ this.restoreHandler.resolve();
118
+ }
119
+ waitRestore() {
120
+ return this.restoreHandler.promise;
121
+ }
95
122
 
96
123
  // eslint-disable-next-line @typescript-eslint/require-await
97
124
  async handle(id, type, request, port) {
@@ -120,6 +147,10 @@ export default class Mobile {
120
147
  return this.stopSubscriptionServices(request);
121
148
  case 'mobile(subscription.restart)':
122
149
  return this.restartSubscriptionServices(request);
150
+ case 'mobile(storage.restore)':
151
+ return this.mobileRestore(request);
152
+ case 'mobile(storage.backup)':
153
+ return this.mobileBackup();
123
154
  default:
124
155
  throw new Error(`Unable to handle message of type ${type}`);
125
156
  }
@@ -84,6 +84,7 @@ export default class KoniState {
84
84
  sign(url: string, request: RequestSign, account: AccountJson): Promise<ResponseSigning>;
85
85
  get authSubjectV2(): BehaviorSubject<import("@subwallet/extension-base/background/types").AuthorizeRequest[]>;
86
86
  generateDefaultBalanceMap(): Record<string, BalanceItem>;
87
+ private afterChainServiceInit;
87
88
  init(): Promise<void>;
88
89
  initMantaPay(password: string): Promise<void>;
89
90
  private startSubscription;
@@ -23,11 +23,11 @@ import RequestService from '@subwallet/extension-base/services/request-service';
23
23
  import SettingService from '@subwallet/extension-base/services/setting-service/SettingService';
24
24
  import DatabaseService from '@subwallet/extension-base/services/storage-service/DatabaseService';
25
25
  import { SubscanService } from '@subwallet/extension-base/services/subscan-service';
26
- import { SUBSCAN_CHAIN_MAP_REVERSE } from '@subwallet/extension-base/services/subscan-service/subscan-chain-map';
26
+ import { SUBSCAN_API_CHAIN_MAP, SUBSCAN_BALANCE_CHAIN_MAP_REVERSE } from '@subwallet/extension-base/services/subscan-service/subscan-chain-map';
27
27
  import TransactionService from '@subwallet/extension-base/services/transaction-service';
28
28
  import WalletConnectService from '@subwallet/extension-base/services/wallet-connect-service';
29
29
  import AccountRefStore from '@subwallet/extension-base/stores/AccountRef';
30
- import { stripUrl } from '@subwallet/extension-base/utils';
30
+ import { stripUrl, TARGET_ENV } from '@subwallet/extension-base/utils';
31
31
  import { isContractAddress, parseContractInput } from '@subwallet/extension-base/utils/eth/parseTransaction';
32
32
  import { createPromiseHandler } from '@subwallet/extension-base/utils/promise';
33
33
  import { decodePair } from '@subwallet/keyring/pair/decode';
@@ -84,14 +84,14 @@ export default class KoniState {
84
84
  this.eventService = new EventService();
85
85
  this.dbService = new DatabaseService(this.eventService);
86
86
  this.keyringService = new KeyringService(this.eventService);
87
- this.subscanService = new SubscanService();
88
87
  this.notificationService = new NotificationService();
89
88
  this.chainService = new ChainService(this.dbService, this.eventService);
89
+ this.subscanService = new SubscanService(SUBSCAN_API_CHAIN_MAP);
90
90
  this.settingService = new SettingService();
91
91
  this.requestService = new RequestService(this.chainService, this.settingService, this.keyringService);
92
92
  this.priceService = new PriceService(this.dbService, this.eventService, this.chainService);
93
93
  this.balanceService = new BalanceService(this.chainService);
94
- this.historyService = new HistoryService(this.dbService, this.chainService, this.eventService, this.keyringService);
94
+ this.historyService = new HistoryService(this.dbService, this.chainService, this.eventService, this.keyringService, this.subscanService);
95
95
  this.transactionService = new TransactionService(this.chainService, this.eventService, this.requestService, this.balanceService, this.historyService, this.notificationService, this.dbService);
96
96
  this.walletConnectService = new WalletConnectService(this, this.requestService);
97
97
  this.migrationService = new MigrationService(this, this.eventService);
@@ -102,7 +102,9 @@ export default class KoniState {
102
102
  this.logger = createLogger('State');
103
103
 
104
104
  // Init state
105
- this.init().catch(console.error);
105
+ if (TARGET_ENV !== 'mobile') {
106
+ this.init().catch(console.error);
107
+ }
106
108
  }
107
109
 
108
110
  // Clone from polkadot.js
@@ -198,9 +200,13 @@ export default class KoniState {
198
200
  });
199
201
  return balanceMap;
200
202
  }
203
+ afterChainServiceInit() {
204
+ this.subscanService.setSubscanChainMap(this.chainService.getSubscanChainMap());
205
+ }
201
206
  async init() {
202
207
  await this.eventService.waitCryptoReady;
203
208
  await this.chainService.init();
209
+ this.afterChainServiceInit();
204
210
  await this.migrationService.run();
205
211
  this.eventService.emit('chain.ready', true);
206
212
  this.onReady();
@@ -1469,7 +1475,7 @@ export default class KoniState {
1469
1475
  symbol
1470
1476
  }) => {
1471
1477
  var _currentAssetSettings;
1472
- const chain = SUBSCAN_CHAIN_MAP_REVERSE[network];
1478
+ const chain = SUBSCAN_BALANCE_CHAIN_MAP_REVERSE[network];
1473
1479
  const chainInfo = chain ? chainMap[chain] : null;
1474
1480
  const balanceIsEmpty = (!balance || balance === '0') && (!locked || locked === '0') && (!bonded || bonded === '0');
1475
1481
 
@@ -1478,10 +1484,11 @@ export default class KoniState {
1478
1484
  return;
1479
1485
  }
1480
1486
  const tokenKey = `${chain}-${category === 'native' ? 'NATIVE' : 'LOCAL'}-${symbol.toUpperCase()}`;
1481
- if (assetMap[tokenKey] && !((_currentAssetSettings = currentAssetSettings[tokenKey]) !== null && _currentAssetSettings !== void 0 && _currentAssetSettings.visible)) {
1487
+ const existedKey = Object.keys(assetMap).find(v => v.toLowerCase() === tokenKey.toLowerCase());
1488
+ if (existedKey && !((_currentAssetSettings = currentAssetSettings[existedKey]) !== null && _currentAssetSettings !== void 0 && _currentAssetSettings.visible)) {
1482
1489
  needEnableChains.push(chain);
1483
- needActiveTokens.push(tokenKey);
1484
- currentAssetSettings[tokenKey] = {
1490
+ needActiveTokens.push(existedKey);
1491
+ currentAssetSettings[existedKey] = {
1485
1492
  visible: true
1486
1493
  };
1487
1494
  }
@@ -1553,6 +1560,7 @@ export default class KoniState {
1553
1560
  this.chainService.resetWallet(resetAll);
1554
1561
  await this.walletConnectService.resetWallet(resetAll);
1555
1562
  await this.chainService.init();
1563
+ this.afterChainServiceInit();
1556
1564
  }
1557
1565
  async enableMantaPay(updateStore, address, password, seedPhrase) {
1558
1566
  var _this$chainService3, _this$chainService3$m, _this$chainService4, _this$chainService4$m, _this$chainService4$m2, _this$chainService11, _this$chainService11$, _this$chainService11$2;
@@ -163,7 +163,7 @@ export class KoniSubscription {
163
163
  initCrowdloanSubscription(addresses, substrateApiMap, onlyRunOnFirstTime) {
164
164
  const subscriptionPromise = subscribeCrowdloan(addresses, substrateApiMap, (networkKey, rs) => {
165
165
  this.state.setCrowdloanItem(networkKey, rs);
166
- }, this.state.getChainInfoMap());
166
+ });
167
167
  if (onlyRunOnFirstTime) {
168
168
  subscriptionPromise.then(unsub => {
169
169
  unsub && unsub();
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "./cjs/detectPackage.js"
18
18
  ],
19
19
  "type": "module",
20
- "version": "1.1.22-0",
20
+ "version": "1.1.24-0",
21
21
  "main": "./cjs/index.js",
22
22
  "module": "./index.js",
23
23
  "types": "./index.d.ts",
@@ -673,6 +673,16 @@
673
673
  "require": "./cjs/services/history-service/helpers/recoverHistoryStatus.js",
674
674
  "default": "./services/history-service/helpers/recoverHistoryStatus.js"
675
675
  },
676
+ "./services/history-service/helpers/subscan-extrinsic-parser-helper": {
677
+ "types": "./services/history-service/helpers/subscan-extrinsic-parser-helper.d.ts",
678
+ "require": "./cjs/services/history-service/helpers/subscan-extrinsic-parser-helper.js",
679
+ "default": "./services/history-service/helpers/subscan-extrinsic-parser-helper.js"
680
+ },
681
+ "./services/history-service/subscan-history": {
682
+ "types": "./services/history-service/subscan-history.d.ts",
683
+ "require": "./cjs/services/history-service/subscan-history.js",
684
+ "default": "./services/history-service/subscan-history.js"
685
+ },
676
686
  "./services/history-service/subsquid-multi-chain-history": {
677
687
  "types": "./services/history-service/subsquid-multi-chain-history.d.ts",
678
688
  "require": "./cjs/services/history-service/subsquid-multi-chain-history.js",
@@ -1312,11 +1322,11 @@
1312
1322
  "@reduxjs/toolkit": "^1.9.1",
1313
1323
  "@sora-substrate/type-definitions": "^1.17.7",
1314
1324
  "@substrate/connect": "^0.7.26",
1315
- "@subwallet/chain-list": "0.2.25",
1316
- "@subwallet/extension-base": "^1.1.22-0",
1317
- "@subwallet/extension-chains": "^1.1.22-0",
1318
- "@subwallet/extension-dapp": "^1.1.22-0",
1319
- "@subwallet/extension-inject": "^1.1.22-0",
1325
+ "@subwallet/chain-list": "0.2.26",
1326
+ "@subwallet/extension-base": "^1.1.24-0",
1327
+ "@subwallet/extension-chains": "^1.1.24-0",
1328
+ "@subwallet/extension-dapp": "^1.1.24-0",
1329
+ "@subwallet/extension-inject": "^1.1.24-0",
1320
1330
  "@subwallet/keyring": "^0.1.1",
1321
1331
  "@subwallet/ui-keyring": "^0.1.1",
1322
1332
  "@walletconnect/sign-client": "^2.8.4",
@@ -1331,6 +1341,7 @@
1331
1341
  "buffer": "^6.0.3",
1332
1342
  "cross-fetch": "^3.1.5",
1333
1343
  "dexie": "^3.2.2",
1344
+ "dexie-export-import": "^4.0.7",
1334
1345
  "eth-simple-keyring": "^4.2.0",
1335
1346
  "ethereumjs-tx": "^2.1.2",
1336
1347
  "ethereumjs-util": "^7.1.5",
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.22-0'
10
+ version: '1.1.24-0'
11
11
  };
@@ -17,6 +17,7 @@ export declare const _BALANCE_CHAIN_GROUP: {
17
17
  bifrost: string[];
18
18
  statemine: string[];
19
19
  kusama: string[];
20
+ centrifuge: string[];
20
21
  };
21
22
  export declare const _BALANCE_TOKEN_GROUP: {
22
23
  crab: string[];
@@ -71,6 +72,7 @@ export declare const _TRANSFER_CHAIN_GROUP: {
71
72
  sora_substrate: string[];
72
73
  avail: string[];
73
74
  pendulum: string[];
75
+ centrifuge: string[];
74
76
  };
75
77
  export declare const _BALANCE_PARSING_CHAIN_GROUP: {
76
78
  bobabeam: string[];
@@ -30,9 +30,10 @@ export const _BALANCE_CHAIN_GROUP = {
30
30
  equilibrium_parachain: ['equilibrium_parachain'],
31
31
  bifrost: ['bifrost', 'acala', 'karura', 'acala_testnet', 'pioneer', 'bitcountry', 'bifrost_dot', 'hydradx_main', 'pendulum', 'amplitude'],
32
32
  statemine: ['statemine', 'astar', 'shiden', 'statemint', 'moonbeam', 'moonbase', 'moonriver', 'crabParachain', 'darwinia2', 'parallel', 'calamari'],
33
- kusama: ['kusama', 'kintsugi', 'kintsugi_test', 'interlay', 'acala', 'statemint', 'karura', 'bifrost'] // perhaps there are some runtime updates
33
+ kusama: ['kusama', 'kintsugi', 'kintsugi_test', 'interlay', 'acala', 'statemint', 'karura', 'bifrost'],
34
+ // perhaps there are some runtime updates
35
+ centrifuge: ['centrifuge']
34
36
  };
35
-
36
37
  export const _BALANCE_TOKEN_GROUP = {
37
38
  crab: ['CKTON', 'PKTON'],
38
39
  bitcountry: ['BIT']
@@ -194,7 +195,8 @@ export const _TRANSFER_CHAIN_GROUP = {
194
195
  riochain: ['riochain'],
195
196
  sora_substrate: ['sora_substrate'],
196
197
  avail: ['kate', 'goldberg_testnet'],
197
- pendulum: ['pendulum', 'amplitude', 'amplitude_test']
198
+ pendulum: ['pendulum', 'amplitude', 'amplitude_test'],
199
+ centrifuge: ['centrifuge']
198
200
  };
199
201
  export const _BALANCE_PARSING_CHAIN_GROUP = {
200
202
  bobabeam: ['bobabeam', 'bobabase']
@@ -113,4 +113,5 @@ export declare class ChainService {
113
113
  getMetadata(chain: string): import("dexie").PromiseExtended<IMetadataItem | undefined>;
114
114
  upsertMetadata(chain: string, metadata: IMetadataItem): import("dexie").PromiseExtended<unknown>;
115
115
  getMetadataByHash(hash: string): import("dexie").PromiseExtended<IMetadataItem | undefined>;
116
+ getSubscanChainMap(reverse?: boolean): Record<string, string>;
116
117
  }
@@ -1381,4 +1381,22 @@ export class ChainService {
1381
1381
  getMetadataByHash(hash) {
1382
1382
  return this.dbService.stores.metadata.getMetadataByGenesisHash(hash);
1383
1383
  }
1384
+ getSubscanChainMap(reverse) {
1385
+ const result = {};
1386
+ const chainInfoMap = this.getChainInfoMap();
1387
+ Object.values(chainInfoMap).forEach(i => {
1388
+ var _i$extraInfo;
1389
+ if (!((_i$extraInfo = i.extraInfo) !== null && _i$extraInfo !== void 0 && _i$extraInfo.subscanSlug)) {
1390
+ return;
1391
+ }
1392
+ if (!reverse) {
1393
+ var _i$extraInfo2;
1394
+ result[i.slug] = (_i$extraInfo2 = i.extraInfo) === null || _i$extraInfo2 === void 0 ? void 0 : _i$extraInfo2.subscanSlug;
1395
+ } else {
1396
+ var _i$extraInfo3;
1397
+ result[(_i$extraInfo3 = i.extraInfo) === null || _i$extraInfo3 === void 0 ? void 0 : _i$extraInfo3.subscanSlug] = i.slug;
1398
+ }
1399
+ });
1400
+ return result;
1401
+ }
1384
1402
  }
@@ -0,0 +1,6 @@
1
+ import { TransactionHistoryItem } from '@subwallet/extension-base/background/KoniTypes';
2
+ import { ExtrinsicItem } from '@subwallet/extension-base/services/subscan-service/types';
3
+ export declare type ExtrinsicParserFunction = (item: TransactionHistoryItem) => TransactionHistoryItem | null;
4
+ export declare function getExtrinsicParserKey(extrinsicItem: ExtrinsicItem): string;
5
+ export declare const subscanExtrinsicParserMap: Record<string, ExtrinsicParserFunction>;
6
+ export declare const supportedExtrinsicParser: string[];
@@ -0,0 +1,44 @@
1
+ // Copyright 2019-2022 @subwallet/extension-koni authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
5
+ import { encodeAddress } from '@polkadot/util-crypto';
6
+ export function getExtrinsicParserKey(extrinsicItem) {
7
+ return `${extrinsicItem.call_module}.${extrinsicItem.call_module_function}`;
8
+ }
9
+ function paramJsonParse(item) {
10
+ try {
11
+ return JSON.parse(item.data || '[]');
12
+ } catch (e) {
13
+ return [];
14
+ }
15
+ }
16
+ function balanceTransferParserFunction(item) {
17
+ const params = paramJsonParse(item);
18
+ params.forEach(p => {
19
+ if (p.name === 'dest') {
20
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
21
+ const toPublicKey = p.value.id || p.value.Id;
22
+ if (toPublicKey) {
23
+ item.to = encodeAddress(toPublicKey, 42);
24
+ }
25
+ } else if (p.name === 'value') {
26
+ if (item.amount) {
27
+ item.amount.value = p.value;
28
+ }
29
+ }
30
+ });
31
+ item.type = ExtrinsicType.TRANSFER_BALANCE;
32
+ if (!item.to) {
33
+ return null;
34
+ }
35
+ return item;
36
+ }
37
+
38
+ // todo: will support other type later
39
+ export const subscanExtrinsicParserMap = {
40
+ 'balances.transfer': balanceTransferParserFunction,
41
+ 'balances.transfer_keep_alive': balanceTransferParserFunction,
42
+ 'balances.transfer_allow_death': balanceTransferParserFunction
43
+ };
44
+ export const supportedExtrinsicParser = Object.keys(subscanExtrinsicParserMap);
@@ -1,24 +1,30 @@
1
1
  import { TransactionHistoryItem } from '@subwallet/extension-base/background/KoniTypes';
2
- import { CronServiceInterface, PersistDataServiceInterface, ServiceStatus, StoppableServiceInterface } from '@subwallet/extension-base/services/base/types';
2
+ import { PersistDataServiceInterface, ServiceStatus, StoppableServiceInterface } from '@subwallet/extension-base/services/base/types';
3
3
  import { ChainService } from '@subwallet/extension-base/services/chain-service';
4
4
  import { EventService } from '@subwallet/extension-base/services/event-service';
5
5
  import { KeyringService } from '@subwallet/extension-base/services/keyring-service';
6
6
  import DatabaseService from '@subwallet/extension-base/services/storage-service/DatabaseService';
7
+ import { SubscanService } from '@subwallet/extension-base/services/subscan-service';
7
8
  import { BehaviorSubject } from 'rxjs';
8
- export declare class HistoryService implements StoppableServiceInterface, PersistDataServiceInterface, CronServiceInterface {
9
+ export declare class HistoryService implements StoppableServiceInterface, PersistDataServiceInterface {
9
10
  #private;
10
11
  private dbService;
11
12
  private chainService;
12
13
  private eventService;
13
14
  private keyringService;
15
+ private subscanService;
14
16
  private historySubject;
15
- constructor(dbService: DatabaseService, chainService: ChainService, eventService: EventService, keyringService: KeyringService);
17
+ constructor(dbService: DatabaseService, chainService: ChainService, eventService: EventService, keyringService: KeyringService, subscanService: SubscanService);
16
18
  private fetchPromise;
17
- private interval;
18
19
  private recoverInterval;
19
20
  private fetchAndLoadHistories;
20
21
  getHistories(): Promise<TransactionHistoryItem<import("@subwallet/extension-base/background/KoniTypes").ExtrinsicType.TRANSFER_BALANCE>[]>;
21
22
  getHistorySubject(): Promise<BehaviorSubject<TransactionHistoryItem<import("@subwallet/extension-base/background/KoniTypes").ExtrinsicType.TRANSFER_BALANCE>[]>>;
23
+ private fetchSubscanTransactionHistory;
24
+ subscribeHistories(chain: string, address: string, cb: (items: TransactionHistoryItem[]) => void): {
25
+ unsubscribe: () => void;
26
+ value: TransactionHistoryItem<import("@subwallet/extension-base/background/KoniTypes").ExtrinsicType.TRANSFER_BALANCE>[];
27
+ };
22
28
  updateHistories(chain: string, extrinsicHash: string, updateData: Partial<TransactionHistoryItem>): Promise<void>;
23
29
  updateHistoryByExtrinsicHash(extrinsicHash: string, updateData: Partial<TransactionHistoryItem>): Promise<void>;
24
30
  insertHistories(historyItems: TransactionHistoryItem[]): Promise<void>;
@@ -27,8 +33,6 @@ export declare class HistoryService implements StoppableServiceInterface, Persis
27
33
  status: ServiceStatus;
28
34
  loadData(): Promise<void>;
29
35
  persistData(): Promise<void>;
30
- startCron(): Promise<void>;
31
- stopCron(): Promise<void>;
32
36
  startRecoverHistories(): Promise<void>;
33
37
  stopRecoverHistories(): Promise<void>;
34
38
  recoverHistories(): Promise<void>;
@@ -2,24 +2,32 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
4
  import { ExtrinsicStatus } from '@subwallet/extension-base/background/KoniTypes';
5
- import { CRON_RECOVER_HISTORY_INTERVAL, CRON_REFRESH_HISTORY_INTERVAL } from '@subwallet/extension-base/constants';
5
+ import { CRON_RECOVER_HISTORY_INTERVAL } from '@subwallet/extension-base/constants';
6
6
  import { ServiceStatus } from '@subwallet/extension-base/services/base/types';
7
7
  import { historyRecover, HistoryRecoverStatus } from '@subwallet/extension-base/services/history-service/helpers/recoverHistoryStatus';
8
+ import { getExtrinsicParserKey } from '@subwallet/extension-base/services/history-service/helpers/subscan-extrinsic-parser-helper';
9
+ import { parseSubscanExtrinsicData, parseSubscanTransferData } from '@subwallet/extension-base/services/history-service/subscan-history';
10
+ import { reformatAddress } from '@subwallet/extension-base/utils';
8
11
  import { createPromiseHandler } from '@subwallet/extension-base/utils/promise';
9
12
  import { keyring } from '@subwallet/ui-keyring';
10
13
  import { BehaviorSubject } from 'rxjs';
14
+ function filterHistoryItemByAddressAndChain(chain, address) {
15
+ return item => {
16
+ return item.chain === chain && item.address === address;
17
+ };
18
+ }
11
19
  export class HistoryService {
12
20
  historySubject = new BehaviorSubject([]);
13
21
  #needRecoveryHistories = {};
14
- constructor(dbService, chainService, eventService, keyringService) {
22
+ constructor(dbService, chainService, eventService, keyringService, subscanService) {
15
23
  this.dbService = dbService;
16
24
  this.chainService = chainService;
17
25
  this.eventService = eventService;
18
26
  this.keyringService = keyringService;
27
+ this.subscanService = subscanService;
19
28
  this.init().catch(console.error);
20
29
  }
21
30
  fetchPromise = null;
22
- interval = undefined;
23
31
  recoverInterval = undefined;
24
32
  async fetchAndLoadHistories(addresses) {
25
33
  if (!addresses || addresses.length === 0) {
@@ -60,6 +68,74 @@ export class HistoryService {
60
68
  await this.getHistories();
61
69
  return this.historySubject;
62
70
  }
71
+ fetchSubscanTransactionHistory(chain, address) {
72
+ if (!this.subscanService.checkSupportedSubscanChain(chain)) {
73
+ return;
74
+ }
75
+ const chainInfo = this.chainService.getChainInfoByKey(chain);
76
+ const excludeExtrinsicParserKeys = ['balances.transfer_all'];
77
+
78
+ // Note: fetchAllPossibleExtrinsicItems and fetchAllPossibleTransferItems-receive can run parallelly
79
+ // Hover, fetchAllPossibleTransferItems-sent must run after fetchAllPossibleExtrinsicItems,
80
+ // to avoid "duplicate Extrinsic Hash between items" problem
81
+
82
+ this.subscanService.fetchAllPossibleExtrinsicItems(chain, address, extrinsicItems => {
83
+ const result = [];
84
+ extrinsicItems.forEach(x => {
85
+ const item = parseSubscanExtrinsicData(address, x, chainInfo);
86
+ if (item) {
87
+ result.push(item);
88
+ }
89
+ });
90
+ this.addHistoryItems(result).catch(e => {
91
+ console.log('addHistoryItems in fetchAllPossibleExtrinsicItems error', e);
92
+ });
93
+ }).then(extrinsicItems => {
94
+ const excludeTransferExtrinsicHash = [];
95
+ extrinsicItems.forEach(x => {
96
+ if (!excludeExtrinsicParserKeys.includes(getExtrinsicParserKey(x))) {
97
+ excludeTransferExtrinsicHash.push(x.extrinsic_hash);
98
+ }
99
+ });
100
+ this.subscanService.fetchAllPossibleTransferItems(chain, address, 'sent', transferItems => {
101
+ const result = [];
102
+ transferItems.forEach(t => {
103
+ if (!excludeTransferExtrinsicHash.includes(t.hash)) {
104
+ result.push(parseSubscanTransferData(address, t, chainInfo));
105
+ }
106
+ });
107
+ this.addHistoryItems(result).catch(e => {
108
+ console.log('addHistoryItems in fetchAllPossibleTransferItems-sent error', e);
109
+ });
110
+ }).catch(e => {
111
+ console.log('fetchAllPossibleTransferItems-sent error', e);
112
+ });
113
+ }).catch(e => {
114
+ console.log('fetchAllPossibleExtrinsicItems error', e);
115
+ });
116
+ this.subscanService.fetchAllPossibleTransferItems(chain, address, 'received', transferItems => {
117
+ const result = [];
118
+ transferItems.forEach(t => {
119
+ result.push(parseSubscanTransferData(address, t, chainInfo));
120
+ });
121
+ this.addHistoryItems(result).catch(e => {
122
+ console.log('addHistoryItems in fetchAllPossibleTransferItems-receive error', e);
123
+ });
124
+ }).catch(e => {
125
+ console.log('fetchAllPossibleTransferItems-receive error', e);
126
+ });
127
+ }
128
+ subscribeHistories(chain, address, cb) {
129
+ const _address = reformatAddress(address);
130
+ const subscription = this.historySubject.subscribe(items => {
131
+ cb(items.filter(filterHistoryItemByAddressAndChain(chain, _address)));
132
+ });
133
+ this.fetchSubscanTransactionHistory(chain, _address);
134
+ return {
135
+ unsubscribe: subscription.unsubscribe,
136
+ value: this.historySubject.getValue().filter(filterHistoryItemByAddressAndChain(chain, _address))
137
+ };
138
+ }
63
139
  async updateHistories(chain, extrinsicHash, updateData) {
64
140
  const existedRecords = await this.dbService.getHistories({
65
141
  chain,
@@ -110,17 +186,6 @@ export class HistoryService {
110
186
  async persistData() {
111
187
  await this.dbService.upsertHistory(this.historySubject.value);
112
188
  }
113
- async startCron() {
114
- await this.getHistories();
115
- this.interval = setInterval(() => {
116
- this.getHistories().catch(console.error);
117
- }, CRON_REFRESH_HISTORY_INTERVAL);
118
- }
119
- stopCron() {
120
- clearTimeout(this.interval);
121
- this.fetchPromise = null;
122
- return Promise.resolve();
123
- }
124
189
  async startRecoverHistories() {
125
190
  await this.recoverHistories();
126
191
  this.recoverInterval = setInterval(() => {
@@ -175,12 +240,6 @@ export class HistoryService {
175
240
  Promise.all([this.eventService.waitKeyringReady, this.eventService.waitChainReady]).then(() => {
176
241
  this.getHistories().catch(console.log);
177
242
  this.recoverProcessingHistory().catch(console.error);
178
- this.eventService.on('account.add', () => {
179
- (async () => {
180
- await this.stopCron();
181
- await this.startCron();
182
- })().catch(console.error);
183
- });
184
243
  this.eventService.on('account.remove', address => {
185
244
  this.removeHistoryByAddress(address).catch(console.error);
186
245
  });
@@ -209,7 +268,6 @@ export class HistoryService {
209
268
  await Promise.all([this.eventService.waitKeyringReady, this.eventService.waitChainReady]);
210
269
  this.startPromiseHandler = createPromiseHandler();
211
270
  this.status = ServiceStatus.STARTING;
212
- await this.startCron();
213
271
  this.status = ServiceStatus.STARTED;
214
272
  this.startPromiseHandler.resolve();
215
273
  } catch (e) {
@@ -225,7 +283,6 @@ export class HistoryService {
225
283
  this.stopPromiseHandler = createPromiseHandler();
226
284
  this.status = ServiceStatus.STOPPING;
227
285
  await this.persistData();
228
- await this.stopCron();
229
286
  await this.stopRecoverHistories();
230
287
  this.stopPromiseHandler.resolve();
231
288
  this.status = ServiceStatus.STOPPED;
@@ -0,0 +1,5 @@
1
+ import { _ChainInfo } from '@subwallet/chain-list/types';
2
+ import { TransactionHistoryItem } from '@subwallet/extension-base/background/KoniTypes';
3
+ import { ExtrinsicItem, TransferItem } from '@subwallet/extension-base/services/subscan-service/types';
4
+ export declare function parseSubscanExtrinsicData(address: string, extrinsicItem: ExtrinsicItem, chainInfo: _ChainInfo): TransactionHistoryItem | null;
5
+ export declare function parseSubscanTransferData(address: string, transferItem: TransferItem, chainInfo: _ChainInfo): TransactionHistoryItem;
@@ -0,0 +1,100 @@
1
+ // Copyright 2019-2022 @subwallet/extension-koni authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { ChainType, ExtrinsicStatus, ExtrinsicType, TransactionDirection } from '@subwallet/extension-base/background/KoniTypes';
5
+ import { getExtrinsicParserKey, subscanExtrinsicParserMap, supportedExtrinsicParser } from '@subwallet/extension-base/services/history-service/helpers/subscan-extrinsic-parser-helper';
6
+ import { decodeAddress, encodeAddress, isEthereumAddress } from '@polkadot/util-crypto';
7
+ function autoFormatAddress(address) {
8
+ try {
9
+ if (isEthereumAddress(address)) {
10
+ return address;
11
+ } else {
12
+ const decoded = decodeAddress(address);
13
+ return encodeAddress(decoded, 42);
14
+ }
15
+ } catch (e) {
16
+ return '';
17
+ }
18
+ }
19
+ export function parseSubscanExtrinsicData(address, extrinsicItem, chainInfo) {
20
+ var _chainInfo$substrateI, _chainInfo$evmInfo, _chainInfo$substrateI2, _chainInfo$evmInfo2;
21
+ const extrinsicParserKey = getExtrinsicParserKey(extrinsicItem);
22
+ if (!supportedExtrinsicParser.includes(extrinsicParserKey)) {
23
+ return null;
24
+ }
25
+ const chainType = chainInfo.substrateInfo ? ChainType.SUBSTRATE : ChainType.EVM;
26
+ const nativeDecimals = ((_chainInfo$substrateI = chainInfo.substrateInfo) === null || _chainInfo$substrateI === void 0 ? void 0 : _chainInfo$substrateI.decimals) || ((_chainInfo$evmInfo = chainInfo.evmInfo) === null || _chainInfo$evmInfo === void 0 ? void 0 : _chainInfo$evmInfo.decimals) || 18;
27
+ const nativeSymbol = ((_chainInfo$substrateI2 = chainInfo.substrateInfo) === null || _chainInfo$substrateI2 === void 0 ? void 0 : _chainInfo$substrateI2.symbol) || ((_chainInfo$evmInfo2 = chainInfo.evmInfo) === null || _chainInfo$evmInfo2 === void 0 ? void 0 : _chainInfo$evmInfo2.symbol) || '';
28
+ const initData = {
29
+ address,
30
+ origin: 'subscan',
31
+ time: extrinsicItem.block_timestamp * 1000,
32
+ chainType,
33
+ from: address,
34
+ signature: extrinsicItem.signature,
35
+ fromName: undefined,
36
+ direction: TransactionDirection.SEND,
37
+ blockNumber: extrinsicItem.block_num,
38
+ blockHash: '',
39
+ chain: chainInfo.slug,
40
+ type: ExtrinsicType.UNKNOWN,
41
+ to: '',
42
+ toName: undefined,
43
+ extrinsicHash: extrinsicItem.extrinsic_hash,
44
+ amount: {
45
+ value: '0',
46
+ decimals: nativeDecimals,
47
+ symbol: nativeSymbol
48
+ },
49
+ data: extrinsicItem.params,
50
+ fee: {
51
+ value: extrinsicItem.fee,
52
+ decimals: nativeDecimals,
53
+ symbol: nativeSymbol
54
+ },
55
+ status: extrinsicItem.success ? ExtrinsicStatus.SUCCESS : ExtrinsicStatus.FAIL,
56
+ nonce: extrinsicItem.nonce
57
+ };
58
+ try {
59
+ return subscanExtrinsicParserMap[extrinsicParserKey](initData);
60
+ } catch (e) {
61
+ console.log('parseSubscanExtrinsicData error:', e, initData);
62
+ return null;
63
+ }
64
+ }
65
+ export function parseSubscanTransferData(address, transferItem, chainInfo) {
66
+ var _chainInfo$substrateI3, _chainInfo$evmInfo3, _chainInfo$substrateI4, _chainInfo$evmInfo4;
67
+ const chainType = chainInfo.substrateInfo ? ChainType.SUBSTRATE : ChainType.EVM;
68
+ const nativeDecimals = ((_chainInfo$substrateI3 = chainInfo.substrateInfo) === null || _chainInfo$substrateI3 === void 0 ? void 0 : _chainInfo$substrateI3.decimals) || ((_chainInfo$evmInfo3 = chainInfo.evmInfo) === null || _chainInfo$evmInfo3 === void 0 ? void 0 : _chainInfo$evmInfo3.decimals) || 18;
69
+ const nativeSymbol = ((_chainInfo$substrateI4 = chainInfo.substrateInfo) === null || _chainInfo$substrateI4 === void 0 ? void 0 : _chainInfo$substrateI4.symbol) || ((_chainInfo$evmInfo4 = chainInfo.evmInfo) === null || _chainInfo$evmInfo4 === void 0 ? void 0 : _chainInfo$evmInfo4.symbol) || '';
70
+ const from = autoFormatAddress(transferItem.from);
71
+ const to = autoFormatAddress(transferItem.to);
72
+ return {
73
+ address,
74
+ origin: 'subscan',
75
+ time: transferItem.block_timestamp * 1000,
76
+ chainType,
77
+ from,
78
+ fromName: transferItem.from_account_display.display,
79
+ direction: address === from ? TransactionDirection.SEND : TransactionDirection.RECEIVED,
80
+ blockNumber: transferItem.block_num,
81
+ blockHash: '',
82
+ chain: chainInfo.slug,
83
+ type: ExtrinsicType.TRANSFER_BALANCE,
84
+ to,
85
+ toName: transferItem.to_account_display.display,
86
+ extrinsicHash: transferItem.hash,
87
+ amount: {
88
+ value: transferItem.amount,
89
+ decimals: 0,
90
+ symbol: transferItem.asset_symbol
91
+ },
92
+ fee: {
93
+ value: transferItem.fee,
94
+ decimals: nativeDecimals,
95
+ symbol: nativeSymbol
96
+ },
97
+ status: transferItem.success ? ExtrinsicStatus.SUCCESS : ExtrinsicStatus.FAIL,
98
+ nonce: transferItem.nonce
99
+ };
100
+ }