@subwallet/extension-base 1.3.45-1 → 1.3.46-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/background/KoniTypes.d.ts +5 -0
  2. package/background/KoniTypes.js +5 -0
  3. package/background/types.d.ts +2 -0
  4. package/cjs/background/KoniTypes.js +7 -1
  5. package/cjs/core/logic-validation/request.js +55 -28
  6. package/cjs/core/utils.js +22 -0
  7. package/cjs/koni/background/handlers/Extension.js +84 -61
  8. package/cjs/koni/background/handlers/Tabs.js +11 -3
  9. package/cjs/packageInfo.js +1 -1
  10. package/cjs/page/evm/index.js +64 -105
  11. package/cjs/page/index.js +5 -3
  12. package/cjs/page/substrate/Accounts.js +2 -1
  13. package/cjs/services/balance-service/helpers/subscribe/index.js +3 -76
  14. package/cjs/services/chain-service/index.js +3 -0
  15. package/cjs/services/chain-service/utils/index.js +31 -1
  16. package/cjs/services/earning-service/constants/chains.js +2 -1
  17. package/cjs/services/earning-service/handlers/native-staking/base.js +3 -0
  18. package/cjs/services/earning-service/handlers/native-staking/relay-chain.js +9 -2
  19. package/cjs/services/earning-service/handlers/nomination-pool/index.js +6 -3
  20. package/cjs/services/earning-service/service.js +39 -17
  21. package/cjs/services/keyring-service/context/handlers/Json.js +2 -1
  22. package/cjs/services/keyring-service/context/handlers/Ledger.js +7 -2
  23. package/cjs/services/request-service/handler/AuthRequestHandler.js +30 -6
  24. package/cjs/types/account/info/keyring.js +1 -0
  25. package/cjs/utils/account/analyze.js +5 -2
  26. package/cjs/utils/account/common.js +93 -2
  27. package/cjs/utils/account/transform.js +10 -0
  28. package/cjs/utils/asset.js +9 -2
  29. package/cjs/utils/staticData/index.js +7 -2
  30. package/core/logic-validation/request.js +31 -4
  31. package/core/types.d.ts +3 -2
  32. package/core/utils.js +24 -2
  33. package/koni/background/handlers/Extension.js +31 -8
  34. package/koni/background/handlers/Tabs.js +11 -4
  35. package/package.json +7 -6
  36. package/packageInfo.js +1 -1
  37. package/page/evm/index.d.ts +9 -18
  38. package/page/evm/index.js +62 -101
  39. package/page/index.js +5 -3
  40. package/page/substrate/Accounts.js +2 -1
  41. package/services/balance-service/helpers/subscribe/index.d.ts +1 -11
  42. package/services/balance-service/helpers/subscribe/index.js +3 -74
  43. package/services/chain-service/index.d.ts +1 -0
  44. package/services/chain-service/index.js +3 -0
  45. package/services/chain-service/utils/index.d.ts +10 -2
  46. package/services/chain-service/utils/index.js +26 -2
  47. package/services/earning-service/constants/chains.d.ts +1 -0
  48. package/services/earning-service/constants/chains.js +2 -1
  49. package/services/earning-service/handlers/native-staking/base.d.ts +1 -0
  50. package/services/earning-service/handlers/native-staking/base.js +3 -0
  51. package/services/earning-service/handlers/native-staking/relay-chain.js +9 -2
  52. package/services/earning-service/handlers/nomination-pool/index.d.ts +1 -0
  53. package/services/earning-service/handlers/nomination-pool/index.js +6 -3
  54. package/services/earning-service/service.d.ts +2 -0
  55. package/services/earning-service/service.js +42 -20
  56. package/services/keyring-service/context/handlers/Json.js +2 -1
  57. package/services/keyring-service/context/handlers/Ledger.js +7 -2
  58. package/services/request-service/handler/AuthRequestHandler.d.ts +1 -0
  59. package/services/request-service/handler/AuthRequestHandler.js +30 -6
  60. package/services/request-service/types.d.ts +1 -0
  61. package/types/account/action/subscribe.d.ts +3 -0
  62. package/types/account/info/keyring.d.ts +3 -0
  63. package/types/account/info/keyring.js +1 -0
  64. package/types/balance/transfer.d.ts +1 -0
  65. package/utils/account/analyze.js +5 -2
  66. package/utils/account/common.d.ts +13 -1
  67. package/utils/account/common.js +91 -2
  68. package/utils/account/transform.js +10 -0
  69. package/utils/asset.d.ts +2 -1
  70. package/utils/asset.js +7 -1
  71. package/utils/staticData/assetHubStaking.json +1 -0
  72. package/utils/staticData/index.d.ts +4 -1
  73. package/utils/staticData/index.js +5 -1
@@ -1018,6 +1018,9 @@ export class ChainService {
1018
1018
  async fetchLatestSufficientChains() {
1019
1019
  return (await fetchStaticData('chains/supported-sufficient-chains')) || [];
1020
1020
  }
1021
+ async fetchAhMapChain() {
1022
+ return await fetchStaticData('asset-hub-staking-map');
1023
+ }
1021
1024
  async initChains() {
1022
1025
  const storedChainSettings = await this.dbService.getAllChainStore();
1023
1026
  const defaultChainInfoMap = filterChainInfoMap(ChainInfoMap, ignoredList);
@@ -2,7 +2,7 @@ import { _AssetRef, _AssetType, _ChainAsset, _ChainInfo, _MultiChainAsset } from
2
2
  import { BasicTokenInfo } from '@subwallet/extension-base/background/KoniTypes';
3
3
  import { _ChainState, _DataMap } from '@subwallet/extension-base/services/chain-service/types';
4
4
  import { IChain } from '@subwallet/extension-base/services/storage-service/databases';
5
- import { AccountChainType } from '@subwallet/extension-base/types';
5
+ import { AccountChainType, AccountSignMode } from '@subwallet/extension-base/types';
6
6
  import { KeypairType } from '@subwallet/keyring/types';
7
7
  export declare function _isCustomChain(slug: string): boolean;
8
8
  export declare function _isCustomAsset(slug: string): boolean;
@@ -40,6 +40,8 @@ export declare function _getTokenOnChainInfo(tokenInfo: _ChainAsset): Record<str
40
40
  export declare function _isBridgedToken(tokenInfo: _ChainAsset): boolean;
41
41
  export declare function _getTokenMinAmount(tokenInfo: _ChainAsset): string;
42
42
  export declare function _isChainEvmCompatible(chainInfo: _ChainInfo): boolean;
43
+ export declare function _isChainCompatibleLedgerEvm(chainInfo: _ChainInfo): boolean;
44
+ export declare function _isSubstrateEvmCompatibleChain(chainInfo: _ChainInfo): boolean;
43
45
  export declare function _isChainBitcoinCompatible(chainInfo: _ChainInfo): boolean;
44
46
  export declare function _isChainTonCompatible(chainInfo: _ChainInfo): boolean;
45
47
  export declare function _isChainCardanoCompatible(chainInfo: _ChainInfo): boolean;
@@ -68,6 +70,7 @@ export declare function _getNftTypesSupportedByChain(chainInfo: _ChainInfo): _As
68
70
  export declare function _getTokenTypesSupportedByChain(chainInfo: _ChainInfo): _AssetType[];
69
71
  export declare function _getChainNativeTokenBasicInfo(chainInfo: _ChainInfo): BasicTokenInfo;
70
72
  export declare function _getChainNativeTokenSlug(chainInfo: _ChainInfo): string;
73
+ export declare function _getChainSubstrateTokenSymbol(chainInfo: _ChainInfo): string;
71
74
  export declare function _isLocalToken(tokenInfo: _ChainAsset): boolean;
72
75
  export declare function _isTokenEvmSmartContract(tokenInfo: _ChainAsset): boolean;
73
76
  export declare function _isTokenTonSmartContract(tokenInfo: _ChainAsset): boolean;
@@ -119,6 +122,11 @@ export declare function updateLatestChainInfo(currentDataMap: _DataMap, latestCh
119
122
  needUpdateChainApiList: _ChainInfo[];
120
123
  };
121
124
  export declare const _chainInfoToChainType: (chainInfo: _ChainInfo) => AccountChainType;
122
- export declare const _isChainInfoCompatibleWithAccountInfo: (chainInfo: _ChainInfo, accountChainType: AccountChainType, accountType: KeypairType) => boolean;
125
+ interface AccountInfo {
126
+ chainType: AccountChainType;
127
+ type: KeypairType;
128
+ signMode?: AccountSignMode;
129
+ }
130
+ export declare const _isChainInfoCompatibleWithAccountInfo: (chainInfo: _ChainInfo, accountInfo: AccountInfo) => boolean;
123
131
  export declare const _getAssetNetuid: (assetInfo: _ChainAsset) => number;
124
132
  export * from './patch';
@@ -4,7 +4,7 @@
4
4
  import { _AssetRefPath, _AssetType, _ChainStatus, _SubstrateChainType } from '@subwallet/chain-list/types';
5
5
  import { _MANTA_ZK_CHAIN_GROUP, _ZK_ASSET_PREFIX } from '@subwallet/extension-base/services/chain-service/constants';
6
6
  import { _CUSTOM_PREFIX, _SMART_CONTRACT_STANDARDS } from '@subwallet/extension-base/services/chain-service/types';
7
- import { AccountChainType } from '@subwallet/extension-base/types';
7
+ import { AccountChainType, AccountSignMode } from '@subwallet/extension-base/types';
8
8
  import { BitcoinMainnetKeypairTypes, BitcoinTestnetKeypairTypes, CardanoKeypairTypes, EthereumKeypairTypes, SubstrateKeypairTypes, TonKeypairTypes } from '@subwallet/keyring/types';
9
9
  import { isEthereumAddress } from '@polkadot/util-crypto';
10
10
  export function _isCustomChain(slug) {
@@ -142,6 +142,12 @@ export function _getTokenMinAmount(tokenInfo) {
142
142
  export function _isChainEvmCompatible(chainInfo) {
143
143
  return !!chainInfo.evmInfo;
144
144
  }
145
+ export function _isChainCompatibleLedgerEvm(chainInfo) {
146
+ return !!chainInfo.evmInfo && chainInfo.evmInfo.evmChainId > 0;
147
+ }
148
+ export function _isSubstrateEvmCompatibleChain(chainInfo) {
149
+ return !!chainInfo.evmInfo && !!chainInfo.substrateInfo;
150
+ }
145
151
  export function _isChainBitcoinCompatible(chainInfo) {
146
152
  return !!chainInfo.bitcoinInfo;
147
153
  }
@@ -312,6 +318,13 @@ export function _getChainNativeTokenSlug(chainInfo) {
312
318
  }
313
319
  return `${chainInfo.slug}-${_AssetType.NATIVE}-${_getChainNativeTokenBasicInfo(chainInfo).symbol}`;
314
320
  }
321
+ export function _getChainSubstrateTokenSymbol(chainInfo) {
322
+ if (chainInfo.substrateInfo) {
323
+ return chainInfo.substrateInfo.symbol || '';
324
+ } else {
325
+ return '';
326
+ }
327
+ }
315
328
  export function _isLocalToken(tokenInfo) {
316
329
  return tokenInfo.assetType === _AssetType.LOCAL;
317
330
  }
@@ -594,11 +607,22 @@ export const _chainInfoToChainType = chainInfo => {
594
607
  }
595
608
  return AccountChainType.SUBSTRATE;
596
609
  };
597
- export const _isChainInfoCompatibleWithAccountInfo = (chainInfo, accountChainType, accountType) => {
610
+ export const _isChainInfoCompatibleWithAccountInfo = (chainInfo, accountInfo) => {
611
+ const {
612
+ chainType: accountChainType,
613
+ signMode: accountSignMode,
614
+ type: accountType
615
+ } = accountInfo;
598
616
  if (accountChainType === AccountChainType.SUBSTRATE) {
599
617
  return _isPureSubstrateChain(chainInfo) && SubstrateKeypairTypes.includes(accountType);
600
618
  }
601
619
  if (accountChainType === AccountChainType.ETHEREUM) {
620
+ if (accountSignMode === AccountSignMode.ECDSA_SUBSTRATE_LEDGER) {
621
+ return _isSubstrateEvmCompatibleChain(chainInfo) && EthereumKeypairTypes.includes(accountType);
622
+ }
623
+ if (accountSignMode === AccountSignMode.GENERIC_LEDGER) {
624
+ return _isChainCompatibleLedgerEvm(chainInfo) && EthereumKeypairTypes.includes(accountType);
625
+ }
602
626
  return _isChainEvmCompatible(chainInfo) && EthereumKeypairTypes.includes(accountType);
603
627
  }
604
628
  if (accountChainType === AccountChainType.TON) {
@@ -1,5 +1,6 @@
1
1
  export declare const _STAKING_CHAIN_GROUP: {
2
2
  relay: string[];
3
+ assetHub: string[];
3
4
  para: string[];
4
5
  astar: string[];
5
6
  amplitude: string[];
@@ -2,7 +2,8 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
4
  export const _STAKING_CHAIN_GROUP = {
5
- relay: ['polkadot', 'kusama', 'aleph', 'polkadex', 'ternoa', 'alephTest', 'polkadexTest', 'westend', 'kate', 'edgeware', 'creditcoin', 'vara_network', 'goldberg_testnet', 'availTuringTest', 'avail_mainnet', 'vara_testnet', 'dentnet', 'cere'],
5
+ relay: ['polkadot', 'kusama', 'aleph', 'polkadex', 'ternoa', 'alephTest', 'polkadexTest', 'westend', 'kate', 'edgeware', 'creditcoin', 'vara_network', 'goldberg_testnet', 'availTuringTest', 'avail_mainnet', 'vara_testnet', 'dentnet', 'cere', 'statemine', 'statemint', 'westend_assethub'],
6
+ assetHub: ['statemine', 'statemint', 'westend_assethub'],
6
7
  para: ['moonbeam', 'moonriver', 'moonbase', 'turing', 'turingStaging', 'bifrost', 'bifrost_testnet', 'calamari_test', 'calamari', 'manta_network', 'polimec'],
7
8
  astar: ['astar', 'shiden', 'shibuya'],
8
9
  amplitude: ['amplitude', 'amplitude_test', 'kilt', 'kilt_peregrine', 'pendulum', 'krest_network'],
@@ -8,6 +8,7 @@ export default abstract class BaseNativeStakingPoolHandler extends BasePoolHandl
8
8
  protected readonly shortName: string;
9
9
  slug: string;
10
10
  protected readonly availableMethod: YieldPoolMethodInfo;
11
+ static generateSlug(symbol: string, chain: string): string;
11
12
  constructor(state: KoniState, chain: string);
12
13
  protected getDescription(amount?: string): string;
13
14
  getPoolReward(useAddresses: string[], callBack: (rs: EarningRewardItem) => void): Promise<VoidFunction>;
@@ -16,6 +16,9 @@ export default class BaseNativeStakingPoolHandler extends BasePoolHandler {
16
16
  withdraw: true,
17
17
  claimReward: false
18
18
  };
19
+ static generateSlug(symbol, chain) {
20
+ return `${symbol}___native_staking___${chain}`;
21
+ }
19
22
  constructor(state, chain) {
20
23
  super(state, chain);
21
24
  const _chainAsset = this.nativeToken;
@@ -651,8 +651,15 @@ export default class RelayNativeStakingPoolHandler extends BaseNativeStakingPool
651
651
  async handleYieldWithdraw(address, unstakingInfo) {
652
652
  const chainApi = await this.substrateApi.isReady;
653
653
  if (chainApi.api.tx.staking.withdrawUnbonded.meta.args.length === 1) {
654
- const _slashingSpans = (await chainApi.api.query.staking.slashingSpans(address)).toHuman();
655
- const slashingSpanCount = _slashingSpans !== null ? _slashingSpans.spanIndex : '0';
654
+ let slashingSpanCount;
655
+ if (chainApi.api.query.staking.nominatorSlashInEra) {
656
+ const currentEra = await chainApi.api.query.staking.currentEra();
657
+ const slashingSpans = (await chainApi.api.query.staking.nominatorSlashInEra(currentEra.toPrimitive(), address)).toPrimitive();
658
+ slashingSpanCount = slashingSpans !== null ? slashingSpans.toString() : '0';
659
+ } else {
660
+ const _slashingSpans = (await chainApi.api.query.staking.slashingSpans(address)).toHuman();
661
+ slashingSpanCount = _slashingSpans !== null ? _slashingSpans.spanIndex : '0';
662
+ }
656
663
  return chainApi.api.tx.staking.withdrawUnbonded(slashingSpanCount);
657
664
  } else {
658
665
  // @ts-ignore
@@ -12,6 +12,7 @@ export default class NominationPoolHandler extends BasePoolHandler {
12
12
  protected readonly shortName: string;
13
13
  slug: string;
14
14
  protected readonly availableMethod: YieldPoolMethodInfo;
15
+ static generateSlug(symbol: string, chain: string): string;
15
16
  constructor(state: KoniState, chain: string);
16
17
  protected getDescription(amount?: string): string;
17
18
  subscribePoolInfo(callback: (data: YieldPoolInfo) => void): Promise<VoidFunction>;
@@ -22,6 +22,9 @@ export default class NominationPoolHandler extends BasePoolHandler {
22
22
  withdraw: true,
23
23
  claimReward: true
24
24
  };
25
+ static generateSlug(symbol, chain) {
26
+ return `${symbol}___nomination_pool___${chain}`;
27
+ }
25
28
  constructor(state, chain) {
26
29
  super(state, chain);
27
30
  const _chainAsset = this.nativeToken;
@@ -79,7 +82,8 @@ export default class NominationPoolHandler extends BasePoolHandler {
79
82
  const maxUnlockingChunks = substrateApi.api.consts.staking.maxUnlockingChunks.toString();
80
83
  const unlockingEras = substrateApi.api.consts.staking.bondingDuration.toString();
81
84
  const maxSupportedEras = substrateApi.api.consts.staking.historyDepth.toString();
82
- const erasPerDay = 24 / _STAKING_ERA_LENGTH_MAP[chainInfo.slug]; // Can be exactly calculate from epochDuration, blockTime, sessionsPerEra
85
+ const eraInHours = _STAKING_ERA_LENGTH_MAP[chainInfo.slug] || _STAKING_ERA_LENGTH_MAP.default; // in hours
86
+ const erasPerDay = 24 / eraInHours; // Can be exactly calculate from epochDuration, blockTime, sessionsPerEra
83
87
 
84
88
  const supportedDays = getSupportedDaysByHistoryDepth(erasPerDay, parseInt(maxSupportedEras), parseInt(currentEra) / erasPerDay);
85
89
  const startEra = parseInt(currentEra) - supportedDays * erasPerDay;
@@ -560,8 +564,7 @@ export default class NominationPoolHandler extends BasePoolHandler {
560
564
  async handleYieldWithdraw(address, unstakingInfo) {
561
565
  const chainApi = await this.substrateApi.isReady;
562
566
  if (chainApi.api.tx.nominationPools.withdrawUnbonded.meta.args.length === 2) {
563
- const _slashingSpans = (await chainApi.api.query.staking.slashingSpans(address)).toHuman();
564
- const slashingSpanCount = _slashingSpans !== null ? _slashingSpans.spanIndex : '0';
567
+ const slashingSpanCount = await chainApi.api.call.nominationPoolsApi.memberPendingSlash(address);
565
568
  return chainApi.api.tx.nominationPools.withdrawUnbonded({
566
569
  Id: address
567
570
  }, slashingSpanCount);
@@ -12,6 +12,7 @@ export default class EarningService implements StoppableServiceInterface, Persis
12
12
  protected readonly state: KoniState;
13
13
  protected handlers: Record<string, BasePoolHandler>;
14
14
  private handlerCache;
15
+ private inactivePoolSlug;
15
16
  private earningRewardSubject;
16
17
  private earningRewardHistorySubject;
17
18
  private minAmountPercentSubject;
@@ -21,6 +22,7 @@ export default class EarningService implements StoppableServiceInterface, Persis
21
22
  private dbService;
22
23
  private eventService;
23
24
  private useOnlineCacheOnly;
25
+ private inactivePoolReady;
24
26
  constructor(state: KoniState);
25
27
  disableOnlineCacheOnly(): void;
26
28
  private initHandlers;
@@ -2,15 +2,15 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
4
  import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
5
- import { ChainType, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
5
+ import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
6
6
  import { CRON_REFRESH_CHAIN_STAKING_METADATA, CRON_REFRESH_EARNING_REWARD_HISTORY_INTERVAL, CRON_REFRESH_STAKING_REWARD_FAST_INTERVAL } from '@subwallet/extension-base/constants';
7
7
  import { ServiceStatus } from '@subwallet/extension-base/services/base/types';
8
- import { _isChainEnabled, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils';
8
+ import { _getChainSubstrateTokenSymbol, _isChainEnabled } from '@subwallet/extension-base/services/chain-service/utils';
9
9
  import { _STAKING_CHAIN_GROUP } from '@subwallet/extension-base/services/earning-service/constants';
10
10
  import BaseLiquidStakingPoolHandler from '@subwallet/extension-base/services/earning-service/handlers/liquid-staking/base';
11
11
  import MythosNativeStakingPoolHandler from '@subwallet/extension-base/services/earning-service/handlers/native-staking/mythos';
12
12
  import { BasicTxErrorType, YieldPoolType } from '@subwallet/extension-base/types';
13
- import { addLazy, createPromiseHandler, getAddressesByChainType, removeLazy } from '@subwallet/extension-base/utils';
13
+ import { addLazy, createPromiseHandler, filterAddressByChainInfo, removeLazy } from '@subwallet/extension-base/utils';
14
14
  import { fetchStaticCache } from '@subwallet/extension-base/utils/fetchStaticCache';
15
15
  import { BehaviorSubject } from 'rxjs';
16
16
  import { AcalaLiquidStakingPoolHandler, AmplitudeNativeStakingPoolHandler, AstarNativeStakingPoolHandler, BifrostLiquidStakingPoolHandler, BifrostMantaLiquidStakingPoolHandler, InterlayLendingPoolHandler, NominationPoolHandler, ParallelLiquidStakingPoolHandler, ParaNativeStakingPoolHandler, RelayNativeStakingPoolHandler, StellaSwapLiquidStakingPoolHandler, SubnetTaoStakingPoolHandler, TaoNativeStakingPoolHandler } from "./handlers/index.js";
@@ -23,6 +23,7 @@ const fetchPoolsData = async () => {
23
23
  export default class EarningService {
24
24
  handlers = {};
25
25
  handlerCache = new Map();
26
+ inactivePoolSlug = new Set();
26
27
  earningRewardSubject = new BehaviorSubject({
27
28
  ready: false,
28
29
  data: {}
@@ -36,6 +37,7 @@ export default class EarningService {
36
37
  yieldPositionListSubject = new BehaviorSubject([]); // virtual list of yieldPositionSubject with filter values
37
38
 
38
39
  useOnlineCacheOnly = true;
40
+ inactivePoolReady = createPromiseHandler();
39
41
  constructor(state) {
40
42
  this.state = state;
41
43
  this.dbService = state.dbService;
@@ -53,10 +55,23 @@ export default class EarningService {
53
55
  }
54
56
  }
55
57
  const minAmountPercent = {};
58
+ const ahMapChain = await this.state.chainService.fetchAhMapChain();
56
59
  for (const chain of chains) {
57
60
  const handlers = [];
61
+ const chainInfo = this.state.getChainInfo(chain);
62
+ const symbol = _getChainSubstrateTokenSymbol(chainInfo);
58
63
  if (_STAKING_CHAIN_GROUP.relay.includes(chain)) {
59
- handlers.push(new RelayNativeStakingPoolHandler(this.state, chain));
64
+ if (_STAKING_CHAIN_GROUP.assetHub.includes(chain)) {
65
+ continue;
66
+ }
67
+ const ahChain = ahMapChain[chain];
68
+ if (ahChain) {
69
+ handlers.push(new RelayNativeStakingPoolHandler(this.state, ahChain));
70
+ const relaySlug = RelayNativeStakingPoolHandler.generateSlug(symbol, chain);
71
+ this.inactivePoolSlug.add(relaySlug);
72
+ } else {
73
+ handlers.push(new RelayNativeStakingPoolHandler(this.state, chain));
74
+ }
60
75
  }
61
76
  if (_STAKING_CHAIN_GROUP.para.includes(chain)) {
62
77
  handlers.push(new ParaNativeStakingPoolHandler(this.state, chain));
@@ -77,7 +92,14 @@ export default class EarningService {
77
92
  handlers.push(new MythosNativeStakingPoolHandler(this.state, chain));
78
93
  }
79
94
  if (_STAKING_CHAIN_GROUP.nominationPool.includes(chain)) {
80
- handlers.push(new NominationPoolHandler(this.state, chain));
95
+ const ahChain = ahMapChain[chain];
96
+ if (ahChain) {
97
+ handlers.push(new NominationPoolHandler(this.state, ahChain));
98
+ const relaySlug = NominationPoolHandler.generateSlug(symbol, chain);
99
+ this.inactivePoolSlug.add(relaySlug);
100
+ } else {
101
+ handlers.push(new NominationPoolHandler(this.state, chain));
102
+ }
81
103
  }
82
104
  if (_STAKING_CHAIN_GROUP.liquidStaking.includes(chain)) {
83
105
  if (chain === 'bifrost_dot') {
@@ -110,6 +132,7 @@ export default class EarningService {
110
132
  }
111
133
  minAmountPercent.default = BaseLiquidStakingPoolHandler.defaultMinAmountPercent;
112
134
  this.minAmountPercentSubject.next(minAmountPercent);
135
+ this.inactivePoolReady.resolve();
113
136
 
114
137
  // Emit earning ready
115
138
  this.eventService.emit('earning.ready', true);
@@ -129,7 +152,7 @@ export default class EarningService {
129
152
  next: data => {
130
153
  const activeMap = this.state.getActiveChainInfoMap();
131
154
  const activePositions = Object.values(data).filter(item => {
132
- return !!activeMap[item.chain];
155
+ return !!activeMap[item.chain] && !this.inactivePoolSlug.has(item.slug);
133
156
  });
134
157
  this.yieldPositionListSubject.next(Object.values(activePositions));
135
158
  }
@@ -312,7 +335,9 @@ export default class EarningService {
312
335
  const yieldPoolInfo = {};
313
336
  const existedYieldPoolInfo = await this.dbService.getYieldPools();
314
337
  existedYieldPoolInfo.forEach(info => {
315
- yieldPoolInfo[info.slug] = info;
338
+ if (!this.inactivePoolSlug.has(info.slug)) {
339
+ yieldPoolInfo[info.slug] = info;
340
+ }
316
341
  });
317
342
  this.yieldPoolInfoSubject.next(yieldPoolInfo);
318
343
  }
@@ -347,6 +372,10 @@ export default class EarningService {
347
372
  }
348
373
  async fetchingPoolsInfoOnline() {
349
374
  const onlineData = await fetchPoolsData();
375
+ await this.inactivePoolReady.promise;
376
+ for (const inactiveSlug of this.inactivePoolSlug) {
377
+ delete onlineData[inactiveSlug];
378
+ }
350
379
  Object.values(onlineData).forEach(item => {
351
380
  this.updateYieldPoolInfo(item);
352
381
  });
@@ -389,14 +418,11 @@ export default class EarningService {
389
418
  async subscribePoolPositions(addresses, callback) {
390
419
  let cancel = false;
391
420
  await this.eventService.waitChainReady;
392
- const evmAddresses = getAddressesByChainType(addresses, [ChainType.EVM]);
393
- const substrateAddresses = getAddressesByChainType(addresses, [ChainType.SUBSTRATE]);
394
421
  const activeChains = this.state.activeChainSlugs;
395
422
  const unsubList = [];
396
423
  for (const handler of Object.values(this.handlers)) {
397
424
  if (activeChains.includes(handler.chain)) {
398
- const chainInfo = handler.chainInfo;
399
- const useAddresses = _isChainEvmCompatible(chainInfo) ? evmAddresses : substrateAddresses;
425
+ const [useAddresses] = filterAddressByChainInfo(addresses, handler.chainInfo);
400
426
  handler.subscribePoolPosition(useAddresses, callback).then(unsub => {
401
427
  if (cancel) {
402
428
  unsub();
@@ -442,7 +468,9 @@ export default class EarningService {
442
468
  const existedYieldPosition = await this.dbService.getYieldNominationPoolPosition(addresses, this.state.activeChainSlugs);
443
469
  const yieldPositionInfo = this.yieldPositionSubject.getValue();
444
470
  existedYieldPosition.forEach(item => {
445
- yieldPositionInfo[this._getYieldPositionKey(item.slug, item.address)] = item;
471
+ if (!this.inactivePoolSlug.has(item.slug)) {
472
+ yieldPositionInfo[this._getYieldPositionKey(item.slug, item.address)] = item;
473
+ }
446
474
  });
447
475
  this.yieldPositionSubject.next(yieldPositionInfo);
448
476
  }
@@ -533,14 +561,11 @@ export default class EarningService {
533
561
  async getPoolReward(addresses, callback) {
534
562
  let cancel = false;
535
563
  await this.eventService.waitChainReady;
536
- const evmAddresses = getAddressesByChainType(addresses, [ChainType.EVM]);
537
- const substrateAddresses = getAddressesByChainType(addresses, [ChainType.SUBSTRATE]);
538
564
  const activeChains = this.state.activeChainSlugs;
539
565
  const unsubList = [];
540
566
  for (const handler of Object.values(this.handlers)) {
541
567
  if (activeChains.includes(handler.chain)) {
542
- const chainInfo = handler.chainInfo;
543
- const useAddresses = _isChainEvmCompatible(chainInfo) ? evmAddresses : substrateAddresses;
568
+ const [useAddresses] = filterAddressByChainInfo(addresses, handler.chainInfo);
544
569
  handler.getPoolReward(useAddresses, callback).then(unsub => {
545
570
  if (cancel) {
546
571
  unsub();
@@ -589,14 +614,11 @@ export default class EarningService {
589
614
  async fetchPoolRewardHistory(addresses, callback) {
590
615
  let cancel = false;
591
616
  await this.eventService.waitChainReady;
592
- const evmAddresses = getAddressesByChainType(addresses, [ChainType.EVM]);
593
- const substrateAddresses = getAddressesByChainType(addresses, [ChainType.SUBSTRATE]);
594
617
  const activeChains = this.state.activeChainSlugs;
595
618
  const unsubList = [];
596
619
  for (const handler of Object.values(this.handlers)) {
597
620
  if (activeChains.includes(handler.chain)) {
598
- const chainInfo = handler.chainInfo;
599
- const useAddresses = _isChainEvmCompatible(chainInfo) ? evmAddresses : substrateAddresses;
621
+ const [useAddresses] = filterAddressByChainInfo(addresses, handler.chainInfo);
600
622
  handler.getPoolRewardHistory(useAddresses, callback).then(unsub => {
601
623
  if (cancel) {
602
624
  unsub();
@@ -2,6 +2,7 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
4
  import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants';
5
+ import { AccountProxyType } from '@subwallet/extension-base/types';
5
6
  import { combineAccountsWithKeyPair, convertAccountProxyType, createPromiseHandler, transformAccount } from '@subwallet/extension-base/utils';
6
7
  import { generateRandomString } from '@subwallet/extension-base/utils/getId';
7
8
  import { createPair } from '@subwallet/keyring';
@@ -307,7 +308,7 @@ export class AccountJsonHandler extends AccountBaseHandler {
307
308
  const _proxyIds = proxyIds || Object.keys(_account);
308
309
  const modifyPairs = Object.fromEntries(Object.entries(_modifyPair).filter(([, modifyPair]) => _proxyIds.includes(modifyPair.accountProxyId || '')));
309
310
  const accountProxies = Object.fromEntries(Object.entries(_accountProxy).filter(([, proxy]) => _proxyIds.includes(proxy.id)));
310
- const addresses = Object.values(_account).filter(account => _proxyIds.includes(account.id)).flatMap(proxy => proxy.accounts.map(account => account.address));
311
+ const addresses = Object.values(_account).filter(account => _proxyIds.includes(account.id) && account.accountType !== AccountProxyType.LEDGER).flatMap(proxy => proxy.accounts.map(account => account.address));
311
312
  const rs = await keyring.backupAccounts(password, addresses);
312
313
  if (Object.keys(modifyPairs).length && Object.keys(accountProxies).length) {
313
314
  rs.accountProxies = accountProxies;
@@ -95,6 +95,7 @@ export class AccountLedgerHandler extends AccountBaseHandler {
95
95
  isEthereum,
96
96
  isGeneric,
97
97
  isLedgerRecovery,
98
+ isSubstrateECDSA,
98
99
  name,
99
100
  originGenesisHash
100
101
  } = account;
@@ -106,9 +107,13 @@ export class AccountLedgerHandler extends AccountBaseHandler {
106
107
  genesisHash,
107
108
  originGenesisHash,
108
109
  isGeneric,
109
- isLedgerRecovery
110
+ isLedgerRecovery,
111
+ isSubstrateECDSA
110
112
  };
111
- const type = isEthereum ? 'ethereum' : 'sr25519';
113
+ let type = 'sr25519';
114
+ if (isEthereum || isSubstrateECDSA) {
115
+ type = 'ethereum';
116
+ }
112
117
  const pair = keyring.keyring.createFromAddress(address, {
113
118
  ...baseMeta,
114
119
  isExternal: true,
@@ -18,6 +18,7 @@ export default class AuthRequestHandler {
18
18
  private init;
19
19
  private migrateAuthUrlInfoToUnified;
20
20
  private getAddressList;
21
+ private getEcdsaAddressList;
21
22
  get numAuthRequestsV2(): number;
22
23
  private get allAuthRequestsV2();
23
24
  private updateIconAuthV2;
@@ -47,6 +47,9 @@ export default class AuthRequestHandler {
47
47
  } else if (!value.currentNetworkMap) {
48
48
  value.currentNetworkMap = {};
49
49
  }
50
+ if (existKeyBothConnectAuthType) {
51
+ value.canConnectSubstrateEcdsa = true;
52
+ }
50
53
  acc[key] = {
51
54
  ...value
52
55
  };
@@ -81,6 +84,18 @@ export default class AuthRequestHandler {
81
84
  [v]: value
82
85
  }), {});
83
86
  }
87
+ getEcdsaAddressList() {
88
+ const addressList = Object.keys(this.keyringService.context.pairs);
89
+ const pairs = this.keyringService.context.pairs;
90
+ const ecdsaAddressList = new Set();
91
+ addressList.forEach(address => {
92
+ const pair = pairs[address];
93
+ if (pair && pair.json.meta.isSubstrateECDSA) {
94
+ ecdsaAddressList.add(address);
95
+ }
96
+ });
97
+ return ecdsaAddressList;
98
+ }
84
99
  get numAuthRequestsV2() {
85
100
  return Object.keys(this.#authRequestsV2).length;
86
101
  }
@@ -188,6 +203,7 @@ export default class AuthRequestHandler {
188
203
  }
189
204
  authCompleteV2 = (id, url, resolve, reject) => {
190
205
  const isAllowedMap = this.getAddressList();
206
+ const ecdsaAddressList = this.getEcdsaAddressList();
191
207
  const complete = (result, cb, accounts) => {
192
208
  const isAllowed = result === true;
193
209
  let isCancelled = false;
@@ -208,6 +224,7 @@ export default class AuthRequestHandler {
208
224
  idStr,
209
225
  request: {
210
226
  allowedAccounts,
227
+ canConnectSubstrateEcdsa,
211
228
  origin
212
229
  },
213
230
  url
@@ -215,10 +232,9 @@ export default class AuthRequestHandler {
215
232
 
216
233
  // Note: accountAuthTypes represents the accountAuthType of this request
217
234
  // allowedAccounts is a list of connected accounts that exist for this origin during this request.
218
-
219
235
  if (accountAuthTypes.length !== ALL_ACCOUNT_AUTH_TYPES.length) {
220
236
  const backupAllowed = (allowedAccounts || []).filter(a => {
221
- if (isEthereumAddress(a) && !accountAuthTypes.includes('evm')) {
237
+ if (isEthereumAddress(a) && (canConnectSubstrateEcdsa || !ecdsaAddressList.has(a)) && !accountAuthTypes.includes('evm')) {
222
238
  return true;
223
239
  }
224
240
  if (isSubstrateAddress(a) && !accountAuthTypes.includes('substrate')) {
@@ -281,7 +297,8 @@ export default class AuthRequestHandler {
281
297
  currentNetworkMap: existed ? {
282
298
  ...defaultNetworkMap,
283
299
  ...existed.currentNetworkMap
284
- } : defaultNetworkMap
300
+ } : defaultNetworkMap,
301
+ canConnectSubstrateEcdsa: canConnectSubstrateEcdsa || (existed === null || existed === void 0 ? void 0 : existed.canConnectSubstrateEcdsa)
285
302
  };
286
303
  this.setAuthorize(authorizeList, () => {
287
304
  cb();
@@ -312,6 +329,7 @@ export default class AuthRequestHandler {
312
329
  const idStr = stripUrl(url);
313
330
  const isAllowedDappConnectBothType = !!DAPP_CONNECT_BOTH_TYPE_ACCOUNT_URL.find(url_ => url.includes(url_));
314
331
  let accountAuthTypes = [...new Set(isAllowedDappConnectBothType ? ['evm', 'substrate'] : request.accountAuthTypes || ['substrate'])];
332
+ let canConnectSubstrateEcdsa = !!request.canConnectSubstrateEcdsa || isAllowedDappConnectBothType;
315
333
  if (!authList) {
316
334
  authList = {};
317
335
  }
@@ -344,6 +362,9 @@ export default class AuthRequestHandler {
344
362
  if (accountAuthTypes && _request.accountAuthTypes) {
345
363
  const filteredAccountAuthTypes = new Set([..._request.accountAuthTypes, ...accountAuthTypes]);
346
364
  accountAuthTypes = [...filteredAccountAuthTypes];
365
+ if (_request.request.canConnectSubstrateEcdsa) {
366
+ canConnectSubstrateEcdsa = true;
367
+ }
347
368
  }
348
369
  mergeKeys.push(key);
349
370
  }
@@ -372,9 +393,10 @@ export default class AuthRequestHandler {
372
393
  }
373
394
  request.allowedAccounts = Object.entries(existedAuth.isAllowedMap).map(([address, allowed]) => allowed ? address : '').filter(item => item !== '');
374
395
  let allowedListByRequestType = [...request.allowedAccounts];
396
+ const ecdsaAddressList = this.getEcdsaAddressList();
375
397
  allowedListByRequestType = accountAuthTypes.reduce((list, accountAuthType) => {
376
398
  if (accountAuthType === 'evm') {
377
- list.push(...allowedListByRequestType.filter(a => isEthereumAddress(a)));
399
+ list.push(...allowedListByRequestType.filter(a => isEthereumAddress(a) && (canConnectSubstrateEcdsa || !ecdsaAddressList.has(a))));
378
400
  } else if (accountAuthType === 'substrate') {
379
401
  list.push(...allowedListByRequestType.filter(a => isSubstrateAddress(a)));
380
402
  } else if (accountAuthType === 'ton') {
@@ -405,7 +427,8 @@ export default class AuthRequestHandler {
405
427
  origin,
406
428
  url,
407
429
  accountAuthTypes: ALL_ACCOUNT_AUTH_TYPES,
408
- currentNetworkMap: {}
430
+ currentNetworkMap: {},
431
+ canConnectSubstrateEcdsa
409
432
  };
410
433
  this.setAuthorize(authList);
411
434
  return true;
@@ -417,7 +440,8 @@ export default class AuthRequestHandler {
417
440
  idStr,
418
441
  request: {
419
442
  ...request,
420
- accountAuthTypes
443
+ accountAuthTypes,
444
+ canConnectSubstrateEcdsa
421
445
  },
422
446
  url,
423
447
  accountAuthTypes: accountAuthTypes || ['substrate']
@@ -21,6 +21,7 @@ export interface AuthUrlInfo {
21
21
  isAllowedMap: Record<string, boolean>;
22
22
  currentNetworkMap: Partial<Record<AccountAuthType, string>>;
23
23
  currentAccount?: string;
24
+ canConnectSubstrateEcdsa?: boolean;
24
25
  }
25
26
  export interface AuthUrlInfoNeedMigration extends Omit<AuthUrlInfo, 'accountAuthTypes'> {
26
27
  accountAuthType?: AccountAuthType | 'both';
@@ -1,6 +1,9 @@
1
+ import { ActionType } from '@subwallet/extension-base/core/types';
1
2
  export interface RequestInputAccountSubscribe {
2
3
  data: string;
3
4
  chain: string;
5
+ token?: string;
6
+ actionType?: ActionType;
4
7
  }
5
8
  export declare enum AnalyzedGroup {
6
9
  WALLET = "wallet",
@@ -54,6 +54,8 @@ export interface AccountLedgerData {
54
54
  availableGenesisHashes?: string[];
55
55
  /** Is Ledger recovery chain */
56
56
  isLedgerRecovery?: boolean;
57
+ /** Is Ledger substrate ECDSA scheme signature */
58
+ isSubstrateECDSA?: boolean;
57
59
  }
58
60
  /**
59
61
  * @interface AccountInjectData
@@ -103,6 +105,7 @@ export declare enum AccountSignMode {
103
105
  QR = "qr",
104
106
  LEGACY_LEDGER = "legacy-ledger",
105
107
  GENERIC_LEDGER = "generic-ledger",
108
+ ECDSA_SUBSTRATE_LEDGER = "ecdsa-substrate-ledger",
106
109
  READ_ONLY = "readonly",
107
110
  ALL_ACCOUNT = "all",
108
111
  INJECTED = "injected",
@@ -54,6 +54,7 @@ export let AccountSignMode;
54
54
  AccountSignMode["QR"] = "qr";
55
55
  AccountSignMode["LEGACY_LEDGER"] = "legacy-ledger";
56
56
  AccountSignMode["GENERIC_LEDGER"] = "generic-ledger";
57
+ AccountSignMode["ECDSA_SUBSTRATE_LEDGER"] = "ecdsa-substrate-ledger";
57
58
  AccountSignMode["READ_ONLY"] = "readonly";
58
59
  AccountSignMode["ALL_ACCOUNT"] = "all";
59
60
  AccountSignMode["INJECTED"] = "injected";
@@ -31,6 +31,7 @@ export interface RequestSubmitTransfer extends BaseRequestSign, TransactionFee {
31
31
  transferAll: boolean;
32
32
  value: string;
33
33
  transferBounceable?: boolean;
34
+ isSubstrateECDSATransaction?: boolean;
34
35
  }
35
36
  export interface RequestSubmitSignPsbtTransfer extends BaseRequestSign {
36
37
  id: string;
@@ -58,7 +58,7 @@ export const _analyzeAddress = async (data, accountProxies, contacts, chainInfo,
58
58
  for (const accountProxy of accountProxies) {
59
59
  const _name = accountProxy.name.trim().toLowerCase();
60
60
  const nameCondition = isNameValid(_data, _name);
61
- const filterAccounts = accountProxy.accounts.filter(account => _isChainInfoCompatibleWithAccountInfo(chainInfo, account.chainType, account.type));
61
+ const filterAccounts = accountProxy.accounts.filter(account => _isChainInfoCompatibleWithAccountInfo(chainInfo, account));
62
62
  for (const account of filterAccounts) {
63
63
  const addressCondition = isStrValidWithAddress(_data, account, chainInfo);
64
64
  const condition = nameCondition !== 'invalid' ? nameCondition : addressCondition;
@@ -86,7 +86,10 @@ export const _analyzeAddress = async (data, accountProxies, contacts, chainInfo,
86
86
  }
87
87
  }
88
88
  }
89
- const filterContacts = contacts.filter(contact => _isChainInfoCompatibleWithAccountInfo(chainInfo, contact.chainType, getKeypairTypeByAddress(contact.address)));
89
+ const filterContacts = contacts.filter(contact => _isChainInfoCompatibleWithAccountInfo(chainInfo, {
90
+ chainType: contact.chainType,
91
+ type: getKeypairTypeByAddress(contact.address)
92
+ }));
90
93
 
91
94
  // Filter address book addresses
92
95
  for (const contact of filterContacts) {