@subwallet/extension-base 1.0.6-2 → 1.0.7-1

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 (66) hide show
  1. package/background/KoniTypes.d.ts +11 -5
  2. package/cjs/constants/index.js +1 -1
  3. package/cjs/koni/api/staking/bonding/amplitude.js +83 -0
  4. package/cjs/koni/api/staking/bonding/astar.js +104 -1
  5. package/cjs/koni/api/staking/bonding/index.js +35 -0
  6. package/cjs/koni/api/staking/bonding/paraChain.js +97 -0
  7. package/cjs/koni/api/staking/bonding/relayChain.js +191 -12
  8. package/cjs/koni/api/staking/index.js +11 -11
  9. package/cjs/koni/api/staking/paraChain.js +200 -130
  10. package/cjs/koni/api/staking/relayChain.js +66 -68
  11. package/cjs/koni/api/staking/subsquidStaking.js +6 -11
  12. package/cjs/koni/background/cron.js +0 -25
  13. package/cjs/koni/background/handlers/State.js +18 -19
  14. package/cjs/koni/background/handlers/Tabs.js +68 -19
  15. package/cjs/koni/background/subscription.js +57 -12
  16. package/cjs/packageInfo.js +1 -1
  17. package/cjs/services/chain-service/utils.js +6 -1
  18. package/cjs/services/migration-service/index.js +2 -2
  19. package/cjs/services/request-service/handler/EvmRequestHandler.js +23 -0
  20. package/cjs/services/request-service/index.js +5 -0
  21. package/cjs/services/storage-service/DatabaseService.js +7 -3
  22. package/cjs/services/storage-service/db-stores/ChainStakingMetadata.js +5 -0
  23. package/cjs/services/storage-service/db-stores/NominatorMetadata.js +4 -4
  24. package/cjs/services/transaction-service/index.js +6 -1
  25. package/constants/index.d.ts +1 -1
  26. package/constants/index.js +1 -1
  27. package/koni/api/staking/bonding/amplitude.d.ts +4 -0
  28. package/koni/api/staking/bonding/amplitude.js +81 -0
  29. package/koni/api/staking/bonding/astar.d.ts +4 -0
  30. package/koni/api/staking/bonding/astar.js +102 -1
  31. package/koni/api/staking/bonding/index.d.ts +1 -0
  32. package/koni/api/staking/bonding/index.js +38 -4
  33. package/koni/api/staking/bonding/paraChain.d.ts +4 -0
  34. package/koni/api/staking/bonding/paraChain.js +95 -0
  35. package/koni/api/staking/bonding/relayChain.d.ts +5 -0
  36. package/koni/api/staking/bonding/relayChain.js +185 -10
  37. package/koni/api/staking/index.d.ts +4 -4
  38. package/koni/api/staking/index.js +11 -11
  39. package/koni/api/staking/paraChain.d.ts +5 -5
  40. package/koni/api/staking/paraChain.js +201 -131
  41. package/koni/api/staking/relayChain.d.ts +4 -4
  42. package/koni/api/staking/relayChain.js +66 -67
  43. package/koni/api/staking/subsquidStaking.d.ts +1 -1
  44. package/koni/api/staking/subsquidStaking.js +6 -11
  45. package/koni/background/cron.js +1 -26
  46. package/koni/background/handlers/State.d.ts +2 -2
  47. package/koni/background/handlers/State.js +18 -19
  48. package/koni/background/handlers/Tabs.js +68 -19
  49. package/koni/background/subscription.d.ts +2 -1
  50. package/koni/background/subscription.js +58 -13
  51. package/package.json +6 -6
  52. package/packageInfo.js +1 -1
  53. package/services/chain-service/types.d.ts +3 -0
  54. package/services/chain-service/utils.js +6 -1
  55. package/services/migration-service/index.js +2 -2
  56. package/services/request-service/handler/EvmRequestHandler.d.ts +1 -0
  57. package/services/request-service/handler/EvmRequestHandler.js +21 -0
  58. package/services/request-service/index.d.ts +1 -0
  59. package/services/request-service/index.js +3 -0
  60. package/services/storage-service/DatabaseService.d.ts +2 -2
  61. package/services/storage-service/DatabaseService.js +7 -3
  62. package/services/storage-service/db-stores/ChainStakingMetadata.d.ts +1 -0
  63. package/services/storage-service/db-stores/ChainStakingMetadata.js +3 -0
  64. package/services/storage-service/db-stores/NominatorMetadata.d.ts +2 -2
  65. package/services/storage-service/db-stores/NominatorMetadata.js +4 -4
  66. package/services/transaction-service/index.js +6 -1
@@ -32,9 +32,8 @@ const getSubsquidQuery = (account, chain) => {
32
32
  }
33
33
  }`;
34
34
  };
35
- const getSubsquidStaking = async (accounts, chain, chainInfoMap) => {
35
+ const getSubsquidStaking = async (accounts, chain, chainInfoMap, callback) => {
36
36
  try {
37
- const result = [];
38
37
  await Promise.all(accounts.map(async account => {
39
38
  if (_isChainEvmCompatible(chainInfoMap[chain]) && isEthereumAddress(account) || !_isChainEvmCompatible(chainInfoMap[chain]) && !isEthereumAddress(account)) {
40
39
  const parsedAccount = reformatAddress(account, _getChainSubstrateAddressPrefix(chainInfoMap[chain]));
@@ -70,17 +69,15 @@ const getSubsquidStaking = async (accounts, chain, chainInfoMap) => {
70
69
  }
71
70
  }
72
71
  if (stakingRewardItem.totalReward && parseFloat(stakingRewardItem.totalReward) > 0) {
73
- result.push(stakingRewardItem);
72
+ callback(stakingRewardItem);
74
73
  }
75
74
  }
76
75
  }));
77
- return result;
78
76
  } catch (e) {
79
- return [];
77
+ console.debug(e);
80
78
  }
81
79
  };
82
- export const getAllSubsquidStaking = async (accounts, chainInfoMap) => {
83
- let rewardList = [];
80
+ export const getAllSubsquidStaking = async (accounts, chainInfoMap, callback) => {
84
81
  const filteredNetworks = [];
85
82
  Object.values(chainInfoMap).forEach(network => {
86
83
  if (INDEXER_SUPPORTED_STAKING_CHAINS.includes(network.slug)) {
@@ -89,11 +86,9 @@ export const getAllSubsquidStaking = async (accounts, chainInfoMap) => {
89
86
  });
90
87
  try {
91
88
  await Promise.all(filteredNetworks.map(async network => {
92
- const rewardItems = await getSubsquidStaking(accounts, network, chainInfoMap);
93
- rewardList = rewardList.concat(rewardItems);
89
+ await getSubsquidStaking(accounts, network, chainInfoMap, callback);
94
90
  }));
95
91
  } catch (e) {
96
- return rewardList;
92
+ console.debug(e);
97
93
  }
98
- return rewardList;
99
94
  };
@@ -1,7 +1,7 @@
1
1
  // Copyright 2019-2022 @subwallet/extension-koni authors & contributors
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
- import { CRON_AUTO_RECOVER_DOTSAMA_INTERVAL, CRON_GET_API_MAP_STATUS, CRON_REFRESH_CHAIN_NOMINATOR_METADATA, CRON_REFRESH_CHAIN_STAKING_METADATA, CRON_REFRESH_NFT_INTERVAL, CRON_REFRESH_STAKING_REWARD_FAST_INTERVAL, CRON_REFRESH_STAKING_REWARD_INTERVAL } from '@subwallet/extension-base/constants';
4
+ import { CRON_AUTO_RECOVER_DOTSAMA_INTERVAL, CRON_GET_API_MAP_STATUS, CRON_REFRESH_CHAIN_STAKING_METADATA, CRON_REFRESH_NFT_INTERVAL, CRON_REFRESH_STAKING_REWARD_FAST_INTERVAL, CRON_REFRESH_STAKING_REWARD_INTERVAL } from '@subwallet/extension-base/constants';
5
5
  import { _isChainSupportEvmNft, _isChainSupportNativeNft, _isChainSupportSubstrateStaking, _isChainSupportWasmNft } from '@subwallet/extension-base/services/chain-service/utils';
6
6
  import { waitTimeout } from '@subwallet/extension-base/utils';
7
7
  import { Subject } from 'rxjs';
@@ -49,26 +49,6 @@ export class KoniCron {
49
49
  delete this.cronMap[key];
50
50
  });
51
51
  };
52
-
53
- // init = () => {
54
- // const currentAccountInfo = this.state.keyringService.currentAccount;
55
- //
56
- // if (!currentAccountInfo?.address) {
57
- // return;
58
- // }
59
- //
60
- // if (Object.keys(this.state.getSubstrateApiMap()).length !== 0 || Object.keys(this.state.getEvmApiMap()).length !== 0) {
61
- // this.refreshNft(currentAccountInfo.address, this.state.getApiMap(), this.state.getSmartContractNfts(), this.state.getActiveChainInfoMap());
62
- // this.updateApiMapStatus();
63
- // this.refreshStakingReward(currentAccountInfo.address);
64
- // this.refreshStakingRewardFastInterval(currentAccountInfo.address);
65
- // // this.updateChainStakingMetadata(this.state.getChainInfoMap(), this.state.getChainStateMap(), this.state.getSubstrateApiMap());
66
- // this.updateNominatorMetadata(currentAccountInfo.address, this.state.getChainInfoMap(), this.state.getChainStateMap(), this.state.getSubstrateApiMap());
67
- // } else {
68
- // this.setStakingRewardReady();
69
- // }
70
- // };
71
-
72
52
  start = () => {
73
53
  if (this.status === 'running') {
74
54
  return;
@@ -109,7 +89,6 @@ export class KoniCron {
109
89
  (commonReload || needUpdateStaking || stakingSubmitted) && this.resetStakingReward();
110
90
  (commonReload || needUpdateStaking || stakingSubmitted) && this.removeCron('refreshStakingReward');
111
91
  (commonReload || needUpdateStaking || stakingSubmitted) && this.removeCron('refreshPoolingStakingReward');
112
- (commonReload || needUpdateStaking || stakingSubmitted) && this.removeCron('updateNominatorMetadata');
113
92
  needUpdateStaking && this.removeCron('updateChainStakingMetadata');
114
93
 
115
94
  // Chains
@@ -122,7 +101,6 @@ export class KoniCron {
122
101
  chainUpdated && this.addCron('recoverApiMap', this.recoverApiMap, CRON_AUTO_RECOVER_DOTSAMA_INTERVAL, false);
123
102
  (commonReload || needUpdateStaking || stakingSubmitted) && this.addCron('refreshStakingReward', this.refreshStakingReward(address), CRON_REFRESH_STAKING_REWARD_INTERVAL);
124
103
  (commonReload || needUpdateStaking || stakingSubmitted) && this.addCron('refreshPoolingStakingReward', this.refreshStakingRewardFastInterval(address), CRON_REFRESH_STAKING_REWARD_FAST_INTERVAL);
125
- (commonReload || needUpdateStaking || stakingSubmitted) && this.addCron('updateNominatorMetadata', this.updateNominatorMetadata(address, serviceInfo.chainInfoMap, serviceInfo.chainStateMap, serviceInfo.chainApiMap.substrate), CRON_REFRESH_CHAIN_NOMINATOR_METADATA);
126
104
  needUpdateStaking && this.addCron('updateChainStakingMetadata', this.updateChainStakingMetadata(serviceInfo.chainInfoMap, serviceInfo.chainStateMap, serviceInfo.chainApiMap.substrate), CRON_REFRESH_CHAIN_STAKING_METADATA);
127
105
  } else {
128
106
  this.setStakingRewardReady();
@@ -140,7 +118,6 @@ export class KoniCron {
140
118
  this.addCron('refreshStakingReward', this.refreshStakingReward(currentAccountInfo.address), CRON_REFRESH_STAKING_REWARD_INTERVAL);
141
119
  this.addCron('refreshPoolingStakingReward', this.refreshStakingRewardFastInterval(currentAccountInfo.address), CRON_REFRESH_STAKING_REWARD_FAST_INTERVAL);
142
120
  this.addCron('updateChainStakingMetadata', this.updateChainStakingMetadata(this.state.getChainInfoMap(), this.state.getChainStateMap(), this.state.getSubstrateApiMap()), CRON_REFRESH_CHAIN_STAKING_METADATA);
143
- this.addCron('updateNominatorMetadata', this.updateNominatorMetadata(currentAccountInfo.address, this.state.getChainInfoMap(), this.state.getChainStateMap(), this.state.getSubstrateApiMap()), CRON_REFRESH_CHAIN_NOMINATOR_METADATA);
144
121
  } else {
145
122
  this.setStakingRewardReady();
146
123
  }
@@ -235,10 +212,8 @@ export class KoniCron {
235
212
  this.resetStakingReward();
236
213
  this.removeCron('refreshStakingReward');
237
214
  this.removeCron('refreshPoolingStakingReward');
238
- this.removeCron('updateNominatorMetadata');
239
215
  this.addCron('refreshStakingReward', this.refreshStakingReward(address), CRON_REFRESH_STAKING_REWARD_INTERVAL);
240
216
  this.addCron('refreshPoolingStakingReward', this.refreshStakingRewardFastInterval(address), CRON_REFRESH_STAKING_REWARD_FAST_INTERVAL);
241
- this.addCron('updateNominatorMetadata', this.updateNominatorMetadata(address, this.state.getChainInfoMap(), this.state.getChainStateMap(), this.state.getSubstrateApiMap()), CRON_REFRESH_CHAIN_NOMINATOR_METADATA);
242
217
  await waitTimeout(1800);
243
218
  return true;
244
219
  }
@@ -101,7 +101,7 @@ export default class KoniState {
101
101
  subscribeNominatorMetadata(): Subject<NominatorMetadata[]>;
102
102
  ensureUrlAuthorizedV2(url: string): Promise<boolean>;
103
103
  setStakingItem(networkKey: string, item: StakingItem): void;
104
- updateChainStakingMetadata(item: ChainStakingMetadata): void;
104
+ updateChainStakingMetadata(item: ChainStakingMetadata, changes?: Record<string, unknown>): void;
105
105
  updateStakingNominatorMetadata(item: NominatorMetadata): void;
106
106
  setNftCollection(network: string, data: NftCollection, callback?: (data: NftCollection) => void): void;
107
107
  getNftCollection(): import("dexie").PromiseExtended<NftCollection[]>;
@@ -113,7 +113,7 @@ export default class KoniState {
113
113
  getNft(): Promise<NftJson | undefined>;
114
114
  subscribeNft(): Subject<NftJson>;
115
115
  resetStakingReward(): void;
116
- updateStakingReward(stakingRewardData: StakingRewardItem[], type: 'slowInterval' | 'fastInterval', callback?: (stakingRewardData: StakingRewardJson) => void): void;
116
+ updateStakingReward(stakingRewardData: StakingRewardItem, callback?: (stakingRewardData: StakingRewardJson) => void): void;
117
117
  updateStakingRewardReady(ready: boolean): void;
118
118
  getAccountRefMap(callback: (refMap: Record<string, Array<string>>) => void): void;
119
119
  addAccountRef(addresses: string[], callback: () => void): void;
@@ -69,8 +69,7 @@ export default class KoniState {
69
69
  stakingRewardSubject = new Subject();
70
70
  stakingRewardState = {
71
71
  ready: false,
72
- slowInterval: [],
73
- fastInterval: []
72
+ data: {}
74
73
  };
75
74
  lazyMap = {};
76
75
  ready = false;
@@ -193,18 +192,24 @@ export default class KoniState {
193
192
  async init() {
194
193
  await this.chainService.init();
195
194
  await this.migrationService.run();
196
- this.startSubscription();
197
195
  this.eventService.emit('chain.ready', true);
198
196
  this.onReady();
199
197
  this.onAccountAdd();
200
198
  this.onAccountRemove();
199
+ await this.startSubscription();
201
200
  }
202
- startSubscription() {
201
+ async startSubscription() {
202
+ await this.eventService.waitKeyringReady;
203
203
  this.dbService.subscribeChainStakingMetadata([], data => {
204
204
  this.chainStakingMetadataSubject.next(data);
205
205
  });
206
- this.dbService.subscribeNominatorMetadata(data => {
207
- this.stakingNominatorMetadataSubject.next(data);
206
+ let unsub;
207
+ this.keyringService.accountSubject.subscribe(accounts => {
208
+ // TODO: improve this
209
+ unsub && unsub.unsubscribe();
210
+ unsub = this.dbService.subscribeNominatorMetadata(Object.keys(accounts), data => {
211
+ this.stakingNominatorMetadataSubject.next(data);
212
+ });
208
213
  });
209
214
  }
210
215
  onReady() {
@@ -296,14 +301,6 @@ export default class KoniState {
296
301
  async getPooledStakingRecordsByAddress(addresses) {
297
302
  return this.dbService.getPooledStakings(addresses, this.activeChainSlugs);
298
303
  }
299
-
300
- // TODO: delete later
301
- // public async getStoredStaking (address: string) {
302
- // const items = await this.dbService.stores.staking.getDataByAddressAsObject(address);
303
- //
304
- // return items || {};
305
- // }
306
-
307
304
  subscribeStaking() {
308
305
  return this.stakingSubject;
309
306
  }
@@ -319,8 +316,8 @@ export default class KoniState {
319
316
  setStakingItem(networkKey, item) {
320
317
  this.dbService.updateStaking(networkKey, item.address, item).catch(e => this.logger.warn(e));
321
318
  }
322
- updateChainStakingMetadata(item) {
323
- this.dbService.updateChainStakingMetadata(item).catch(e => this.logger.warn(e));
319
+ updateChainStakingMetadata(item, changes) {
320
+ this.dbService.updateChainStakingMetadata(item, changes).catch(e => this.logger.warn(e));
324
321
  }
325
322
  updateStakingNominatorMetadata(item) {
326
323
  this.dbService.updateNominatorMetadata(item).catch(e => this.logger.warn(e));
@@ -373,12 +370,13 @@ export default class KoniState {
373
370
  return this.nftSubject;
374
371
  }
375
372
  resetStakingReward() {
376
- this.stakingRewardState.slowInterval = [];
373
+ this.stakingRewardState.data = {};
377
374
  this.stakingRewardSubject.next(this.stakingRewardState);
378
375
  }
379
- updateStakingReward(stakingRewardData, type, callback) {
376
+ updateStakingReward(stakingRewardData, callback) {
380
377
  this.stakingRewardState.ready = true;
381
- this.stakingRewardState[type] = stakingRewardData;
378
+ const key = `${stakingRewardData.chain}___${stakingRewardData.address}___${stakingRewardData.type}`;
379
+ this.stakingRewardState.data[key] = stakingRewardData;
382
380
  if (callback) {
383
381
  callback(this.stakingRewardState);
384
382
  }
@@ -1343,6 +1341,7 @@ export default class KoniState {
1343
1341
  await this.priceService.stop();
1344
1342
  }
1345
1343
  async wakeup() {
1344
+ await this.eventService.waitChainReady;
1346
1345
  await this.resumeAllNetworks();
1347
1346
  this.cron.start();
1348
1347
  this.subscription.start();
@@ -10,6 +10,7 @@ import RequestBytesSign from '@subwallet/extension-base/background/RequestBytesS
10
10
  import RequestExtrinsicSign from '@subwallet/extension-base/background/RequestExtrinsicSign';
11
11
  import { ALL_ACCOUNT_KEY, CRON_GET_API_MAP_STATUS } from '@subwallet/extension-base/constants';
12
12
  import { PHISHING_PAGE_REDIRECT } from '@subwallet/extension-base/defaults';
13
+ import { _CHAIN_VALIDATION_ERROR } from '@subwallet/extension-base/services/chain-service/handler/types';
13
14
  import { _generateCustomProviderKey } from '@subwallet/extension-base/services/chain-service/utils';
14
15
  import { DEFAULT_CHAIN_PATROL_ENABLE } from '@subwallet/extension-base/services/setting-service/constants';
15
16
  import { canDerive } from '@subwallet/extension-base/utils';
@@ -365,7 +366,7 @@ export default class KoniTabs {
365
366
  async addEvmToken(id, url, {
366
367
  params
367
368
  }) {
368
- var _input$type, _input$options, _input$options2;
369
+ var _input$type, _input$options, _input$options2, _input$options3, _input$options4, _input$options5;
369
370
  const input = params;
370
371
  const _tokenType = (input === null || input === void 0 ? void 0 : (_input$type = input.type) === null || _input$type === void 0 ? void 0 : _input$type.toLowerCase()) || '';
371
372
  if (_tokenType !== 'erc20' && _tokenType !== 'erc721') {
@@ -380,28 +381,42 @@ export default class KoniTabs {
380
381
  throw new EvmProviderError(EvmProviderErrorType.INTERNAL_ERROR, 'Current chain is not available');
381
382
  }
382
383
  const tokenType = _tokenType === 'erc20' ? _AssetType.ERC20 : _AssetType.ERC721;
383
- const validate = await this.#koniState.validateCustomAsset({
384
+ const tokenInfo = {
385
+ slug: '',
386
+ type: tokenType,
387
+ name: (input === null || input === void 0 ? void 0 : (_input$options3 = input.options) === null || _input$options3 === void 0 ? void 0 : _input$options3.symbol) || '',
388
+ contractAddress: input.options.address,
389
+ symbol: (input === null || input === void 0 ? void 0 : (_input$options4 = input.options) === null || _input$options4 === void 0 ? void 0 : _input$options4.symbol) || '',
390
+ decimals: (input === null || input === void 0 ? void 0 : (_input$options5 = input.options) === null || _input$options5 === void 0 ? void 0 : _input$options5.decimals) || 0,
391
+ originChain: chain,
392
+ contractError: false,
393
+ validated: false
394
+ };
395
+ this.#koniState.validateCustomAsset({
384
396
  type: tokenType,
385
397
  contractAddress: input.options.address,
386
398
  originChain: chain
399
+ }).then(validate => {
400
+ if (validate.contractError) {
401
+ tokenInfo.contractError = true;
402
+ } else {
403
+ tokenInfo.slug = validate === null || validate === void 0 ? void 0 : validate.existedSlug;
404
+ tokenInfo.name = validate.name;
405
+ tokenInfo.symbol = validate.symbol;
406
+ tokenInfo.decimals = validate.decimals;
407
+ }
408
+ }).catch(() => {
409
+ tokenInfo.contractError = true;
410
+ }).finally(() => {
411
+ tokenInfo.validated = true;
412
+ this.#koniState.requestService.updateConfirmation(id, 'addTokenRequest', tokenInfo);
387
413
  });
388
414
 
389
415
  // Below code is comment because we will handle exited token in the ui-view
390
416
  // if (validate.isExist) {
391
417
  // throw new EvmProviderError(EvmProviderErrorType.INTERNAL_ERROR, 'Current token is existed');
392
418
  // } else
393
- if (validate.contractError) {
394
- throw new EvmProviderError(EvmProviderErrorType.INVALID_PARAMS, 'Contract address is invalid');
395
- }
396
- const tokenInfo = {
397
- slug: validate === null || validate === void 0 ? void 0 : validate.existedSlug,
398
- type: tokenType,
399
- name: validate.name,
400
- contractAddress: input.options.address,
401
- symbol: validate.symbol,
402
- decimals: validate.decimals,
403
- originChain: chain
404
- };
419
+
405
420
  return await this.#koniState.addTokenConfirm(id, url, tokenInfo);
406
421
  }
407
422
  async addEvmChain(id, url, {
@@ -413,6 +428,10 @@ export default class KoniTabs {
413
428
  blockExplorerUrls,
414
429
  chainId,
415
430
  chainName,
431
+ nativeCurrency: {
432
+ decimals,
433
+ symbol
434
+ },
416
435
  rpcUrls
417
436
  } = input[0];
418
437
  if (chainId) {
@@ -463,12 +482,19 @@ export default class KoniTabs {
463
482
  throw new EvmProviderError(EvmProviderErrorType.INTERNAL_ERROR, 'Currently HTTP provider for EVM network');
464
483
  }
465
484
  const provider = filteredUrls[0];
466
- const chainInfo = await this.#koniState.validateCustomChain(provider);
467
- if (!chainInfo.success) {
468
- throw new EvmProviderError(EvmProviderErrorType.INVALID_PARAMS, 'Invalid provider');
469
- }
485
+ const chainInfo = {
486
+ existentialDeposit: '0',
487
+ genesisHash: '',
488
+ success: true,
489
+ addressPrefix: '',
490
+ evmChainId: chainIdNum,
491
+ decimals: decimals,
492
+ symbol: symbol,
493
+ paraId: null,
494
+ name: chainName
495
+ };
470
496
  const newProviderKey = _generateCustomProviderKey(0);
471
- return await this.#koniState.addNetworkConfirm(id, url, {
497
+ const networkData = {
472
498
  mode: 'insert',
473
499
  chainSpec: {
474
500
  evmChainId: chainInfo.evmChainId,
@@ -488,8 +514,31 @@ export default class KoniTabs {
488
514
  symbol: chainInfo.symbol,
489
515
  chainType: 'EVM',
490
516
  name: chainInfo.name
517
+ },
518
+ unconfirmed: true
519
+ };
520
+ this.#koniState.validateCustomChain(provider).then(res => {
521
+ if (!res.success) {
522
+ networkData.providerError = res.error;
523
+ } else {
524
+ networkData.chainSpec = {
525
+ evmChainId: res.evmChainId,
526
+ decimals: res.decimals,
527
+ existentialDeposit: res.existentialDeposit,
528
+ genesisHash: res.genesisHash,
529
+ paraId: res.paraId,
530
+ addressPrefix: res.addressPrefix ? parseInt(res.addressPrefix) : 0
531
+ };
532
+ networkData.chainEditInfo.symbol = res.symbol;
533
+ networkData.chainEditInfo.name = res.name;
491
534
  }
535
+ }).catch(() => {
536
+ networkData.providerError = _CHAIN_VALIDATION_ERROR.NONE;
537
+ }).finally(() => {
538
+ networkData.unconfirmed = false;
539
+ this.#koniState.requestService.updateConfirmation(id, 'addNetworkRequest', networkData);
492
540
  });
541
+ return await this.#koniState.addNetworkConfirm(id, url, networkData);
493
542
  } else {
494
543
  throw new EvmProviderError(EvmProviderErrorType.INVALID_PARAMS, 'Invalid provider');
495
544
  }
@@ -3,7 +3,7 @@ import { ChainStakingMetadata } from '@subwallet/extension-base/background/KoniT
3
3
  import { _ChainState, _EvmApi, _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types';
4
4
  import DatabaseService from '@subwallet/extension-base/services/storage-service/DatabaseService';
5
5
  import KoniState from './handlers/State';
6
- declare type SubscriptionName = 'balance' | 'crowdloan' | 'stakingOnChain';
6
+ declare type SubscriptionName = 'balance' | 'crowdloan' | 'stakingOnChain' | 'essentialChainStakingMetadata';
7
7
  export declare class KoniSubscription {
8
8
  private eventHandler?;
9
9
  private subscriptionMap;
@@ -20,6 +20,7 @@ export declare class KoniSubscription {
20
20
  subscribeBalancesAndCrowdloans(address: string, chainInfoMap: Record<string, _ChainInfo>, chainStateMap: Record<string, _ChainState>, substrateApiMap: Record<string, _SubstrateApi>, web3ApiMap: Record<string, _EvmApi>, onlyRunOnFirstTime?: boolean): void;
21
21
  subscribeStakingOnChain(address: string, substrateApiMap: Record<string, _SubstrateApi>, onlyRunOnFirstTime?: boolean): void;
22
22
  initStakingOnChainSubscription(addresses: string[], substrateApiMap: Record<string, _SubstrateApi>, onlyRunOnFirstTime?: boolean): (() => void) | undefined;
23
+ initEssentialChainStakingMetadataSubscription(substrateApiMap: Record<string, _SubstrateApi>, onlyRunOnFirstTime?: boolean): (() => void) | undefined;
23
24
  initBalanceSubscription(addresses: string[], chainInfoMap: Record<string, _ChainInfo>, chainStateMap: Record<string, _ChainState>, substrateApiMap: Record<string, _SubstrateApi>, evmApiMap: Record<string, _EvmApi>, onlyRunOnFirstTime?: boolean): (() => void) | undefined;
24
25
  initCrowdloanSubscription(addresses: string[], substrateApiMap: Record<string, _SubstrateApi>, onlyRunOnFirstTime?: boolean): (() => void) | undefined;
25
26
  subscribeNft(address: string, substrateApiMap: Record<string, _SubstrateApi>, evmApiMap: Record<string, _EvmApi>, smartContractNfts: _ChainAsset[], chainInfoMap: Record<string, _ChainInfo>): void;
@@ -5,7 +5,7 @@ import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants';
5
5
  import { subscribeBalance } from '@subwallet/extension-base/koni/api/dotsama/balance';
6
6
  import { subscribeCrowdloan } from '@subwallet/extension-base/koni/api/dotsama/crowdloan';
7
7
  import { getNominationStakingRewardData, getPoolingStakingRewardData, stakingOnChainApi } from '@subwallet/extension-base/koni/api/staking';
8
- import { getChainStakingMetadata, getNominatorMetadata } from '@subwallet/extension-base/koni/api/staking/bonding';
8
+ import { getChainStakingMetadata, getNominatorMetadata, subscribeEssentialChainStakingMetadata } from '@subwallet/extension-base/koni/api/staking/bonding';
9
9
  import { getRelayChainPoolMemberMetadata } from '@subwallet/extension-base/koni/api/staking/bonding/relayChain';
10
10
  import { getAmplitudeUnclaimedStakingReward } from '@subwallet/extension-base/koni/api/staking/paraChain';
11
11
  import { nftHandler } from '@subwallet/extension-base/koni/background/handlers';
@@ -19,7 +19,8 @@ export class KoniSubscription {
19
19
  subscriptionMap = {
20
20
  crowdloan: undefined,
21
21
  balance: undefined,
22
- stakingOnChain: undefined
22
+ stakingOnChain: undefined,
23
+ essentialChainStakingMetadata: undefined
23
24
  };
24
25
  constructor(state, dbService) {
25
26
  this.dbService = dbService;
@@ -98,11 +99,38 @@ export class KoniSubscription {
98
99
  return;
99
100
  }
100
101
  this.updateSubscription('stakingOnChain', this.initStakingOnChainSubscription(addresses, substrateApiMap, onlyRunOnFirstTime));
102
+ this.updateSubscription('essentialChainStakingMetadata', this.initEssentialChainStakingMetadataSubscription(substrateApiMap, onlyRunOnFirstTime)); // TODO: might not need to re-subscribe on changing account
101
103
  }
104
+
102
105
  initStakingOnChainSubscription(addresses, substrateApiMap, onlyRunOnFirstTime) {
103
- const unsub = stakingOnChainApi(addresses, substrateApiMap, (networkKey, rs) => {
106
+ const stakingCallback = (networkKey, rs) => {
104
107
  this.state.setStakingItem(networkKey, rs);
105
- }, this.state.getActiveChainInfoMap());
108
+ };
109
+ const nominatorStateCallback = nominatorMetadata => {
110
+ this.state.updateStakingNominatorMetadata(nominatorMetadata);
111
+ };
112
+ const unsub = stakingOnChainApi(addresses, substrateApiMap, this.state.getActiveChainInfoMap(), stakingCallback, nominatorStateCallback);
113
+ if (onlyRunOnFirstTime) {
114
+ unsub && unsub();
115
+ return;
116
+ }
117
+ return () => {
118
+ unsub && unsub();
119
+ };
120
+ }
121
+ initEssentialChainStakingMetadataSubscription(substrateApiMap, onlyRunOnFirstTime) {
122
+ const unsub = subscribeEssentialChainStakingMetadata(substrateApiMap, this.state.getActiveChainInfoMap(), (networkKey, rs) => {
123
+ this.state.updateChainStakingMetadata(rs, {
124
+ era: rs.era,
125
+ minStake: rs.minStake,
126
+ maxValidatorPerNominator: rs.maxValidatorPerNominator,
127
+ // temporary fix for Astar, there's no limit for now
128
+ maxWithdrawalRequestPerValidator: rs.maxWithdrawalRequestPerValidator,
129
+ // by default
130
+ allowCancelUnstaking: rs.allowCancelUnstaking,
131
+ unstakingPeriod: rs.unstakingPeriod
132
+ });
133
+ });
106
134
  if (onlyRunOnFirstTime) {
107
135
  unsub && unsub();
108
136
  return;
@@ -168,8 +196,9 @@ export class KoniSubscription {
168
196
  targetNetworkMap[key] = network;
169
197
  }
170
198
  });
171
- const result = await getNominationStakingRewardData(addresses, targetNetworkMap);
172
- this.state.updateStakingReward(result, 'slowInterval');
199
+ await getNominationStakingRewardData(addresses, targetNetworkMap, rewardItem => {
200
+ this.state.updateStakingReward(rewardItem);
201
+ });
173
202
  }
174
203
  async subscribeStakingRewardFastInterval(address) {
175
204
  const addresses = this.state.getDecodedAddresses(address);
@@ -195,9 +224,10 @@ export class KoniSubscription {
195
224
  Object.keys(targetChainMap).forEach(key => {
196
225
  activeNetworks.push(key);
197
226
  });
198
- const [poolingStakingRewards, amplitudeUnclaimedStakingRewards] = await Promise.all([getPoolingStakingRewardData(pooledAddresses, targetChainMap, this.state.getSubstrateApiMap()), getAmplitudeUnclaimedStakingReward(this.state.getSubstrateApiMap(), addresses, chainInfoMap, activeNetworks)]);
199
- const result = [...poolingStakingRewards, ...amplitudeUnclaimedStakingRewards];
200
- this.state.updateStakingReward(result, 'fastInterval');
227
+ const updateState = result => {
228
+ this.state.updateStakingReward(result);
229
+ };
230
+ await Promise.all([getPoolingStakingRewardData(pooledAddresses, targetChainMap, this.state.getSubstrateApiMap(), updateState), getAmplitudeUnclaimedStakingReward(this.state.getSubstrateApiMap(), addresses, chainInfoMap, activeNetworks, updateState)]);
201
231
  }
202
232
  async fetchingStakingFromApi() {
203
233
  try {
@@ -221,16 +251,31 @@ export class KoniSubscription {
221
251
  if (Object.values(filteredChainInfoMap).length === 0) {
222
252
  return;
223
253
  }
254
+ const timeout = new Promise(resolve => {
255
+ const id = setTimeout(() => {
256
+ clearTimeout(id);
257
+ resolve(null);
258
+ }, 3000);
259
+ });
224
260
 
225
261
  // Fetch data from helper API
226
- const dataFromApi = await this.fetchingStakingFromApi();
262
+ const _dataFromApi = await Promise.race([this.fetchingStakingFromApi(), timeout]);
263
+ const dataFromApi = _dataFromApi;
227
264
  await Promise.all(Object.values(filteredChainInfoMap).map(async chainInfo => {
228
265
  // Use fetch API data if available
229
- if (dataFromApi[chainInfo.slug]) {
230
- this.state.updateChainStakingMetadata(dataFromApi[chainInfo.slug]);
266
+ if (dataFromApi && dataFromApi[chainInfo.slug]) {
267
+ this.state.updateChainStakingMetadata(dataFromApi[chainInfo.slug], {
268
+ expectedReturn: dataFromApi[chainInfo.slug].expectedReturn,
269
+ inflation: dataFromApi[chainInfo.slug].inflation,
270
+ nominatorCount: dataFromApi[chainInfo.slug].nominatorCount
271
+ });
231
272
  } else {
232
273
  const chainStakingMetadata = await getChainStakingMetadata(chainInfo, substrateApiMap[chainInfo.slug]);
233
- this.state.updateChainStakingMetadata(chainStakingMetadata);
274
+ this.state.updateChainStakingMetadata(chainStakingMetadata, {
275
+ expectedReturn: chainStakingMetadata.expectedReturn,
276
+ inflation: chainStakingMetadata.inflation,
277
+ nominatorCount: chainStakingMetadata.nominatorCount
278
+ });
234
279
  }
235
280
  }));
236
281
  }
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "./cjs/detectPackage.js"
18
18
  ],
19
19
  "type": "module",
20
- "version": "1.0.6-2",
20
+ "version": "1.0.7-1",
21
21
  "main": "./cjs/index.js",
22
22
  "module": "./index.js",
23
23
  "types": "./index.d.ts",
@@ -1697,11 +1697,11 @@
1697
1697
  "@sora-substrate/type-definitions": "^1.17.7",
1698
1698
  "@subsocial/types": "^0.6.8",
1699
1699
  "@substrate/connect": "^0.7.26",
1700
- "@subwallet/chain-list": "^0.1.8",
1701
- "@subwallet/extension-base": "^1.0.6-2",
1702
- "@subwallet/extension-chains": "^1.0.6-2",
1703
- "@subwallet/extension-dapp": "^1.0.6-2",
1704
- "@subwallet/extension-inject": "^1.0.6-2",
1700
+ "@subwallet/chain-list": "^0.1.9",
1701
+ "@subwallet/extension-base": "^1.0.7-1",
1702
+ "@subwallet/extension-chains": "^1.0.7-1",
1703
+ "@subwallet/extension-dapp": "^1.0.7-1",
1704
+ "@subwallet/extension-inject": "^1.0.7-1",
1705
1705
  "@subwallet/keyring": "^0.0.9",
1706
1706
  "@subwallet/ui-keyring": "^0.0.9",
1707
1707
  "@unique-nft/types": "^0.6.0-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.0.6-2'
10
+ version: '1.0.7-1'
11
11
  };
@@ -1,4 +1,5 @@
1
1
  import { _AssetRef, _AssetType, _ChainAsset, _ChainInfo } from '@subwallet/chain-list/types';
2
+ import { _CHAIN_VALIDATION_ERROR } from '@subwallet/extension-base/services/chain-service/handler/types';
2
3
  import Web3 from 'web3';
3
4
  import { ApiPromise } from '@polkadot/api';
4
5
  import { SubmittableExtrinsicFunction } from '@polkadot/api/promise/types';
@@ -88,6 +89,8 @@ export declare type _NetworkUpsertParams = {
88
89
  existentialDeposit: string;
89
90
  decimals: number;
90
91
  };
92
+ unconfirmed?: boolean;
93
+ providerError?: _CHAIN_VALIDATION_ERROR;
91
94
  };
92
95
  export declare const _CUSTOM_PREFIX = "custom-";
93
96
  export interface _ValidateCustomAssetRequest {
@@ -53,7 +53,12 @@ export function _isPureSubstrateChain(chainInfo) {
53
53
  }
54
54
  export function _getOriginChainOfAsset(assetSlug) {
55
55
  if (assetSlug.startsWith(_CUSTOM_PREFIX)) {
56
- return assetSlug.split('-')[1];
56
+ const arr = assetSlug.split('-').slice(1);
57
+ if (arr[0] === 'custom') {
58
+ const end = arr.findIndex(str => Object.values(_AssetType).includes(str));
59
+ return arr.slice(0, end).join('-');
60
+ }
61
+ return arr[0];
57
62
  }
58
63
  return assetSlug.split('-')[0];
59
64
  }
@@ -11,8 +11,8 @@ export default class MigrationService {
11
11
  async run() {
12
12
  const keys = Object.keys(MigrationScripts).sort((a, b) => a.localeCompare(b));
13
13
 
14
- // Await timeout 2s
15
- await new Promise(resolve => setTimeout(resolve, 2000));
14
+ // Await timeout 1s
15
+ await new Promise(resolve => setTimeout(resolve, 1000));
16
16
  for (let i = 0; i < keys.length; i++) {
17
17
  try {
18
18
  const JobClass = MigrationScripts[keys[i]];
@@ -11,6 +11,7 @@ export default class EvmRequestHandler {
11
11
  get numEvmRequests(): number;
12
12
  getConfirmationsQueueSubject(): BehaviorSubject<ConfirmationsQueue>;
13
13
  addConfirmation<CT extends ConfirmationType>(id: string, url: string, type: CT, payload: ConfirmationDefinitions[CT][0]['payload'], options?: ConfirmationsQueueItemOptions, validator?: (input: ConfirmationDefinitions[CT][1]) => Error | undefined): Promise<ConfirmationDefinitions[CT][1]>;
14
+ updateConfirmation<CT extends ConfirmationType>(id: string, type: CT, payload: ConfirmationDefinitions[CT][0]['payload'], options?: ConfirmationsQueueItemOptions, validator?: (input: ConfirmationDefinitions[CT][1]) => Error | undefined): void;
14
15
  private signMessage;
15
16
  configToTransaction(config: TransactionConfig): Transaction;
16
17
  private signTransaction;
@@ -72,6 +72,27 @@ export default class EvmRequestHandler {
72
72
  this.#requestService.updateIconV2();
73
73
  return promise;
74
74
  }
75
+ updateConfirmation(id, type, payload, options = {}, validator) {
76
+ const confirmations = this.confirmationsQueueSubject.getValue();
77
+ const confirmationType = confirmations[type];
78
+
79
+ // Check duplicate request
80
+ const exists = confirmationType[id];
81
+ if (!exists) {
82
+ throw new EvmProviderError(EvmProviderErrorType.INVALID_PARAMS, 'Request does not exist');
83
+ }
84
+ const payloadJson = JSON.stringify(payload);
85
+ confirmationType[id] = {
86
+ ...exists,
87
+ payload,
88
+ payloadJson,
89
+ ...options
90
+ };
91
+ if (validator) {
92
+ this.confirmationsPromiseMap[id].validator = validator;
93
+ }
94
+ this.confirmationsQueueSubject.next(confirmations);
95
+ }
75
96
  async signMessage(confirmation) {
76
97
  const {
77
98
  account,
@@ -51,6 +51,7 @@ export default class RequestService {
51
51
  signInternalTransaction(id: string, address: string, url: string, payload: SignerPayloadJSON): Promise<ResponseSigning>;
52
52
  addConfirmation<CT extends ConfirmationType>(id: string, url: string, type: CT, payload: ConfirmationDefinitions[CT][0]['payload'], options?: ConfirmationsQueueItemOptions, validator?: (input: ConfirmationDefinitions[CT][1]) => Error | undefined): Promise<ConfirmationDefinitions[CT][1]>;
53
53
  completeConfirmation(request: RequestConfirmationComplete): Promise<boolean>;
54
+ updateConfirmation<CT extends ConfirmationType>(id: string, type: CT, payload: ConfirmationDefinitions[CT][0]['payload'], options?: ConfirmationsQueueItemOptions, validator?: (input: ConfirmationDefinitions[CT][1]) => Error | undefined): void;
54
55
  get numRequests(): number;
55
56
  resetWallet(): void;
56
57
  }
@@ -154,6 +154,9 @@ export default class RequestService {
154
154
  async completeConfirmation(request) {
155
155
  return await this.#evmRequestHandler.completeConfirmation(request);
156
156
  }
157
+ updateConfirmation(id, type, payload, options = {}, validator) {
158
+ return this.#evmRequestHandler.updateConfirmation(id, type, payload, options, validator);
159
+ }
157
160
 
158
161
  // General methods
159
162
  get numRequests() {