@subwallet/extension-base 1.0.7-0 → 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 (55) hide show
  1. package/background/KoniTypes.d.ts +4 -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 +17 -19
  14. package/cjs/koni/background/subscription.js +57 -12
  15. package/cjs/packageInfo.js +1 -1
  16. package/cjs/services/chain-service/utils.js +6 -1
  17. package/cjs/services/storage-service/DatabaseService.js +7 -3
  18. package/cjs/services/storage-service/db-stores/ChainStakingMetadata.js +5 -0
  19. package/cjs/services/storage-service/db-stores/NominatorMetadata.js +4 -4
  20. package/cjs/services/transaction-service/index.js +6 -1
  21. package/constants/index.d.ts +1 -1
  22. package/constants/index.js +1 -1
  23. package/koni/api/staking/bonding/amplitude.d.ts +4 -0
  24. package/koni/api/staking/bonding/amplitude.js +81 -0
  25. package/koni/api/staking/bonding/astar.d.ts +4 -0
  26. package/koni/api/staking/bonding/astar.js +102 -1
  27. package/koni/api/staking/bonding/index.d.ts +1 -0
  28. package/koni/api/staking/bonding/index.js +38 -4
  29. package/koni/api/staking/bonding/paraChain.d.ts +4 -0
  30. package/koni/api/staking/bonding/paraChain.js +95 -0
  31. package/koni/api/staking/bonding/relayChain.d.ts +5 -0
  32. package/koni/api/staking/bonding/relayChain.js +185 -10
  33. package/koni/api/staking/index.d.ts +4 -4
  34. package/koni/api/staking/index.js +11 -11
  35. package/koni/api/staking/paraChain.d.ts +5 -5
  36. package/koni/api/staking/paraChain.js +201 -131
  37. package/koni/api/staking/relayChain.d.ts +4 -4
  38. package/koni/api/staking/relayChain.js +66 -67
  39. package/koni/api/staking/subsquidStaking.d.ts +1 -1
  40. package/koni/api/staking/subsquidStaking.js +6 -11
  41. package/koni/background/cron.js +1 -26
  42. package/koni/background/handlers/State.d.ts +2 -2
  43. package/koni/background/handlers/State.js +17 -19
  44. package/koni/background/subscription.d.ts +2 -1
  45. package/koni/background/subscription.js +58 -13
  46. package/package.json +5 -5
  47. package/packageInfo.js +1 -1
  48. package/services/chain-service/utils.js +6 -1
  49. package/services/storage-service/DatabaseService.d.ts +2 -2
  50. package/services/storage-service/DatabaseService.js +7 -3
  51. package/services/storage-service/db-stores/ChainStakingMetadata.d.ts +1 -0
  52. package/services/storage-service/db-stores/ChainStakingMetadata.js +3 -0
  53. package/services/storage-service/db-stores/NominatorMetadata.d.ts +2 -2
  54. package/services/storage-service/db-stores/NominatorMetadata.js +4 -4
  55. package/services/transaction-service/index.js +6 -1
@@ -1,98 +1,89 @@
1
1
  // Copyright 2019-2022 @subwallet/extension-koni authors & contributors
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
- import { APIItemState, StakingType } from '@subwallet/extension-base/background/KoniTypes';
4
+ import { APIItemState, StakingStatus, StakingType } from '@subwallet/extension-base/background/KoniTypes';
5
+ import { subscribeRelayChainNominatorMetadata, subscribeRelayChainPoolMemberMetadata } from '@subwallet/extension-base/koni/api/staking/bonding/relayChain';
5
6
  import { _getChainNativeTokenBasicInfo } from '@subwallet/extension-base/services/chain-service/utils';
6
7
  import { reformatAddress } from '@subwallet/extension-base/utils';
7
8
  import { BN } from '@polkadot/util';
8
9
  import { isEthereumAddress } from '@polkadot/util-crypto';
9
- export function getRelayStakingOnChain(substrateApi, useAddresses, chainInfoMap, chain, callback) {
10
+ export function getRelayStakingOnChain(substrateApi, useAddresses, chainInfoMap, chain, stakingCallback, nominatorStateCallback) {
10
11
  var _substrateApi$api$que;
11
12
  const {
12
13
  symbol
13
14
  } = _getChainNativeTokenBasicInfo(chainInfoMap[chain]);
14
- return (_substrateApi$api$que = substrateApi.api.query.staking) === null || _substrateApi$api$que === void 0 ? void 0 : _substrateApi$api$que.ledger.multi(useAddresses, ledgers => {
15
- let unit = '';
15
+ return (_substrateApi$api$que = substrateApi.api.query.staking) === null || _substrateApi$api$que === void 0 ? void 0 : _substrateApi$api$que.ledger.multi(useAddresses, async ledgers => {
16
16
  if (ledgers) {
17
- for (let i = 0; i < ledgers.length; i++) {
18
- const ledger = ledgers[i];
19
- const owner = reformatAddress(useAddresses[i], 42) || undefined;
20
- const data = ledger.toHuman();
21
- if (data && data.active) {
22
- const _totalBalance = data.total;
23
- const _activeBalance = data.active;
24
- let bnUnlockingBalance = new BN(0);
25
- data.unlocking.forEach(({
26
- value
27
- }) => {
28
- value = value.split(' ')[0];
29
- const _unlockingBalance = value.replaceAll(',', '');
30
- bnUnlockingBalance = bnUnlockingBalance.add(new BN(_unlockingBalance));
31
- });
32
- let amount = _totalBalance ? _totalBalance.split(' ')[0] : '';
33
- amount = amount.replaceAll(',', '');
34
- unit = _totalBalance ? _totalBalance.split(' ')[1] : '';
35
- const bnTotalBalance = new BN(amount);
36
- amount = _activeBalance ? _activeBalance.split(' ')[0] : '';
37
- amount = amount.replaceAll(',', '');
38
- unit = _activeBalance ? _activeBalance.split(' ')[1] : '';
39
- const bnActiveBalance = new BN(amount);
40
- const stakingItem = {
17
+ await Promise.all(ledgers.map(async (_ledger, i) => {
18
+ const owner = reformatAddress(useAddresses[i], 42);
19
+ const ledger = _ledger.toPrimitive();
20
+ if (ledger) {
21
+ const _totalBalance = ledger.total.toString();
22
+ const _activeBalance = ledger.active.toString();
23
+ const bnUnlockingBalance = new BN(_totalBalance).sub(new BN(_activeBalance));
24
+ stakingCallback(chain, {
41
25
  name: chainInfoMap[chain].name,
42
26
  chain: chain,
43
- balance: bnTotalBalance.toString(),
44
- activeBalance: bnActiveBalance.toString(),
27
+ balance: _totalBalance,
28
+ activeBalance: _activeBalance,
45
29
  unlockingBalance: bnUnlockingBalance.toString(),
46
30
  nativeToken: symbol,
47
- unit: unit || symbol,
31
+ unit: symbol,
48
32
  state: APIItemState.READY,
49
33
  type: StakingType.NOMINATED,
50
34
  address: owner
51
- };
52
- callback(chain, stakingItem);
35
+ });
36
+ const nominatorMetadata = await subscribeRelayChainNominatorMetadata(chainInfoMap[chain], owner, substrateApi, ledger);
37
+ nominatorStateCallback(nominatorMetadata);
53
38
  } else {
54
- const stakingItem = {
39
+ stakingCallback(chain, {
55
40
  name: chainInfoMap[chain].name,
56
41
  chain: chain,
57
42
  balance: '0',
58
43
  activeBalance: '0',
59
44
  unlockingBalance: '0',
60
45
  nativeToken: symbol,
61
- unit: unit || symbol,
46
+ unit: symbol,
62
47
  state: APIItemState.READY,
63
48
  type: StakingType.NOMINATED,
64
49
  address: owner
65
- };
66
- callback(chain, stakingItem);
50
+ });
51
+ nominatorStateCallback({
52
+ chain,
53
+ type: StakingType.NOMINATED,
54
+ status: StakingStatus.NOT_STAKING,
55
+ address: owner,
56
+ activeStake: '0',
57
+ nominations: [],
58
+ unstakings: []
59
+ });
67
60
  }
68
- }
61
+ }));
69
62
  }
70
63
  });
71
64
  }
72
- export function getRelayPoolingOnChain(parentApi, useAddresses, networks, chain, callback) {
73
- var _parentApi$api$query, _parentApi$api$query$;
65
+ export function getRelayPoolingOnChain(substrateApi, useAddresses, chainInfoMap, chain, stakingCallback, nominatorStateCallback) {
66
+ var _substrateApi$api$que2, _substrateApi$api$que3;
74
67
  const {
75
68
  symbol
76
- } = _getChainNativeTokenBasicInfo(networks[chain]);
77
- return (_parentApi$api$query = parentApi.api.query) === null || _parentApi$api$query === void 0 ? void 0 : (_parentApi$api$query$ = _parentApi$api$query.nominationPools) === null || _parentApi$api$query$ === void 0 ? void 0 : _parentApi$api$query$.poolMembers.multi(useAddresses, ledgers => {
69
+ } = _getChainNativeTokenBasicInfo(chainInfoMap[chain]);
70
+ return (_substrateApi$api$que2 = substrateApi.api.query) === null || _substrateApi$api$que2 === void 0 ? void 0 : (_substrateApi$api$que3 = _substrateApi$api$que2.nominationPools) === null || _substrateApi$api$que3 === void 0 ? void 0 : _substrateApi$api$que3.poolMembers.multi(useAddresses, async ledgers => {
78
71
  if (ledgers) {
79
- for (let i = 0; i < ledgers.length; i++) {
80
- const ledger = ledgers[i];
72
+ await Promise.all(ledgers.map(async (_poolMemberInfo, i) => {
73
+ const poolMemberInfo = _poolMemberInfo.toPrimitive();
81
74
  const owner = reformatAddress(useAddresses[i], 42);
82
- const data = ledger.toHuman();
83
- if (data !== null) {
84
- const bondedBalance = data.points;
85
- const unbondedBalance = data.unbondingEras;
75
+ if (poolMemberInfo) {
76
+ const bondedBalance = poolMemberInfo.points;
77
+ const unbondedBalance = poolMemberInfo.unbondingEras;
86
78
  let unlockingBalance = new BN(0);
87
- let totalBalance = new BN(0);
88
- Object.entries(unbondedBalance).forEach(([era, value]) => {
89
- const bnUnbondedBalance = new BN(value.replaceAll(',', ''));
79
+ const bnBondedBalance = new BN(bondedBalance.toString());
80
+ Object.entries(unbondedBalance).forEach(([, value]) => {
81
+ const bnUnbondedBalance = new BN(value.toString());
90
82
  unlockingBalance = unlockingBalance.add(bnUnbondedBalance);
91
83
  });
92
- const bnBondedBalance = new BN(bondedBalance.replaceAll(',', ''));
93
- totalBalance = totalBalance.add(bnBondedBalance).add(unlockingBalance);
94
- const stakingItem = {
95
- name: networks[chain].name,
84
+ const totalBalance = bnBondedBalance.add(unlockingBalance);
85
+ stakingCallback(chain, {
86
+ name: chainInfoMap[chain].name,
96
87
  chain: chain,
97
88
  balance: totalBalance.toString(),
98
89
  activeBalance: bnBondedBalance.toString(),
@@ -102,11 +93,12 @@ export function getRelayPoolingOnChain(parentApi, useAddresses, networks, chain,
102
93
  state: APIItemState.READY,
103
94
  type: StakingType.POOLED,
104
95
  address: owner
105
- };
106
- callback(chain, stakingItem);
96
+ });
97
+ const nominatorMetadata = await subscribeRelayChainPoolMemberMetadata(chainInfoMap[chain], owner, substrateApi, poolMemberInfo);
98
+ nominatorStateCallback(nominatorMetadata);
107
99
  } else {
108
- const stakingItem = {
109
- name: networks[chain].name,
100
+ stakingCallback(chain, {
101
+ name: chainInfoMap[chain].name,
110
102
  chain: chain,
111
103
  balance: '0',
112
104
  activeBalance: '0',
@@ -116,14 +108,23 @@ export function getRelayPoolingOnChain(parentApi, useAddresses, networks, chain,
116
108
  state: APIItemState.READY,
117
109
  type: StakingType.POOLED,
118
110
  address: owner
119
- };
120
- callback(chain, stakingItem);
111
+ });
112
+ nominatorStateCallback({
113
+ chain,
114
+ type: StakingType.POOLED,
115
+ address: owner,
116
+ status: StakingStatus.NOT_STAKING,
117
+ activeStake: '0',
118
+ nominations: [],
119
+ // can only join 1 pool at a time
120
+ unstakings: []
121
+ });
121
122
  }
122
- }
123
+ }));
123
124
  }
124
125
  });
125
126
  }
126
- export async function getNominationPoolReward(addresses, chainInfoMap, substrateApiMap) {
127
+ export async function getNominationPoolReward(addresses, chainInfoMap, substrateApiMap, callBack) {
127
128
  const targetNetworks = [];
128
129
  const validAddresses = [];
129
130
  Object.keys(chainInfoMap).forEach(key => {
@@ -134,7 +135,6 @@ export async function getNominationPoolReward(addresses, chainInfoMap, substrate
134
135
  validAddresses.push(address);
135
136
  }
136
137
  });
137
- const rewardList = [];
138
138
  try {
139
139
  await Promise.all(targetNetworks.map(async networkKey => {
140
140
  const substrateApi = await substrateApiMap[networkKey].isReady;
@@ -143,7 +143,7 @@ export async function getNominationPoolReward(addresses, chainInfoMap, substrate
143
143
  var _substrateApi$api$cal, _substrateApi$api$cal2;
144
144
  const _unclaimedReward = await ((_substrateApi$api$cal = substrateApi.api.call) === null || _substrateApi$api$cal === void 0 ? void 0 : (_substrateApi$api$cal2 = _substrateApi$api$cal.nominationPoolsApi) === null || _substrateApi$api$cal2 === void 0 ? void 0 : _substrateApi$api$cal2.pendingRewards(address));
145
145
  if (_unclaimedReward) {
146
- rewardList.push({
146
+ callBack({
147
147
  address: address,
148
148
  chain: networkKey,
149
149
  unclaimedReward: _unclaimedReward.toString(),
@@ -156,7 +156,6 @@ export async function getNominationPoolReward(addresses, chainInfoMap, substrate
156
156
  }
157
157
  }));
158
158
  } catch (e) {
159
- return rewardList;
159
+ console.debug(e);
160
160
  }
161
- return rewardList;
162
161
  }
@@ -1,3 +1,3 @@
1
1
  import { _ChainInfo } from '@subwallet/chain-list/types';
2
2
  import { StakingRewardItem } from '@subwallet/extension-base/background/KoniTypes';
3
- export declare const getAllSubsquidStaking: (accounts: string[], chainInfoMap: Record<string, _ChainInfo>) => Promise<StakingRewardItem[]>;
3
+ export declare const getAllSubsquidStaking: (accounts: string[], chainInfoMap: Record<string, _ChainInfo>, callback: (rewardItem: StakingRewardItem) => void) => Promise<void>;
@@ -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
  }
@@ -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.7-0",
20
+ "version": "1.0.7-1",
21
21
  "main": "./cjs/index.js",
22
22
  "module": "./index.js",
23
23
  "types": "./index.d.ts",
@@ -1698,10 +1698,10 @@
1698
1698
  "@subsocial/types": "^0.6.8",
1699
1699
  "@substrate/connect": "^0.7.26",
1700
1700
  "@subwallet/chain-list": "^0.1.9",
1701
- "@subwallet/extension-base": "^1.0.7-0",
1702
- "@subwallet/extension-chains": "^1.0.7-0",
1703
- "@subwallet/extension-dapp": "^1.0.7-0",
1704
- "@subwallet/extension-inject": "^1.0.7-0",
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.7-0'
10
+ version: '1.0.7-1'
11
11
  };
@@ -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
  }
@@ -38,7 +38,7 @@ export default class DatabaseService {
38
38
  getPooledStakings(addresses: string[], chainHashes?: string[]): Promise<StakingItem[]>;
39
39
  subscribeStaking(addresses: string[], chainList?: string[], callback?: (stakingItems: StakingItem[]) => void): Subscription;
40
40
  subscribeChainStakingMetadata(chains: string[], callback: (data: ChainStakingMetadata[]) => void): void;
41
- subscribeNominatorMetadata(callback: (data: NominatorMetadata[]) => void): void;
41
+ subscribeNominatorMetadata(addresses: string[], callback: (data: NominatorMetadata[]) => void): Subscription;
42
42
  getHistories(query?: HistoryQuery): Promise<import("@subwallet/extension-base/services/storage-service/databases").ITransactionHistoryItem[]>;
43
43
  upsertHistory(histories: TransactionHistoryItem[]): Promise<unknown>;
44
44
  updateHistoryByExtrinsicHash(extrinsicHash: string, updateData: Partial<TransactionHistoryItem>): Promise<unknown>;
@@ -58,7 +58,7 @@ export default class DatabaseService {
58
58
  updateAssetStore(item: _ChainAsset): Promise<unknown>;
59
59
  getAllAssetStore(): Promise<_ChainAsset[]>;
60
60
  removeFromAssetStore(items: string[]): Promise<number>;
61
- updateChainStakingMetadata(item: ChainStakingMetadata): Promise<unknown>;
61
+ updateChainStakingMetadata(item: ChainStakingMetadata, changes?: Record<string, unknown>): Promise<unknown>;
62
62
  getChainStakingMetadata(): Promise<ChainStakingMetadata[]>;
63
63
  getStakingMetadataByChain(chain: string, type?: StakingType): Promise<ChainStakingMetadata | undefined>;
64
64
  updateNominatorMetadata(item: NominatorMetadata): Promise<unknown>;