@subwallet/extension-base 1.0.2-2 → 1.0.3-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 (151) hide show
  1. package/background/KoniTypes.d.ts +56 -40
  2. package/background/KoniTypes.js +11 -9
  3. package/background/errors/TransactionError.js +25 -1
  4. package/background/types.d.ts +10 -5
  5. package/cjs/background/KoniTypes.js +11 -9
  6. package/cjs/background/errors/TransactionError.js +24 -0
  7. package/cjs/constants/index.js +8 -26
  8. package/cjs/koni/api/dotsama/balance.js +49 -224
  9. package/cjs/koni/api/dotsama/transfer.js +34 -39
  10. package/cjs/koni/api/nft/acala_nft/index.js +7 -7
  11. package/cjs/koni/api/nft/bit.country/index.js +7 -6
  12. package/cjs/koni/api/nft/evm_nft/index.js +8 -3
  13. package/cjs/koni/api/nft/index.js +3 -6
  14. package/cjs/koni/api/nft/karura_nft/index.js +7 -6
  15. package/cjs/koni/api/nft/rmrk_nft/index.js +11 -1
  16. package/cjs/koni/api/nft/statemine_nft/index.js +7 -6
  17. package/cjs/koni/api/nft/unique_nft/index.js +5 -1
  18. package/cjs/koni/api/nft/wasm_nft/index.js +170 -111
  19. package/cjs/koni/api/nft/wasm_nft/utils.js +11 -7
  20. package/cjs/koni/api/staking/bonding/amplitude.js +13 -9
  21. package/cjs/koni/api/staking/bonding/astar.js +15 -13
  22. package/cjs/koni/api/staking/bonding/index.js +22 -10
  23. package/cjs/koni/api/staking/bonding/paraChain.js +85 -2
  24. package/cjs/koni/api/staking/bonding/relayChain.js +122 -16
  25. package/cjs/koni/api/staking/bonding/utils.js +27 -8
  26. package/cjs/koni/api/tokens/wasm/index.js +5 -4
  27. package/cjs/koni/api/tokens/wasm/utils.js +63 -0
  28. package/cjs/koni/api/xcm/polkadotXcm.js +1 -1
  29. package/cjs/koni/api/xcm/utils.js +18 -13
  30. package/cjs/koni/api/xcm/xTokens.js +1 -1
  31. package/cjs/koni/api/xcm/xcmPallet.js +9 -6
  32. package/cjs/koni/background/cron.js +171 -61
  33. package/cjs/koni/background/handlers/Extension.js +391 -207
  34. package/cjs/koni/background/handlers/State.js +49 -34
  35. package/cjs/koni/background/handlers/Tabs.js +50 -17
  36. package/cjs/koni/background/subscription.js +53 -28
  37. package/cjs/packageInfo.js +1 -1
  38. package/cjs/services/base/types.js +20 -0
  39. package/cjs/services/chain-service/handler/SubstrateChainHandler.js +13 -8
  40. package/cjs/services/chain-service/index.js +73 -49
  41. package/cjs/services/event-service/index.js +5 -1
  42. package/cjs/services/event-service/types.js +11 -1
  43. package/cjs/services/history-service/index.js +101 -50
  44. package/cjs/services/history-service/subsquid-multi-chain-history.js +13 -10
  45. package/cjs/services/keyring-service/index.js +11 -13
  46. package/cjs/services/migration-service/scripts/MigrateImportedToken.js +2 -1
  47. package/cjs/services/price-service/coingecko.js +0 -1
  48. package/cjs/services/price-service/index.js +71 -24
  49. package/cjs/services/request-service/handler/AuthRequestHandler.js +13 -7
  50. package/cjs/services/request-service/handler/EvmRequestHandler.js +8 -12
  51. package/cjs/services/request-service/index.js +14 -5
  52. package/cjs/services/storage-service/DatabaseService.js +66 -34
  53. package/cjs/services/storage-service/db-stores/Nft.js +7 -15
  54. package/cjs/services/storage-service/db-stores/Transaction.js +6 -10
  55. package/cjs/services/transaction-service/event-parser/index.js +20 -48
  56. package/cjs/services/transaction-service/index.js +104 -48
  57. package/cjs/services/transaction-service/utils.js +10 -8
  58. package/cjs/utils/address.js +10 -1
  59. package/cjs/utils/index.js +9 -15
  60. package/cjs/utils/promise.js +26 -0
  61. package/constants/index.d.ts +7 -13
  62. package/constants/index.js +7 -13
  63. package/koni/api/dotsama/balance.d.ts +0 -1
  64. package/koni/api/dotsama/balance.js +22 -197
  65. package/koni/api/dotsama/transfer.js +11 -16
  66. package/koni/api/nft/acala_nft/index.js +7 -7
  67. package/koni/api/nft/bit.country/index.js +7 -6
  68. package/koni/api/nft/evm_nft/index.js +7 -3
  69. package/koni/api/nft/index.d.ts +1 -2
  70. package/koni/api/nft/index.js +3 -6
  71. package/koni/api/nft/karura_nft/index.js +7 -6
  72. package/koni/api/nft/nft.d.ts +1 -0
  73. package/koni/api/nft/rmrk_nft/index.js +11 -1
  74. package/koni/api/nft/statemine_nft/index.js +7 -6
  75. package/koni/api/nft/unique_nft/index.js +5 -1
  76. package/koni/api/nft/wasm_nft/index.d.ts +0 -2
  77. package/koni/api/nft/wasm_nft/index.js +168 -109
  78. package/koni/api/nft/wasm_nft/utils.d.ts +7 -5
  79. package/koni/api/nft/wasm_nft/utils.js +7 -5
  80. package/koni/api/staking/bonding/amplitude.d.ts +0 -1
  81. package/koni/api/staking/bonding/amplitude.js +15 -10
  82. package/koni/api/staking/bonding/astar.js +8 -6
  83. package/koni/api/staking/bonding/index.d.ts +4 -1
  84. package/koni/api/staking/bonding/index.js +23 -13
  85. package/koni/api/staking/bonding/paraChain.d.ts +3 -0
  86. package/koni/api/staking/bonding/paraChain.js +86 -5
  87. package/koni/api/staking/bonding/relayChain.d.ts +5 -1
  88. package/koni/api/staking/bonding/relayChain.js +121 -18
  89. package/koni/api/staking/bonding/utils.d.ts +3 -2
  90. package/koni/api/staking/bonding/utils.js +27 -9
  91. package/koni/api/tokens/wasm/index.js +5 -4
  92. package/koni/api/tokens/wasm/utils.d.ts +6 -0
  93. package/koni/api/tokens/wasm/utils.js +54 -0
  94. package/koni/api/xcm/polkadotXcm.js +2 -2
  95. package/koni/api/xcm/utils.d.ts +5 -6
  96. package/koni/api/xcm/utils.js +15 -10
  97. package/koni/api/xcm/xTokens.js +2 -2
  98. package/koni/api/xcm/xcmPallet.js +10 -9
  99. package/koni/background/cron.d.ts +6 -1
  100. package/koni/background/cron.js +172 -62
  101. package/koni/background/handlers/Extension.d.ts +9 -3
  102. package/koni/background/handlers/Extension.js +306 -126
  103. package/koni/background/handlers/State.d.ts +5 -6
  104. package/koni/background/handlers/State.js +51 -34
  105. package/koni/background/handlers/Tabs.js +50 -17
  106. package/koni/background/subscription.d.ts +2 -0
  107. package/koni/background/subscription.js +51 -29
  108. package/package.json +29 -14
  109. package/packageInfo.js +1 -1
  110. package/services/base/types.d.ts +34 -0
  111. package/services/base/types.js +15 -0
  112. package/services/chain-service/handler/SubstrateChainHandler.js +14 -9
  113. package/services/chain-service/helper/psp22_abi.json +1041 -881
  114. package/services/chain-service/helper/psp34_abi.json +2963 -1807
  115. package/services/chain-service/index.d.ts +5 -2
  116. package/services/chain-service/index.js +68 -45
  117. package/services/chain-service/types.d.ts +1 -0
  118. package/services/event-service/index.js +5 -1
  119. package/services/event-service/types.d.ts +5 -9
  120. package/services/event-service/types.js +4 -1
  121. package/services/history-service/index.d.ts +28 -7
  122. package/services/history-service/index.js +101 -50
  123. package/services/history-service/subsquid-multi-chain-history.js +16 -12
  124. package/services/keyring-service/index.d.ts +4 -2
  125. package/services/keyring-service/index.js +11 -13
  126. package/services/migration-service/scripts/MigrateImportedToken.js +2 -1
  127. package/services/price-service/coingecko.js +0 -1
  128. package/services/price-service/index.d.ts +22 -1
  129. package/services/price-service/index.js +71 -24
  130. package/services/request-service/handler/AuthRequestHandler.d.ts +3 -1
  131. package/services/request-service/handler/AuthRequestHandler.js +13 -7
  132. package/services/request-service/handler/EvmRequestHandler.js +8 -12
  133. package/services/request-service/index.d.ts +3 -1
  134. package/services/request-service/index.js +14 -5
  135. package/services/storage-service/DatabaseService.d.ts +2 -0
  136. package/services/storage-service/DatabaseService.js +66 -34
  137. package/services/storage-service/db-stores/Nft.d.ts +2 -2
  138. package/services/storage-service/db-stores/Nft.js +7 -14
  139. package/services/storage-service/db-stores/Transaction.d.ts +2 -0
  140. package/services/storage-service/db-stores/Transaction.js +6 -10
  141. package/services/transaction-service/event-parser/index.js +21 -49
  142. package/services/transaction-service/index.d.ts +2 -0
  143. package/services/transaction-service/index.js +86 -32
  144. package/services/transaction-service/types.d.ts +2 -0
  145. package/services/transaction-service/utils.js +10 -8
  146. package/utils/address.d.ts +3 -0
  147. package/utils/address.js +8 -1
  148. package/utils/index.d.ts +2 -2
  149. package/utils/index.js +7 -13
  150. package/utils/promise.d.ts +6 -0
  151. package/utils/promise.js +20 -0
@@ -19,7 +19,6 @@ export declare class ChainService {
19
19
  private store;
20
20
  private assetSettingSubject;
21
21
  private logger;
22
- private refreshChainStateTimeout;
23
22
  constructor(dbService: DatabaseService, eventService: EventService);
24
23
  getXcmRefMap(): Record<string, _AssetRef>;
25
24
  getEvmApi(slug: string): _EvmApi;
@@ -92,8 +91,10 @@ export declare class ChainService {
92
91
  refreshEvmApi(slug: string): void;
93
92
  stopAllChainApis(): Promise<void[]>;
94
93
  resumeAllChainApis(): Promise<void[]>;
94
+ private refreshChainStateTimeout;
95
+ private refreshChainStateTimes;
95
96
  private refreshChainStateInterval;
96
- private updateApiMapStatus;
97
+ updateApiMapStatus(): Promise<void>;
97
98
  initAssetSettings(): Promise<void>;
98
99
  setAssetSettings(assetSettings: Record<string, AssetSetting>, emitEvent?: boolean): void;
99
100
  getStoreAssetSettings(): Promise<Record<string, AssetSetting>>;
@@ -101,4 +102,6 @@ export declare class ChainService {
101
102
  updateAssetSetting(assetSlug: string, assetSetting: AssetSetting): Promise<boolean | undefined>;
102
103
  updateAssetSettingByChain(chainSlug: string, visible: boolean): Promise<void>;
103
104
  subscribeAssetSettings(): BehaviorSubject<Record<string, AssetSetting>>;
105
+ getChainLogoMap(): Promise<Record<string, string>>;
106
+ getAssetLogoMap(): Promise<Record<string, string>>;
104
107
  }
@@ -1,9 +1,8 @@
1
1
  // Copyright 2019-2022 @subwallet/extension-base authors & contributors
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
- import { AssetRefMap, ChainAssetMap, ChainInfoMap, MultiChainAssetMap } from '@subwallet/chain-list';
4
+ import { AssetLogoMap, AssetRefMap, ChainAssetMap, ChainInfoMap, ChainLogoMap, MultiChainAssetMap } from '@subwallet/chain-list';
5
5
  import { _AssetRefPath, _AssetType, _ChainStatus, _SubstrateChainType } from '@subwallet/chain-list/types';
6
- import { CRON_GET_API_MAP_STATUS } from '@subwallet/extension-base/constants';
7
6
  import { _DEFAULT_ACTIVE_CHAINS } from '@subwallet/extension-base/services/chain-service/constants';
8
7
  import { EvmChainHandler } from '@subwallet/extension-base/services/chain-service/handler/EvmChainHandler';
9
8
  import { SubstrateChainHandler } from '@subwallet/extension-base/services/chain-service/handler/SubstrateChainHandler';
@@ -44,7 +43,7 @@ export class ChainService {
44
43
  this.multiChainAssetMapSubject.next(MultiChainAssetMap);
45
44
  this.xcmRefMapSubject.next(this.getXcmRefMap());
46
45
  this.logger = createLogger('chain-service');
47
- this.refreshChainStateInterval(3000);
46
+ this.refreshChainStateInterval(3000, 6);
48
47
  }
49
48
 
50
49
  // Getter
@@ -150,7 +149,8 @@ export class ChainService {
150
149
  priceId: '',
151
150
  slug: '',
152
151
  symbol: '',
153
- hasValue: true
152
+ hasValue: true,
153
+ icon: ''
154
154
  };
155
155
  for (const assetInfo of Object.values(this.getAssetRegistry())) {
156
156
  if (assetInfo.assetType === _AssetType.NATIVE && assetInfo.originChain === chainSlug) {
@@ -277,7 +277,7 @@ export class ChainService {
277
277
  this.dbService.removeFromChainStore([slug]).catch(console.error);
278
278
  this.updateChainSubscription();
279
279
  this.lockChainInfoMap = false;
280
- this.eventService.emit('chain.remove', slug);
280
+ this.eventService.emit('chain.updateState', slug);
281
281
  return true;
282
282
  }
283
283
  resetChainInfoMap(excludedChains) {
@@ -343,7 +343,7 @@ export class ChainService {
343
343
  this.dbService.removeFromAssetStore(targetAssets).catch(e => this.logger.error(e));
344
344
  this.assetRegistrySubject.next(assetRegistry);
345
345
  targetAssets.forEach(assetSlug => {
346
- this.eventService.emit('asset.remove', assetSlug);
346
+ this.eventService.emit('asset.updateState', assetSlug);
347
347
  });
348
348
  }
349
349
 
@@ -407,14 +407,14 @@ export class ChainService {
407
407
  this.lockChainInfoMap = true;
408
408
  chainStateMap[chainSlug].active = true;
409
409
  this.initApiForChain(chainInfo);
410
- this.refreshChainStateInterval(1000);
410
+ this.refreshChainStateInterval(3000, 6);
411
411
  this.dbService.updateChainStore({
412
412
  ...chainInfo,
413
413
  active: true,
414
414
  currentProvider: chainStateMap[chainSlug].currentProvider
415
415
  }).catch(console.error);
416
416
  this.lockChainInfoMap = false;
417
- this.eventService.emit('chain.enable', chainSlug);
417
+ this.eventService.emit('chain.updateState', chainSlug);
418
418
  return true;
419
419
  }
420
420
  enableChain(chainSlug) {
@@ -449,7 +449,7 @@ export class ChainService {
449
449
  }).catch(console.error);
450
450
  this.updateChainStateMapSubscription();
451
451
  this.lockChainInfoMap = false;
452
- this.eventService.emit('chain.disable', chainSlug);
452
+ this.eventService.emit('chain.updateState', chainSlug);
453
453
  return true;
454
454
  }
455
455
  checkExistedPredefinedChain(genesisHash, evmChainId) {
@@ -547,7 +547,8 @@ export class ChainService {
547
547
  evmInfo: storedChainInfo.evmInfo,
548
548
  substrateInfo: storedChainInfo.substrateInfo,
549
549
  isTestnet: storedChainInfo.isTestnet,
550
- chainStatus: storedChainInfo.chainStatus
550
+ chainStatus: storedChainInfo.chainStatus,
551
+ icon: storedChainInfo.icon
551
552
  };
552
553
  this.dataMap.chainStateMap[storedSlug] = {
553
554
  currentProvider: storedChainInfo.currentProvider,
@@ -672,7 +673,7 @@ export class ChainService {
672
673
  active: targetChainState.active,
673
674
  currentProvider: targetChainState.currentProvider
674
675
  }).then(() => {
675
- this.eventService.emit('chain.update', chainSlug);
676
+ this.eventService.emit('chain.updateState', chainSlug);
676
677
  }).catch(e => this.logger.error(e));
677
678
  }
678
679
  insertChain(params) {
@@ -718,7 +719,8 @@ export class ChainService {
718
719
  substrateInfo,
719
720
  evmInfo,
720
721
  isTestnet: false,
721
- chainStatus: _ChainStatus.ACTIVE
722
+ chainStatus: _ChainStatus.ACTIVE,
723
+ icon: '' // Todo: Allow update with custom chain
722
724
  };
723
725
 
724
726
  // insert new chainInfo
@@ -746,7 +748,8 @@ export class ChainService {
746
748
  priceId: params.chainEditInfo.priceId || null,
747
749
  slug: '',
748
750
  symbol: params.chainEditInfo.symbol,
749
- hasValue: true
751
+ hasValue: true,
752
+ icon: ''
750
753
  });
751
754
 
752
755
  // update subscription
@@ -961,21 +964,23 @@ export class ChainService {
961
964
  }
962
965
  async validateCustomToken(data) {
963
966
  const assetRegistry = this.getSmartContractTokens();
964
- let isExist = false;
967
+ let existedToken;
965
968
  for (const token of Object.values(assetRegistry)) {
966
969
  var _token$metadata2;
967
970
  const contractAddress = token === null || token === void 0 ? void 0 : (_token$metadata2 = token.metadata) === null || _token$metadata2 === void 0 ? void 0 : _token$metadata2.contractAddress;
968
971
  if (_isEqualContractAddress(contractAddress, data.contractAddress) && token.assetType === data.type && token.originChain === data.originChain) {
969
- isExist = true;
972
+ existedToken = token;
970
973
  break;
971
974
  }
972
975
  }
973
- if (isExist) {
976
+ if (existedToken) {
977
+ var _existedToken;
974
978
  return {
975
- decimals: -1,
976
- name: '',
977
- symbol: '',
978
- isExist,
979
+ decimals: existedToken.decimals || 0,
980
+ name: existedToken.name,
981
+ symbol: existedToken.symbol,
982
+ isExist: !!existedToken,
983
+ existedSlug: (_existedToken = existedToken) === null || _existedToken === void 0 ? void 0 : _existedToken.slug,
979
984
  contractError: false
980
985
  };
981
986
  }
@@ -989,7 +994,7 @@ export class ChainService {
989
994
  name,
990
995
  decimals,
991
996
  symbol,
992
- isExist,
997
+ isExist: !!existedToken,
993
998
  contractError
994
999
  };
995
1000
  }
@@ -1039,19 +1044,26 @@ export class ChainService {
1039
1044
 
1040
1045
  return this.substrateChainHandler.resumeAllApis();
1041
1046
  }
1042
-
1043
- // Interval update api status
1044
- refreshChainStateInterval(delay = 0) {
1047
+ refreshChainStateTimeout = undefined;
1048
+ refreshChainStateTimes = 0;
1049
+ refreshChainStateInterval(delay = 0, times) {
1045
1050
  clearTimeout(this.refreshChainStateTimeout);
1046
1051
  setTimeout(() => {
1047
- this.updateApiMapStatus();
1052
+ if (times) {
1053
+ this.refreshChainStateTimes = times;
1054
+ }
1055
+ this.refreshChainStateTimes -= 1;
1056
+ if (this.refreshChainStateTimes < 0) {
1057
+ return;
1058
+ }
1059
+ this.updateApiMapStatus().catch(console.error);
1048
1060
  this.refreshChainStateTimeout = setTimeout(() => {
1049
- this.updateApiMapStatus();
1050
- this.refreshChainStateInterval();
1051
- }, CRON_GET_API_MAP_STATUS);
1061
+ this.updateApiMapStatus().catch(console.error);
1062
+ this.refreshChainStateInterval(0);
1063
+ }, 3000);
1052
1064
  }, delay);
1053
1065
  }
1054
- updateApiMapStatus() {
1066
+ async updateApiMapStatus() {
1055
1067
  const substrateApiMap = this.getSubstrateApiMap();
1056
1068
  const evmApiMap = this.getEvmApiMap();
1057
1069
  const chainStateMap = this.getChainStateMap();
@@ -1062,24 +1074,30 @@ export class ChainService {
1062
1074
  update = true;
1063
1075
  }
1064
1076
  }
1065
- Object.entries(chainStateMap).forEach(([chain, chainState]) => {
1066
- if (chainState.active) {
1067
- if (substrateApiMap[chain]) {
1068
- const api = substrateApiMap[chain];
1069
- if (api) {
1070
- updateState(chainState, _ChainConnectionStatus.CONNECTED);
1071
- return;
1072
- }
1073
- } else if (evmApiMap[chain]) {
1074
- const api = evmApiMap[chain];
1075
- if (api) {
1076
- updateState(chainState, _ChainConnectionStatus.CONNECTED);
1077
- return;
1077
+ const promiseList = Object.entries(chainStateMap).map(async ([chain, chainState]) => {
1078
+ try {
1079
+ if (chainState.active) {
1080
+ if (substrateApiMap[chain]) {
1081
+ const api = substrateApiMap[chain];
1082
+ if (api.isApiConnected) {
1083
+ updateState(chainState, _ChainConnectionStatus.CONNECTED);
1084
+ return;
1085
+ }
1086
+ } else if (evmApiMap[chain]) {
1087
+ var _api$api;
1088
+ const api = evmApiMap[chain];
1089
+ if (await (api === null || api === void 0 ? void 0 : (_api$api = api.api) === null || _api$api === void 0 ? void 0 : _api$api.eth.net.isListening())) {
1090
+ updateState(chainState, _ChainConnectionStatus.CONNECTED);
1091
+ return;
1092
+ }
1078
1093
  }
1079
1094
  }
1095
+ updateState(chainState, _ChainConnectionStatus.DISCONNECTED);
1096
+ } catch (e) {
1097
+ updateState(chainState, _ChainConnectionStatus.DISCONNECTED);
1080
1098
  }
1081
- updateState(chainState, _ChainConnectionStatus.DISCONNECTED);
1082
1099
  });
1100
+ await Promise.all(promiseList);
1083
1101
  if (update) {
1084
1102
  console.log('Update chain connection state');
1085
1103
  this.chainStateMapSubject.next(chainStateMap);
@@ -1105,7 +1123,6 @@ export class ChainService {
1105
1123
  this.setAssetSettings(assetSettings, false);
1106
1124
  }
1107
1125
  this.eventService.emit('asset.ready', true);
1108
- console.log('Done init asset settings');
1109
1126
  }
1110
1127
  setAssetSettings(assetSettings, emitEvent = true) {
1111
1128
  const updateAssets = [];
@@ -1119,7 +1136,7 @@ export class ChainService {
1119
1136
  }
1120
1137
  this.assetSettingSubject.next(assetSettings);
1121
1138
  updateAssets.forEach(slug => {
1122
- this.eventService.emit(assetSettings[slug].visible ? 'asset.enable' : 'asset.disable', slug);
1139
+ this.eventService.emit('asset.updateState', slug);
1123
1140
  });
1124
1141
  this.store.set('AssetSetting', assetSettings);
1125
1142
  }
@@ -1168,4 +1185,10 @@ export class ChainService {
1168
1185
  subscribeAssetSettings() {
1169
1186
  return this.assetSettingSubject;
1170
1187
  }
1188
+ async getChainLogoMap() {
1189
+ return Promise.resolve(ChainLogoMap);
1190
+ }
1191
+ async getAssetLogoMap() {
1192
+ return Promise.resolve(AssetLogoMap);
1193
+ }
1171
1194
  }
@@ -104,6 +104,7 @@ export interface _SmartContractTokenInfo {
104
104
  }
105
105
  export interface _ValidateCustomAssetResponse extends _SmartContractTokenInfo {
106
106
  isExist: boolean;
107
+ existedSlug?: string;
107
108
  }
108
109
  export declare const _FUNGIBLE_CONTRACT_STANDARDS: _AssetType[];
109
110
  export declare const _NFT_CONTRACT_STANDARDS: _AssetType[];
@@ -34,7 +34,11 @@ export class EventService extends EventEmitter {
34
34
  }, this.lazyTime);
35
35
  }
36
36
  emitLazy() {
37
- this.lazyEmitter.emit('lazy', this.pendingEvents, this.pendingEvents.map(e => e.type));
37
+ try {
38
+ this.lazyEmitter.emit('lazy', this.pendingEvents, this.pendingEvents.map(e => e.type));
39
+ } catch (e) {
40
+ console.error('Get error in some listener of lazy event', e);
41
+ }
38
42
  this.pendingEvents = [];
39
43
  this.timeoutId = null;
40
44
  }
@@ -9,20 +9,16 @@ export interface EventRegistry {
9
9
  'account.remove': [string];
10
10
  'chain.ready': [boolean];
11
11
  'chain.add': [string];
12
- 'chain.update': [string];
13
- 'chain.disable': [string];
14
- 'chain.enable': [string];
15
- 'chain.remove': [string];
12
+ 'chain.updateState': [string];
16
13
  'asset.ready': [boolean];
17
- 'asset.add': [string];
18
- 'asset.update': [string];
19
- 'asset.enable': [string];
20
- 'asset.disable': [string];
21
- 'asset.remove': [string];
14
+ 'asset.updateState': [string];
22
15
  'transaction.done': [SWTransaction];
23
16
  'transaction.failed': [SWTransaction | undefined];
17
+ 'transaction.submitStaking': [string];
18
+ 'transaction.transferNft': [SWTransaction | undefined];
24
19
  }
25
20
  export declare type EventType = keyof EventRegistry;
21
+ export declare const COMMON_RELOAD_EVENTS: EventType[];
26
22
  export interface EventItem<T extends EventType> {
27
23
  type: T;
28
24
  data: EventRegistry[T];
@@ -1 +1,4 @@
1
- export {};
1
+ // Copyright 2019-2022 @subwallet/extension-base
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ export const COMMON_RELOAD_EVENTS = ['account.updateCurrent', 'asset.updateState', 'account.add', 'chain.updateState', 'account.remove', 'chain.add'];
@@ -1,24 +1,45 @@
1
1
  import { TransactionHistoryItem } from '@subwallet/extension-base/background/KoniTypes';
2
+ import { CronServiceInterface, PersistDataServiceInterface, ServiceStatus, StoppableServiceInterface } from '@subwallet/extension-base/services/base/types';
2
3
  import { ChainService } from '@subwallet/extension-base/services/chain-service';
3
4
  import { EventService } from '@subwallet/extension-base/services/event-service';
5
+ import { KeyringService } from '@subwallet/extension-base/services/keyring-service';
4
6
  import DatabaseService from '@subwallet/extension-base/services/storage-service/DatabaseService';
5
7
  import { BehaviorSubject } from 'rxjs';
6
- export declare class HistoryService {
8
+ export declare class HistoryService implements StoppableServiceInterface, PersistDataServiceInterface, CronServiceInterface {
7
9
  private dbService;
8
10
  private chainService;
9
11
  private eventService;
12
+ private keyringService;
10
13
  private historySubject;
11
- constructor(dbService: DatabaseService, chainService: ChainService, eventService: EventService);
14
+ constructor(dbService: DatabaseService, chainService: ChainService, eventService: EventService, keyringService: KeyringService);
12
15
  private fetchPromise;
13
- private nextFetch;
16
+ private interval;
14
17
  private fetchAndLoadHistories;
15
- fetchHistories(addresses: string[]): Promise<TransactionHistoryItem<import("@subwallet/extension-base/background/KoniTypes").ExtrinsicType.TRANSFER_BALANCE>[]>;
16
- invalidCache(): void;
17
- refreshHistoryInterval(): void;
18
18
  getHistories(): Promise<TransactionHistoryItem<import("@subwallet/extension-base/background/KoniTypes").ExtrinsicType.TRANSFER_BALANCE>[]>;
19
19
  getHistorySubject(): Promise<BehaviorSubject<TransactionHistoryItem<import("@subwallet/extension-base/background/KoniTypes").ExtrinsicType.TRANSFER_BALANCE>[]>>;
20
- insertHistories(historyItems: TransactionHistoryItem[]): Promise<void>;
21
20
  updateHistories(chain: string, extrinsicHash: string, updateData: Partial<TransactionHistoryItem>): Promise<void>;
21
+ updateHistoryByExtrinsicHash(extrinsicHash: string, updateData: Partial<TransactionHistoryItem>): Promise<void>;
22
+ insertHistories(historyItems: TransactionHistoryItem[]): Promise<void>;
22
23
  addHistoryItems(historyItems: TransactionHistoryItem[]): Promise<void>;
23
24
  removeHistoryByAddress(address: string): Promise<void>;
25
+ status: ServiceStatus;
26
+ loadData(): Promise<void>;
27
+ persistData(): Promise<void>;
28
+ startCron(): Promise<void>;
29
+ stopCron(): Promise<void>;
30
+ startPromiseHandler: {
31
+ resolve: (value: void) => void;
32
+ reject: (reason?: unknown) => void;
33
+ promise: Promise<void>;
34
+ };
35
+ init(): Promise<void>;
36
+ start(): Promise<void>;
37
+ waitForStarted(): Promise<void>;
38
+ stopPromiseHandler: {
39
+ resolve: (value: void) => void;
40
+ reject: (reason?: unknown) => void;
41
+ promise: Promise<void>;
42
+ };
43
+ stop(): Promise<void>;
44
+ waitForStopped(): Promise<void>;
24
45
  }
@@ -2,35 +2,22 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
4
  import { CRON_REFRESH_HISTORY_INTERVAL } from '@subwallet/extension-base/constants';
5
- import { quickFormatAddressToCompare } from '@subwallet/extension-base/utils/address';
5
+ import { ServiceStatus } from '@subwallet/extension-base/services/base/types';
6
+ import { createPromiseHandler } from '@subwallet/extension-base/utils/promise';
6
7
  import { keyring } from '@subwallet/ui-keyring';
7
- import { accounts } from '@subwallet/ui-keyring/observable/accounts';
8
8
  import { BehaviorSubject } from 'rxjs';
9
9
  import { fetchMultiChainHistories } from "./subsquid-multi-chain-history.js";
10
10
  export class HistoryService {
11
11
  historySubject = new BehaviorSubject([]);
12
- constructor(dbService, chainService, eventService) {
12
+ constructor(dbService, chainService, eventService, keyringService) {
13
13
  this.dbService = dbService;
14
14
  this.chainService = chainService;
15
15
  this.eventService = eventService;
16
- // Load history from database
17
- this.dbService.getHistories().then(histories => {
18
- this.historySubject.next(histories);
19
- }).catch(console.error);
20
-
21
- // Wait for keyring and chain ready and start
22
- Promise.all([this.eventService.waitKeyringReady, this.eventService.waitChainReady]).then(() => {
23
- this.getHistories().catch(console.log);
24
- this.eventService.on('account.add', () => {
25
- this.refreshHistoryInterval();
26
- });
27
- this.eventService.on('account.remove', address => {
28
- this.removeHistoryByAddress(address).catch(console.error);
29
- });
30
- }).catch(console.error);
16
+ this.keyringService = keyringService;
17
+ this.init().catch(console.error);
31
18
  }
32
19
  fetchPromise = null;
33
- nextFetch = undefined;
20
+ interval = undefined;
34
21
  async fetchAndLoadHistories(addresses) {
35
22
  if (!addresses || addresses.length === 0) {
36
23
  return [];
@@ -41,7 +28,7 @@ export class HistoryService {
41
28
  const historyRecords = await fetchMultiChainHistories(addresses, chainMap);
42
29
 
43
30
  // Fill additional info
44
- const accountMap = Object.entries(accounts.subject.value).reduce((map, [address, account]) => {
31
+ const accountMap = Object.entries(this.keyringService.accounts).reduce((map, [address, account]) => {
45
32
  map[address.toLowerCase()] = account.json.meta.name || address;
46
33
  return map;
47
34
  }, {});
@@ -50,44 +37,24 @@ export class HistoryService {
50
37
  record.fromName = accountMap[(_record$from = record.from) === null || _record$from === void 0 ? void 0 : _record$from.toLowerCase()];
51
38
  record.toName = accountMap[(_record$to = record.to) === null || _record$to === void 0 ? void 0 : _record$to.toLowerCase()];
52
39
  });
53
- this.dbService.upsertHistory(historyRecords).catch(console.error);
40
+ await this.addHistoryItems(historyRecords);
54
41
  return historyRecords;
55
42
  }
56
- async fetchHistories(addresses) {
57
- if (!this.fetchPromise) {
58
- // Fetch another histories data data indexer and merge it with stored in database
59
- this.fetchPromise = this.fetchAndLoadHistories(addresses);
60
- }
61
- return this.fetchPromise;
62
- }
63
- invalidCache() {
64
- this.fetchPromise = null;
65
- }
66
- refreshHistoryInterval() {
67
- clearTimeout(this.nextFetch);
68
- this.invalidCache();
69
- this.getHistories().catch(console.error);
70
- this.nextFetch = setTimeout(() => {
71
- this.refreshHistoryInterval();
72
- }, CRON_REFRESH_HISTORY_INTERVAL);
73
- }
74
43
  async getHistories() {
75
44
  const addressList = keyring.getAccounts().map(a => a.address);
76
- const currentHistories = this.historySubject.value;
77
- if (!this.fetchPromise || currentHistories.length === 0) {
78
- const historyRecords = await this.fetchHistories(addressList);
79
- this.historySubject.next(historyRecords);
45
+ if (!this.fetchPromise) {
46
+ this.fetchPromise = (async () => {
47
+ await this.fetchAndLoadHistories(addressList);
48
+ const histories = await this.dbService.getHistories();
49
+ this.historySubject.next(histories);
50
+ })();
80
51
  }
81
- return this.historySubject.getValue();
52
+ return Promise.resolve(this.historySubject.getValue());
82
53
  }
83
54
  async getHistorySubject() {
84
55
  await this.getHistories();
85
56
  return this.historySubject;
86
57
  }
87
- async insertHistories(historyItems) {
88
- await this.dbService.upsertHistory(historyItems);
89
- this.historySubject.next(await this.dbService.getHistories());
90
- }
91
58
  async updateHistories(chain, extrinsicHash, updateData) {
92
59
  const existedRecords = await this.dbService.getHistories({
93
60
  chain,
@@ -101,14 +68,29 @@ export class HistoryService {
101
68
  });
102
69
  await this.addHistoryItems(updatedRecords);
103
70
  }
71
+ async updateHistoryByExtrinsicHash(extrinsicHash, updateData) {
72
+ await this.dbService.updateHistoryByNewExtrinsicHash(extrinsicHash, updateData);
73
+ this.historySubject.next(await this.dbService.getHistories());
74
+ }
75
+
76
+ // Insert history without check override origin 'app'
77
+ async insertHistories(historyItems) {
78
+ await this.dbService.upsertHistory(historyItems);
79
+ this.historySubject.next(await this.dbService.getHistories());
80
+ }
81
+
82
+ // Insert history with check override origin 'app'
104
83
  async addHistoryItems(historyItems) {
105
84
  // Prevent override record with original is 'app'
106
85
  const appRecords = this.historySubject.value.filter(item => item.origin === 'app');
107
86
  const excludeKeys = appRecords.map(item => {
108
- return `${item.chain}-${quickFormatAddressToCompare(item.address) || ''}-${item.extrinsicHash}`;
87
+ return `${item.chain}-${item.extrinsicHash}`;
109
88
  });
110
89
  const updateRecords = historyItems.filter(item => {
111
- const key = `${item.chain}-${quickFormatAddressToCompare(item.address) || ''}-${item.extrinsicHash}`;
90
+ const key = `${item.chain}-${item.extrinsicHash}`;
91
+
92
+ // !excludeKeys.includes(key) && console.log('Cancel update', key);
93
+
112
94
  return item.origin === 'app' || !excludeKeys.includes(key);
113
95
  });
114
96
  await this.dbService.upsertHistory(updateRecords);
@@ -118,4 +100,73 @@ export class HistoryService {
118
100
  await this.dbService.stores.transaction.removeAllByAddress(address);
119
101
  this.historySubject.next(await this.dbService.getHistories());
120
102
  }
103
+ status = ServiceStatus.NOT_INITIALIZED;
104
+ async loadData() {
105
+ const histories = await this.dbService.getHistories();
106
+ this.historySubject.next(histories);
107
+ }
108
+ async persistData() {
109
+ await this.dbService.upsertHistory(this.historySubject.value);
110
+ }
111
+ async startCron() {
112
+ await this.getHistories();
113
+ this.interval = setInterval(() => {
114
+ this.getHistories().catch(console.error);
115
+ }, CRON_REFRESH_HISTORY_INTERVAL);
116
+ }
117
+ stopCron() {
118
+ clearTimeout(this.interval);
119
+ this.fetchPromise = null;
120
+ return Promise.resolve();
121
+ }
122
+ startPromiseHandler = createPromiseHandler();
123
+ async init() {
124
+ this.status = ServiceStatus.INITIALIZING;
125
+ await this.loadData();
126
+ Promise.all([this.eventService.waitKeyringReady, this.eventService.waitChainReady]).then(() => {
127
+ this.getHistories().catch(console.log);
128
+ this.eventService.on('account.add', () => {
129
+ (async () => {
130
+ await this.stopCron();
131
+ await this.startCron();
132
+ })().catch(console.error);
133
+ });
134
+ this.eventService.on('account.remove', address => {
135
+ this.removeHistoryByAddress(address).catch(console.error);
136
+ });
137
+ }).catch(console.error);
138
+ this.status = ServiceStatus.INITIALIZED;
139
+ }
140
+ async start() {
141
+ try {
142
+ console.debug('Start history service');
143
+ this.startPromiseHandler = createPromiseHandler();
144
+ this.status = ServiceStatus.STARTING;
145
+ await this.startCron();
146
+ this.status = ServiceStatus.STARTED;
147
+ this.startPromiseHandler.resolve();
148
+ } catch (e) {
149
+ this.startPromiseHandler.reject(e);
150
+ }
151
+ }
152
+ waitForStarted() {
153
+ return this.startPromiseHandler.promise;
154
+ }
155
+ stopPromiseHandler = createPromiseHandler();
156
+ async stop() {
157
+ console.debug('Stop history service');
158
+ try {
159
+ this.stopPromiseHandler = createPromiseHandler();
160
+ this.status = ServiceStatus.STOPPING;
161
+ await this.persistData();
162
+ await this.stopCron();
163
+ this.stopPromiseHandler.resolve();
164
+ this.status = ServiceStatus.STOPPED;
165
+ } catch (e) {
166
+ this.stopPromiseHandler.reject(e);
167
+ }
168
+ }
169
+ waitForStopped() {
170
+ return this.stopPromiseHandler.promise;
171
+ }
121
172
  }
@@ -57,11 +57,15 @@ function autoFormatAddress(address) {
57
57
  return '';
58
58
  }
59
59
  }
60
- function generateSignature({
61
- r,
62
- s,
63
- v
64
- }) {
60
+ function generateSignature(input) {
61
+ if (!input) {
62
+ return '';
63
+ }
64
+ const {
65
+ r,
66
+ s,
67
+ v
68
+ } = input;
65
69
  const rHex = r.startsWith('0x') ? r.slice(2) : r;
66
70
  const sHex = s.startsWith('0x') ? s.slice(2) : s;
67
71
  const vHex = parseInt(v).toString(16);
@@ -107,7 +111,7 @@ export function parseSubsquidTransactionData(address, type, historyItem, chainIn
107
111
  const transaction = data.call.data.args.transaction.value;
108
112
  to = autoFormatAddress(parsedArgs.to);
109
113
  from = autoFormatAddress(parsedArgs.from);
110
- extrinsicHash = parsedArgs.transactionHash;
114
+ extrinsicHash = parsedArgs.transactionHash || extrinsic.hash;
111
115
  amount = transaction.value || '0';
112
116
  fee = (parseInt(transaction.gasPrice) * parseInt(transaction.gasLimit)).toString();
113
117
  signature = generateSignature(transaction.signature);
@@ -243,14 +247,14 @@ export async function fetchMultiChainHistories(addresses, chainMap, maxPage = 25
243
247
  console.warn(`Not found chain info for chain id: ${chainId}`);
244
248
  return;
245
249
  }
246
- try {
247
- usedAddresses.forEach(address => {
250
+ usedAddresses.forEach(address => {
251
+ try {
248
252
  const transactionData = parseSubsquidTransactionData(address, name, historyItem, chainInfo, parseData(args), parseData(_data));
249
253
  histories.push(transactionData);
250
- });
251
- } catch (e) {
252
- console.warn('Parse transaction data failed', e);
253
- }
254
+ } catch (e) {
255
+ console.warn('Parse transaction data failed', address, e);
256
+ }
257
+ });
254
258
  });
255
259
  return histories;
256
260
  }