@subwallet/extension-base 1.0.7-0 → 1.0.7-2

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 (64) hide show
  1. package/background/KoniTypes.d.ts +7 -8
  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 +109 -5
  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 +203 -15
  8. package/cjs/koni/api/staking/bonding/utils.js +7 -0
  9. package/cjs/koni/api/staking/index.js +11 -11
  10. package/cjs/koni/api/staking/paraChain.js +200 -130
  11. package/cjs/koni/api/staking/relayChain.js +66 -68
  12. package/cjs/koni/api/staking/subsquidStaking.js +6 -11
  13. package/cjs/koni/background/cron.js +0 -25
  14. package/cjs/koni/background/handlers/Extension.js +98 -74
  15. package/cjs/koni/background/handlers/State.js +17 -19
  16. package/cjs/koni/background/subscription.js +57 -12
  17. package/cjs/packageInfo.js +1 -1
  18. package/cjs/services/chain-service/constants.js +3 -1
  19. package/cjs/services/chain-service/utils.js +6 -1
  20. package/cjs/services/storage-service/DatabaseService.js +7 -3
  21. package/cjs/services/storage-service/db-stores/ChainStakingMetadata.js +5 -0
  22. package/cjs/services/storage-service/db-stores/NominatorMetadata.js +4 -4
  23. package/cjs/services/transaction-service/index.js +6 -1
  24. package/constants/index.d.ts +1 -1
  25. package/constants/index.js +1 -1
  26. package/koni/api/staking/bonding/amplitude.d.ts +4 -0
  27. package/koni/api/staking/bonding/amplitude.js +81 -0
  28. package/koni/api/staking/bonding/astar.d.ts +4 -0
  29. package/koni/api/staking/bonding/astar.js +107 -5
  30. package/koni/api/staking/bonding/index.d.ts +1 -0
  31. package/koni/api/staking/bonding/index.js +38 -4
  32. package/koni/api/staking/bonding/paraChain.d.ts +4 -0
  33. package/koni/api/staking/bonding/paraChain.js +95 -0
  34. package/koni/api/staking/bonding/relayChain.d.ts +5 -0
  35. package/koni/api/staking/bonding/relayChain.js +198 -14
  36. package/koni/api/staking/bonding/utils.d.ts +5 -0
  37. package/koni/api/staking/bonding/utils.js +6 -0
  38. package/koni/api/staking/index.d.ts +4 -4
  39. package/koni/api/staking/index.js +11 -11
  40. package/koni/api/staking/paraChain.d.ts +5 -5
  41. package/koni/api/staking/paraChain.js +201 -131
  42. package/koni/api/staking/relayChain.d.ts +4 -4
  43. package/koni/api/staking/relayChain.js +66 -67
  44. package/koni/api/staking/subsquidStaking.d.ts +1 -1
  45. package/koni/api/staking/subsquidStaking.js +6 -11
  46. package/koni/background/cron.js +1 -26
  47. package/koni/background/handlers/Extension.js +29 -7
  48. package/koni/background/handlers/State.d.ts +2 -2
  49. package/koni/background/handlers/State.js +17 -19
  50. package/koni/background/subscription.d.ts +2 -1
  51. package/koni/background/subscription.js +58 -13
  52. package/package.json +5 -5
  53. package/packageInfo.js +1 -1
  54. package/services/chain-service/constants.d.ts +1 -0
  55. package/services/chain-service/constants.js +3 -2
  56. package/services/chain-service/types.d.ts +8 -0
  57. package/services/chain-service/utils.js +6 -1
  58. package/services/storage-service/DatabaseService.d.ts +2 -2
  59. package/services/storage-service/DatabaseService.js +7 -3
  60. package/services/storage-service/db-stores/ChainStakingMetadata.d.ts +1 -0
  61. package/services/storage-service/db-stores/ChainStakingMetadata.js +3 -0
  62. package/services/storage-service/db-stores/NominatorMetadata.d.ts +2 -2
  63. package/services/storage-service/db-stores/NominatorMetadata.js +4 -4
  64. package/services/transaction-service/index.js +6 -1
@@ -77,8 +77,7 @@ class KoniState {
77
77
  stakingRewardSubject = new _rxjs.Subject();
78
78
  stakingRewardState = {
79
79
  ready: false,
80
- slowInterval: [],
81
- fastInterval: []
80
+ data: {}
82
81
  };
83
82
  lazyMap = {};
84
83
  ready = false;
@@ -203,18 +202,24 @@ class KoniState {
203
202
  async init() {
204
203
  await this.chainService.init();
205
204
  await this.migrationService.run();
206
- this.startSubscription();
207
205
  this.eventService.emit('chain.ready', true);
208
206
  this.onReady();
209
207
  this.onAccountAdd();
210
208
  this.onAccountRemove();
209
+ await this.startSubscription();
211
210
  }
212
- startSubscription() {
211
+ async startSubscription() {
212
+ await this.eventService.waitKeyringReady;
213
213
  this.dbService.subscribeChainStakingMetadata([], data => {
214
214
  this.chainStakingMetadataSubject.next(data);
215
215
  });
216
- this.dbService.subscribeNominatorMetadata(data => {
217
- this.stakingNominatorMetadataSubject.next(data);
216
+ let unsub;
217
+ this.keyringService.accountSubject.subscribe(accounts => {
218
+ // TODO: improve this
219
+ unsub && unsub.unsubscribe();
220
+ unsub = this.dbService.subscribeNominatorMetadata(Object.keys(accounts), data => {
221
+ this.stakingNominatorMetadataSubject.next(data);
222
+ });
218
223
  });
219
224
  }
220
225
  onReady() {
@@ -309,14 +314,6 @@ class KoniState {
309
314
  async getPooledStakingRecordsByAddress(addresses) {
310
315
  return this.dbService.getPooledStakings(addresses, this.activeChainSlugs);
311
316
  }
312
-
313
- // TODO: delete later
314
- // public async getStoredStaking (address: string) {
315
- // const items = await this.dbService.stores.staking.getDataByAddressAsObject(address);
316
- //
317
- // return items || {};
318
- // }
319
-
320
317
  subscribeStaking() {
321
318
  return this.stakingSubject;
322
319
  }
@@ -332,8 +329,8 @@ class KoniState {
332
329
  setStakingItem(networkKey, item) {
333
330
  this.dbService.updateStaking(networkKey, item.address, item).catch(e => this.logger.warn(e));
334
331
  }
335
- updateChainStakingMetadata(item) {
336
- this.dbService.updateChainStakingMetadata(item).catch(e => this.logger.warn(e));
332
+ updateChainStakingMetadata(item, changes) {
333
+ this.dbService.updateChainStakingMetadata(item, changes).catch(e => this.logger.warn(e));
337
334
  }
338
335
  updateStakingNominatorMetadata(item) {
339
336
  this.dbService.updateNominatorMetadata(item).catch(e => this.logger.warn(e));
@@ -386,12 +383,13 @@ class KoniState {
386
383
  return this.nftSubject;
387
384
  }
388
385
  resetStakingReward() {
389
- this.stakingRewardState.slowInterval = [];
386
+ this.stakingRewardState.data = {};
390
387
  this.stakingRewardSubject.next(this.stakingRewardState);
391
388
  }
392
- updateStakingReward(stakingRewardData, type, callback) {
389
+ updateStakingReward(stakingRewardData, callback) {
393
390
  this.stakingRewardState.ready = true;
394
- this.stakingRewardState[type] = stakingRewardData;
391
+ const key = `${stakingRewardData.chain}___${stakingRewardData.address}___${stakingRewardData.type}`;
392
+ this.stakingRewardState.data[key] = stakingRewardData;
395
393
  if (callback) {
396
394
  callback(this.stakingRewardState);
397
395
  }
@@ -26,7 +26,8 @@ class KoniSubscription {
26
26
  subscriptionMap = {
27
27
  crowdloan: undefined,
28
28
  balance: undefined,
29
- stakingOnChain: undefined
29
+ stakingOnChain: undefined,
30
+ essentialChainStakingMetadata: undefined
30
31
  };
31
32
  constructor(state, dbService) {
32
33
  this.dbService = dbService;
@@ -105,11 +106,38 @@ class KoniSubscription {
105
106
  return;
106
107
  }
107
108
  this.updateSubscription('stakingOnChain', this.initStakingOnChainSubscription(addresses, substrateApiMap, onlyRunOnFirstTime));
109
+ this.updateSubscription('essentialChainStakingMetadata', this.initEssentialChainStakingMetadataSubscription(substrateApiMap, onlyRunOnFirstTime)); // TODO: might not need to re-subscribe on changing account
108
110
  }
111
+
109
112
  initStakingOnChainSubscription(addresses, substrateApiMap, onlyRunOnFirstTime) {
110
- const unsub = (0, _staking.stakingOnChainApi)(addresses, substrateApiMap, (networkKey, rs) => {
113
+ const stakingCallback = (networkKey, rs) => {
111
114
  this.state.setStakingItem(networkKey, rs);
112
- }, this.state.getActiveChainInfoMap());
115
+ };
116
+ const nominatorStateCallback = nominatorMetadata => {
117
+ this.state.updateStakingNominatorMetadata(nominatorMetadata);
118
+ };
119
+ const unsub = (0, _staking.stakingOnChainApi)(addresses, substrateApiMap, this.state.getActiveChainInfoMap(), stakingCallback, nominatorStateCallback);
120
+ if (onlyRunOnFirstTime) {
121
+ unsub && unsub();
122
+ return;
123
+ }
124
+ return () => {
125
+ unsub && unsub();
126
+ };
127
+ }
128
+ initEssentialChainStakingMetadataSubscription(substrateApiMap, onlyRunOnFirstTime) {
129
+ const unsub = (0, _bonding.subscribeEssentialChainStakingMetadata)(substrateApiMap, this.state.getActiveChainInfoMap(), (networkKey, rs) => {
130
+ this.state.updateChainStakingMetadata(rs, {
131
+ era: rs.era,
132
+ minStake: rs.minStake,
133
+ maxValidatorPerNominator: rs.maxValidatorPerNominator,
134
+ // temporary fix for Astar, there's no limit for now
135
+ maxWithdrawalRequestPerValidator: rs.maxWithdrawalRequestPerValidator,
136
+ // by default
137
+ allowCancelUnstaking: rs.allowCancelUnstaking,
138
+ unstakingPeriod: rs.unstakingPeriod
139
+ });
140
+ });
113
141
  if (onlyRunOnFirstTime) {
114
142
  unsub && unsub();
115
143
  return;
@@ -183,8 +211,9 @@ class KoniSubscription {
183
211
  targetNetworkMap[key] = network;
184
212
  }
185
213
  });
186
- const result = await (0, _staking.getNominationStakingRewardData)(addresses, targetNetworkMap);
187
- this.state.updateStakingReward(result, 'slowInterval');
214
+ await (0, _staking.getNominationStakingRewardData)(addresses, targetNetworkMap, rewardItem => {
215
+ this.state.updateStakingReward(rewardItem);
216
+ });
188
217
  }
189
218
  async subscribeStakingRewardFastInterval(address) {
190
219
  const addresses = this.state.getDecodedAddresses(address);
@@ -211,9 +240,10 @@ class KoniSubscription {
211
240
  Object.keys(targetChainMap).forEach(key => {
212
241
  activeNetworks.push(key);
213
242
  });
214
- const [poolingStakingRewards, amplitudeUnclaimedStakingRewards] = await Promise.all([(0, _staking.getPoolingStakingRewardData)(pooledAddresses, targetChainMap, this.state.getSubstrateApiMap()), (0, _paraChain.getAmplitudeUnclaimedStakingReward)(this.state.getSubstrateApiMap(), addresses, chainInfoMap, activeNetworks)]);
215
- const result = [...poolingStakingRewards, ...amplitudeUnclaimedStakingRewards];
216
- this.state.updateStakingReward(result, 'fastInterval');
243
+ const updateState = result => {
244
+ this.state.updateStakingReward(result);
245
+ };
246
+ await Promise.all([(0, _staking.getPoolingStakingRewardData)(pooledAddresses, targetChainMap, this.state.getSubstrateApiMap(), updateState), (0, _paraChain.getAmplitudeUnclaimedStakingReward)(this.state.getSubstrateApiMap(), addresses, chainInfoMap, activeNetworks, updateState)]);
217
247
  }
218
248
  async fetchingStakingFromApi() {
219
249
  try {
@@ -237,16 +267,31 @@ class KoniSubscription {
237
267
  if (Object.values(filteredChainInfoMap).length === 0) {
238
268
  return;
239
269
  }
270
+ const timeout = new Promise(resolve => {
271
+ const id = setTimeout(() => {
272
+ clearTimeout(id);
273
+ resolve(null);
274
+ }, 3000);
275
+ });
240
276
 
241
277
  // Fetch data from helper API
242
- const dataFromApi = await this.fetchingStakingFromApi();
278
+ const _dataFromApi = await Promise.race([this.fetchingStakingFromApi(), timeout]);
279
+ const dataFromApi = _dataFromApi;
243
280
  await Promise.all(Object.values(filteredChainInfoMap).map(async chainInfo => {
244
281
  // Use fetch API data if available
245
- if (dataFromApi[chainInfo.slug]) {
246
- this.state.updateChainStakingMetadata(dataFromApi[chainInfo.slug]);
282
+ if (dataFromApi && dataFromApi[chainInfo.slug]) {
283
+ this.state.updateChainStakingMetadata(dataFromApi[chainInfo.slug], {
284
+ expectedReturn: dataFromApi[chainInfo.slug].expectedReturn,
285
+ inflation: dataFromApi[chainInfo.slug].inflation,
286
+ nominatorCount: dataFromApi[chainInfo.slug].nominatorCount
287
+ });
247
288
  } else {
248
289
  const chainStakingMetadata = await (0, _bonding.getChainStakingMetadata)(chainInfo, substrateApiMap[chainInfo.slug]);
249
- this.state.updateChainStakingMetadata(chainStakingMetadata);
290
+ this.state.updateChainStakingMetadata(chainStakingMetadata, {
291
+ expectedReturn: chainStakingMetadata.expectedReturn,
292
+ inflation: chainStakingMetadata.inflation,
293
+ nominatorCount: chainStakingMetadata.nominatorCount
294
+ });
250
295
  }
251
296
  }));
252
297
  }
@@ -13,6 +13,6 @@ const packageInfo = {
13
13
  name: '@subwallet/extension-base',
14
14
  path: typeof __dirname === 'string' ? __dirname : 'auto',
15
15
  type: 'cjs',
16
- version: '1.0.7-0'
16
+ version: '1.0.7-2'
17
17
  };
18
18
  exports.packageInfo = packageInfo;
@@ -66,7 +66,9 @@ const _STAKING_CHAIN_GROUP = {
66
66
  kilt: ['kilt', 'kilt_peregrine'],
67
67
  nominationPool: ['polkadot', 'kusama', 'westend', 'alephTest', 'aleph'],
68
68
  bifrost: ['bifrost', 'bifrost_testnet'],
69
- aleph: ['aleph', 'alephTest'] // A0 has distinct tokenomics
69
+ aleph: ['aleph', 'alephTest'],
70
+ // A0 has distinct tokenomics
71
+ ternoa: ['ternoa', 'ternoa_alphanet']
70
72
  };
71
73
  exports._STAKING_CHAIN_GROUP = _STAKING_CHAIN_GROUP;
72
74
  const _STAKING_ERA_LENGTH_MAP = {
@@ -121,7 +121,12 @@ function _isPureSubstrateChain(chainInfo) {
121
121
  }
122
122
  function _getOriginChainOfAsset(assetSlug) {
123
123
  if (assetSlug.startsWith(_types2._CUSTOM_PREFIX)) {
124
- return assetSlug.split('-')[1];
124
+ const arr = assetSlug.split('-').slice(1);
125
+ if (arr[0] === 'custom') {
126
+ const end = arr.findIndex(str => Object.values(_types._AssetType).includes(str));
127
+ return arr.slice(0, end).join('-');
128
+ }
129
+ return arr[0];
125
130
  }
126
131
  return assetSlug.split('-')[0];
127
132
  }
@@ -106,8 +106,8 @@ class DatabaseService {
106
106
  next: data => callback && callback(data)
107
107
  });
108
108
  }
109
- subscribeNominatorMetadata(callback) {
110
- this.stores.nominatorMetadata.subscribeAll().subscribe({
109
+ subscribeNominatorMetadata(addresses, callback) {
110
+ return this.stores.nominatorMetadata.subscribeByAddresses(addresses).subscribe({
111
111
  next: data => callback && callback(data)
112
112
  });
113
113
  }
@@ -198,7 +198,11 @@ class DatabaseService {
198
198
  }
199
199
 
200
200
  // Staking
201
- async updateChainStakingMetadata(item) {
201
+ async updateChainStakingMetadata(item, changes) {
202
+ const existingRecord = await this.stores.chainStakingMetadata.getByChainAndType(item.chain, item.type);
203
+ if (existingRecord && changes) {
204
+ return this.stores.chainStakingMetadata.updateByChainAndType(item.chain, item.type, changes);
205
+ }
202
206
  return this.stores.chainStakingMetadata.upsert(item);
203
207
  }
204
208
  async getChainStakingMetadata() {
@@ -34,5 +34,10 @@ class ChainStakingMetadataStore extends _BaseStoreWithChain.default {
34
34
  async removeByChains(chains) {
35
35
  return this.table.where('chain').anyOfIgnoreCase(chains).delete();
36
36
  }
37
+ updateByChainAndType(chain) {
38
+ let type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _KoniTypes.StakingType.NOMINATED;
39
+ let changes = arguments.length > 2 ? arguments[2] : undefined;
40
+ return this.table.update([chain, type], changes);
41
+ }
37
42
  }
38
43
  exports.default = ChainStakingMetadataStore;
@@ -14,14 +14,14 @@ class NominatorMetadataStore extends _BaseStoreWithAddressAndChain.default {
14
14
  async getAll() {
15
15
  return this.table.toArray();
16
16
  }
17
- subscribeByAddress(address) {
18
- return (0, _dexie.liveQuery)(() => this.getByAddress(address));
17
+ subscribeByAddresses(addresses) {
18
+ return (0, _dexie.liveQuery)(() => this.getByAddress(addresses));
19
19
  }
20
20
  subscribeAll() {
21
21
  return (0, _dexie.liveQuery)(() => this.getAll());
22
22
  }
23
- getByAddress(address) {
24
- return this.table.where('address').anyOfIgnoreCase(address).toArray();
23
+ getByAddress(addresses) {
24
+ return this.table.where('address').anyOfIgnoreCase(addresses).toArray();
25
25
  }
26
26
  async removeByAddress(address) {
27
27
  return this.table.where('address').anyOfIgnoreCase(address).delete();
@@ -644,7 +644,12 @@ class TransactionService {
644
644
  if (!payload.parseData) {
645
645
  const isToContract = await (0, _parseTransaction.isContractAddress)(payload.to || '', evmApi);
646
646
  payload.isToContract = isToContract;
647
- payload.parseData = isToContract ? payload.data ? (await (0, _parseTransaction.parseContractInput)(payload.data || '', payload.to || '', chainInfo)).result : '' : payload.data || '';
647
+ try {
648
+ payload.parseData = isToContract ? payload.data ? (await (0, _parseTransaction.parseContractInput)(payload.data || '', payload.to || '', chainInfo)).result : '' : payload.data || '';
649
+ } catch (e) {
650
+ console.warn('Unable to parse contract input data');
651
+ payload.parseData = payload.data;
652
+ }
648
653
  }
649
654
  if ('data' in payload && payload.data === undefined) {
650
655
  delete payload.data;
@@ -6,7 +6,7 @@ export declare const ASTAR_REFRESH_BALANCE_INTERVAL = 60000;
6
6
  export declare const SUB_TOKEN_REFRESH_BALANCE_INTERVAL = 60000;
7
7
  export declare const CRON_REFRESH_NFT_INTERVAL = 7200000;
8
8
  export declare const CRON_REFRESH_STAKING_REWARD_INTERVAL = 900000;
9
- export declare const CRON_REFRESH_STAKING_REWARD_FAST_INTERVAL = 45000;
9
+ export declare const CRON_REFRESH_STAKING_REWARD_FAST_INTERVAL = 300000;
10
10
  export declare const CRON_REFRESH_HISTORY_INTERVAL = 900000;
11
11
  export declare const CRON_GET_API_MAP_STATUS = 10000;
12
12
  export declare const CRON_REFRESH_CHAIN_STAKING_METADATA = 900000;
@@ -9,7 +9,7 @@ export const ASTAR_REFRESH_BALANCE_INTERVAL = 60000;
9
9
  export const SUB_TOKEN_REFRESH_BALANCE_INTERVAL = 60000;
10
10
  export const CRON_REFRESH_NFT_INTERVAL = 7200000;
11
11
  export const CRON_REFRESH_STAKING_REWARD_INTERVAL = 900000;
12
- export const CRON_REFRESH_STAKING_REWARD_FAST_INTERVAL = 45000;
12
+ export const CRON_REFRESH_STAKING_REWARD_FAST_INTERVAL = 300000;
13
13
  export const CRON_REFRESH_HISTORY_INTERVAL = 900000;
14
14
  export const CRON_GET_API_MAP_STATUS = 10000;
15
15
  export const CRON_REFRESH_CHAIN_STAKING_METADATA = 900000;
@@ -1,7 +1,11 @@
1
1
  import { _ChainInfo } from '@subwallet/chain-list/types';
2
2
  import { ChainStakingMetadata, NominatorMetadata, ValidatorInfo } from '@subwallet/extension-base/background/KoniTypes';
3
+ import { ParachainStakingStakeOption } from '@subwallet/extension-base/koni/api/staking/bonding/utils';
3
4
  import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types';
5
+ import { Codec } from '@polkadot/types/types';
6
+ export declare function subscribeAmplitudeStakingMetadata(chain: string, substrateApi: _SubstrateApi, callback: (chain: string, rs: ChainStakingMetadata) => void): Promise<Codec>;
4
7
  export declare function getAmplitudeStakingMetadata(chain: string, substrateApi: _SubstrateApi): Promise<ChainStakingMetadata>;
8
+ export declare function subscribeAmplitudeNominatorMetadata(chainInfo: _ChainInfo, address: string, substrateApi: _SubstrateApi, delegatorState: ParachainStakingStakeOption, unstakingInfo: Record<string, number>): Promise<NominatorMetadata>;
5
9
  export declare function getAmplitudeNominatorMetadata(chainInfo: _ChainInfo, address: string, substrateApi: _SubstrateApi): Promise<NominatorMetadata | undefined>;
6
10
  export declare function getAmplitudeCollatorsInfo(chain: string, substrateApi: _SubstrateApi): Promise<ValidatorInfo[]>;
7
11
  export declare function getAmplitudeBondingExtrinsic(substrateApi: _SubstrateApi, amount: string, selectedValidatorInfo: ValidatorInfo, nominatorMetadata?: NominatorMetadata): Promise<import("@polkadot/api-base/types").SubmittableExtrinsic<"promise", import("@polkadot/types/types").ISubmittableResult>>;
@@ -7,6 +7,30 @@ import { _STAKING_ERA_LENGTH_MAP } from '@subwallet/extension-base/services/chai
7
7
  import { parseRawNumber, reformatAddress } from '@subwallet/extension-base/utils';
8
8
  import { BN, BN_ZERO } from '@polkadot/util';
9
9
  import { isEthereumAddress } from '@polkadot/util-crypto';
10
+ export function subscribeAmplitudeStakingMetadata(chain, substrateApi, callback) {
11
+ return substrateApi.api.query.parachainStaking.round(_round => {
12
+ const roundObj = _round.toHuman();
13
+ const round = parseRawNumber(roundObj.current);
14
+ const maxDelegations = substrateApi.api.consts.parachainStaking.maxDelegationsPerRound.toString();
15
+ const minDelegatorStake = substrateApi.api.consts.parachainStaking.minDelegatorStake.toString();
16
+ const unstakingDelay = substrateApi.api.consts.parachainStaking.stakeDuration.toString();
17
+ const _blockPerRound = substrateApi.api.consts.parachainStaking.defaultBlocksPerRound.toString();
18
+ const blockPerRound = parseFloat(_blockPerRound);
19
+ const blockDuration = (_STAKING_ERA_LENGTH_MAP[chain] || _STAKING_ERA_LENGTH_MAP.default) / blockPerRound; // in hours
20
+ const unstakingPeriod = blockDuration * parseInt(unstakingDelay);
21
+ callback(chain, {
22
+ chain,
23
+ type: StakingType.NOMINATED,
24
+ era: round,
25
+ minStake: minDelegatorStake,
26
+ maxValidatorPerNominator: parseInt(maxDelegations),
27
+ maxWithdrawalRequestPerValidator: 1,
28
+ // by default
29
+ allowCancelUnstaking: true,
30
+ unstakingPeriod
31
+ });
32
+ });
33
+ }
10
34
  export async function getAmplitudeStakingMetadata(chain, substrateApi) {
11
35
  const chainApi = await substrateApi.isReady;
12
36
  const _round = (await chainApi.api.query.parachainStaking.round()).toHuman();
@@ -30,6 +54,63 @@ export async function getAmplitudeStakingMetadata(chain, substrateApi) {
30
54
  unstakingPeriod
31
55
  };
32
56
  }
57
+ export async function subscribeAmplitudeNominatorMetadata(chainInfo, address, substrateApi, delegatorState, unstakingInfo) {
58
+ const nominationList = [];
59
+ const unstakingList = [];
60
+ const minDelegatorStake = substrateApi.api.consts.parachainStaking.minDelegatorStake.toString();
61
+ let activeStake = '0';
62
+ if (delegatorState) {
63
+ // delegatorState can be null while unstaking all
64
+ const identityInfo = substrateApi.api.query.identity ? (await substrateApi.api.query.identity.identityOf(delegatorState.owner)).toPrimitive() : undefined;
65
+ const identity = identityInfo ? parseIdentity(identityInfo) : undefined;
66
+ activeStake = delegatorState.amount.toString();
67
+ const bnActiveStake = new BN(activeStake);
68
+ let delegationStatus = StakingStatus.NOT_EARNING;
69
+ if (bnActiveStake.gt(BN_ZERO) && bnActiveStake.gte(new BN(minDelegatorStake))) {
70
+ delegationStatus = StakingStatus.EARNING_REWARD;
71
+ }
72
+ nominationList.push({
73
+ status: delegationStatus,
74
+ chain: chainInfo.slug,
75
+ validatorAddress: delegatorState.owner,
76
+ activeStake: delegatorState.amount.toString(),
77
+ validatorMinStake: '0',
78
+ hasUnstaking: !!unstakingInfo && Object.values(unstakingInfo).length > 0,
79
+ validatorIdentity: identity
80
+ });
81
+ }
82
+ if (unstakingInfo && Object.values(unstakingInfo).length > 0) {
83
+ const _currentBlockInfo = await substrateApi.api.rpc.chain.getHeader();
84
+ const currentBlockInfo = _currentBlockInfo.toPrimitive();
85
+ const currentBlockNumber = currentBlockInfo.number;
86
+ const _blockPerRound = substrateApi.api.consts.parachainStaking.defaultBlocksPerRound.toString();
87
+ const blockPerRound = parseFloat(_blockPerRound);
88
+ const nearestUnstakingBlock = Object.keys(unstakingInfo)[0];
89
+ const nearestUnstakingAmount = Object.values(unstakingInfo)[0];
90
+ const blockDuration = (_STAKING_ERA_LENGTH_MAP[chainInfo.slug] || _STAKING_ERA_LENGTH_MAP.default) / blockPerRound; // in hours
91
+
92
+ const isClaimable = parseInt(nearestUnstakingBlock) - currentBlockNumber <= 0;
93
+ const remainingBlock = parseInt(nearestUnstakingBlock) - (currentBlockNumber + 1);
94
+ const waitingTime = remainingBlock * blockDuration;
95
+ unstakingList.push({
96
+ chain: chainInfo.slug,
97
+ status: isClaimable ? UnstakingStatus.CLAIMABLE : UnstakingStatus.UNLOCKING,
98
+ claimable: nearestUnstakingAmount.toString(),
99
+ waitingTime: waitingTime > 0 ? waitingTime : 0,
100
+ validatorAddress: (delegatorState === null || delegatorState === void 0 ? void 0 : delegatorState.owner) || undefined
101
+ });
102
+ }
103
+ const stakingStatus = getStakingStatusByNominations(new BN(activeStake), nominationList);
104
+ return {
105
+ chain: chainInfo.slug,
106
+ type: StakingType.NOMINATED,
107
+ status: stakingStatus,
108
+ address: address,
109
+ activeStake: activeStake,
110
+ nominations: nominationList,
111
+ unstakings: unstakingList
112
+ };
113
+ }
33
114
  export async function getAmplitudeNominatorMetadata(chainInfo, address, substrateApi) {
34
115
  if (isEthereumAddress(address)) {
35
116
  return;
@@ -1,7 +1,11 @@
1
1
  import { _ChainInfo } from '@subwallet/chain-list/types';
2
2
  import { ChainStakingMetadata, NominatorMetadata, UnstakingInfo, ValidatorInfo } from '@subwallet/extension-base/background/KoniTypes';
3
+ import { PalletDappsStakingAccountLedger } from '@subwallet/extension-base/koni/api/staking/bonding/utils';
3
4
  import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types';
5
+ import { Codec } from '@polkadot/types/types';
6
+ export declare function subscribeAstarStakingMetadata(chain: string, substrateApi: _SubstrateApi, callback: (chain: string, rs: ChainStakingMetadata) => void): Promise<Codec>;
4
7
  export declare function getAstarStakingMetadata(chain: string, substrateApi: _SubstrateApi): Promise<ChainStakingMetadata>;
8
+ export declare function subscribeAstarNominatorMetadata(chainInfo: _ChainInfo, address: string, substrateApi: _SubstrateApi, ledger: PalletDappsStakingAccountLedger): Promise<NominatorMetadata>;
5
9
  export declare function getAstarNominatorMetadata(chainInfo: _ChainInfo, address: string, substrateApi: _SubstrateApi): Promise<NominatorMetadata | undefined>;
6
10
  export declare function getAstarDappsInfo(networkKey: string, substrateApi: _SubstrateApi): Promise<ValidatorInfo[]>;
7
11
  export declare function getAstarBondingExtrinsic(substrateApi: _SubstrateApi, amount: string, dappInfo: ValidatorInfo): Promise<import("@polkadot/api-base/types").SubmittableExtrinsic<"promise", import("@polkadot/types/types").ISubmittableResult>>;
@@ -8,6 +8,26 @@ import { isUrl, parseRawNumber } from '@subwallet/extension-base/utils';
8
8
  import fetch from 'cross-fetch';
9
9
  import { BN, BN_ZERO } from '@polkadot/util';
10
10
  import { isEthereumAddress } from '@polkadot/util-crypto';
11
+ export function subscribeAstarStakingMetadata(chain, substrateApi, callback) {
12
+ return substrateApi.api.query.dappsStaking.currentEra(_currentEra => {
13
+ const era = _currentEra.toString();
14
+ const minDelegatorStake = substrateApi.api.consts.dappsStaking.minimumStakingAmount.toString();
15
+ const unstakingDelay = substrateApi.api.consts.dappsStaking.unbondingPeriod.toString();
16
+ const unstakingPeriod = parseInt(unstakingDelay) * _STAKING_ERA_LENGTH_MAP[chain];
17
+ callback(chain, {
18
+ chain,
19
+ type: StakingType.NOMINATED,
20
+ era: parseInt(era),
21
+ minStake: minDelegatorStake,
22
+ maxValidatorPerNominator: 100,
23
+ // temporary fix for Astar, there's no limit for now
24
+ maxWithdrawalRequestPerValidator: 1,
25
+ // by default
26
+ allowCancelUnstaking: true,
27
+ unstakingPeriod
28
+ });
29
+ });
30
+ }
11
31
  export async function getAstarStakingMetadata(chain, substrateApi) {
12
32
  const aprPromise = new Promise(function (resolve) {
13
33
  fetch(`https://api.astar.network/api/v1/${chain}/dapps-staking/apr`, {
@@ -43,6 +63,87 @@ export async function getAstarStakingMetadata(chain, substrateApi) {
43
63
  unstakingPeriod
44
64
  };
45
65
  }
66
+ export async function subscribeAstarNominatorMetadata(chainInfo, address, substrateApi, ledger) {
67
+ const nominationList = [];
68
+ const unstakingList = [];
69
+ const allDappsReq = new Promise(function (resolve) {
70
+ fetch(`https://api.astar.network/api/v1/${chainInfo.slug}/dapps-staking/dapps`, {
71
+ method: 'GET'
72
+ }).then(resp => {
73
+ resolve(resp.json());
74
+ }).catch(console.error);
75
+ });
76
+ const [_allDapps, _era, _stakerInfo] = await Promise.all([allDappsReq, substrateApi.api.query.dappsStaking.currentEra(), substrateApi.api.query.dappsStaking.generalStakerInfo.entries(address)]);
77
+ const currentEra = _era.toString();
78
+ const minDelegatorStake = substrateApi.api.consts.dappsStaking.minimumStakingAmount.toString();
79
+ const allDapps = _allDapps;
80
+ let bnTotalActiveStake = BN_ZERO;
81
+ if (_stakerInfo.length > 0) {
82
+ const dAppInfoMap = {};
83
+ allDapps.forEach(dappInfo => {
84
+ dAppInfoMap[dappInfo.address.toLowerCase()] = dappInfo;
85
+ });
86
+ for (const item of _stakerInfo) {
87
+ const data = item[0].toHuman();
88
+ const stakedDapp = data[1];
89
+ const stakeData = item[1].toPrimitive();
90
+ const stakeList = stakeData.stakes;
91
+ const dappAddress = stakedDapp.Evm ? stakedDapp.Evm.toLowerCase() : stakedDapp.Wasm;
92
+ const currentStake = stakeList.slice(-1)[0].staked.toString() || '0';
93
+ const bnCurrentStake = new BN(currentStake);
94
+ if (bnCurrentStake.gt(BN_ZERO)) {
95
+ const dappStakingStatus = bnCurrentStake.gt(BN_ZERO) && bnCurrentStake.gte(new BN(minDelegatorStake)) ? StakingStatus.EARNING_REWARD : StakingStatus.NOT_EARNING;
96
+ bnTotalActiveStake = bnTotalActiveStake.add(bnCurrentStake);
97
+ const dappInfo = dAppInfoMap[dappAddress];
98
+ nominationList.push({
99
+ status: dappStakingStatus,
100
+ chain: chainInfo.slug,
101
+ validatorAddress: dappAddress.toLowerCase(),
102
+ activeStake: currentStake,
103
+ validatorMinStake: '0',
104
+ validatorIdentity: dappInfo === null || dappInfo === void 0 ? void 0 : dappInfo.name,
105
+ hasUnstaking: false // cannot get unstaking info by dapp
106
+ });
107
+ }
108
+ }
109
+ }
110
+
111
+ const unlockingChunks = ledger.unbondingInfo.unlockingChunks;
112
+ if (unlockingChunks.length > 0) {
113
+ for (const unlockingChunk of unlockingChunks) {
114
+ const isClaimable = unlockingChunk.unlockEra - parseInt(currentEra) <= 0;
115
+ const remainingEra = unlockingChunk.unlockEra - (parseInt(currentEra) + 1);
116
+ const waitingTime = remainingEra * _STAKING_ERA_LENGTH_MAP[chainInfo.slug];
117
+ unstakingList.push({
118
+ chain: chainInfo.slug,
119
+ status: isClaimable ? UnstakingStatus.CLAIMABLE : UnstakingStatus.UNLOCKING,
120
+ claimable: unlockingChunk.amount.toString(),
121
+ waitingTime: waitingTime > 0 ? waitingTime : 0
122
+ });
123
+ }
124
+ }
125
+ if (nominationList.length === 0 && unstakingList.length === 0) {
126
+ return {
127
+ chain: chainInfo.slug,
128
+ type: StakingType.NOMINATED,
129
+ address,
130
+ status: StakingStatus.NOT_STAKING,
131
+ activeStake: '0',
132
+ nominations: [],
133
+ unstakings: []
134
+ };
135
+ }
136
+ const stakingStatus = getStakingStatusByNominations(bnTotalActiveStake, nominationList);
137
+ return {
138
+ chain: chainInfo.slug,
139
+ type: StakingType.NOMINATED,
140
+ address: address,
141
+ activeStake: bnTotalActiveStake.toString(),
142
+ nominations: nominationList,
143
+ unstakings: unstakingList,
144
+ status: stakingStatus
145
+ };
146
+ }
46
147
  export async function getAstarNominatorMetadata(chainInfo, address, substrateApi) {
47
148
  if (isEthereumAddress(address)) {
48
149
  return;
@@ -67,14 +168,15 @@ export async function getAstarNominatorMetadata(chainInfo, address, substrateApi
67
168
  const dAppInfoMap = {};
68
169
  const allDapps = await allDappsReq;
69
170
  allDapps.forEach(dappInfo => {
70
- dAppInfoMap[dappInfo.address.toLowerCase()] = dappInfo;
171
+ const address = isEthereumAddress(dappInfo.address) ? dappInfo.address.toLowerCase() : dappInfo.address;
172
+ dAppInfoMap[address] = dappInfo;
71
173
  });
72
174
  for (const item of _stakerInfo) {
73
175
  const data = item[0].toHuman();
74
176
  const stakedDapp = data[1];
75
177
  const stakeData = item[1].toPrimitive();
76
178
  const stakeList = stakeData.stakes;
77
- const dappAddress = stakedDapp.Evm.toLowerCase();
179
+ const dappAddress = isEthereumAddress(stakedDapp.Evm) ? stakedDapp.Evm.toLowerCase() : stakedDapp.Evm;
78
180
  const currentStake = stakeList.slice(-1)[0].staked.toString() || '0';
79
181
  const bnCurrentStake = new BN(currentStake);
80
182
  if (bnCurrentStake.gt(BN_ZERO)) {
@@ -84,7 +186,7 @@ export async function getAstarNominatorMetadata(chainInfo, address, substrateApi
84
186
  nominationList.push({
85
187
  status: dappStakingStatus,
86
188
  chain,
87
- validatorAddress: dappAddress.toLowerCase(),
189
+ validatorAddress: dappAddress,
88
190
  activeStake: currentStake,
89
191
  validatorMinStake: '0',
90
192
  validatorIdentity: dappInfo === null || dappInfo === void 0 ? void 0 : dappInfo.name,
@@ -167,7 +269,7 @@ export async function getAstarDappsInfo(networkKey, substrateApi) {
167
269
  allDappsInfo.push({
168
270
  commission: 0,
169
271
  expectedReturn: 0,
170
- address: dappAddress.toLowerCase(),
272
+ address: isEthereumAddress(dappAddress) ? dappAddress.toLowerCase() : dappAddress,
171
273
  totalStake: totalStake,
172
274
  ownStake: '0',
173
275
  otherStake: totalStake.toString(),
@@ -217,7 +319,7 @@ export async function getAstarClaimRewardExtrinsic(substrateApi, address) {
217
319
  const stakedDapp = data[1];
218
320
  const stakeData = item[1].toHuman();
219
321
  const stakes = stakeData.stakes;
220
- const dappAddress = stakedDapp.Evm.toLowerCase();
322
+ const dappAddress = isEthereumAddress(stakedDapp.Evm) ? stakedDapp.Evm.toLowerCase() : stakedDapp.Evm;
221
323
  let numberOfUnclaimedEra = 0;
222
324
  const maxTx = 50;
223
325
  for (let i = 0; i < stakes.length; i++) {
@@ -13,3 +13,4 @@ export declare function getUnbondingExtrinsic(nominatorMetadata: NominatorMetada
13
13
  export declare function getWithdrawalExtrinsic(substrateApi: _SubstrateApi, chain: string, nominatorMetadata: NominatorMetadata, validatorAddress?: string): Promise<import("@polkadot/api-base/types").SubmittableExtrinsic<"promise", import("@polkadot/types/types").ISubmittableResult>>;
14
14
  export declare function getClaimRewardExtrinsic(substrateApi: _SubstrateApi, chain: string, address: string, stakingType: StakingType, bondReward?: boolean): Promise<import("@polkadot/api-base/types").SubmittableExtrinsic<"promise", import("@polkadot/types/types").ISubmittableResult>>;
15
15
  export declare function getCancelWithdrawalExtrinsic(substrateApi: _SubstrateApi, chain: string, selectedUnstaking: UnstakingInfo): Promise<import("@polkadot/api-base/types").SubmittableExtrinsic<"promise", import("@polkadot/types/types").ISubmittableResult>>;
16
+ export declare function subscribeEssentialChainStakingMetadata(substrateApiMap: Record<string, _SubstrateApi>, chainInfoMap: Record<string, _ChainInfo>, callback: (chain: string, rs: ChainStakingMetadata) => void): () => void;