@subwallet/extension-base 1.3.66-0 → 1.3.68-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 (81) hide show
  1. package/background/KoniTypes.d.ts +12 -1
  2. package/cjs/constants/environment.js +1 -3
  3. package/cjs/constants/index.js +4 -1
  4. package/cjs/core/substrate/system-pallet.js +4 -0
  5. package/cjs/core/substrate/xcm-parser.js +0 -176
  6. package/cjs/koni/api/nft/rari/index.js +1 -1
  7. package/cjs/koni/background/cron.js +16 -0
  8. package/cjs/koni/background/handlers/Extension.js +166 -90
  9. package/cjs/koni/background/handlers/State.js +25 -0
  10. package/cjs/packageInfo.js +1 -1
  11. package/cjs/services/balance-service/helpers/group.js +31 -2
  12. package/cjs/services/balance-service/helpers/subscribe/substrate/index.js +51 -13
  13. package/cjs/services/balance-service/helpers/subscribe/substrate/utils.js +69 -0
  14. package/cjs/services/balance-service/index.js +36 -11
  15. package/cjs/services/balance-service/transfer/smart-contract.js +56 -23
  16. package/cjs/services/balance-service/transfer/xcm/index.js +30 -44
  17. package/cjs/services/balance-service/transfer/xcm/utils.js +53 -18
  18. package/cjs/services/chain-service/constants.js +8 -46
  19. package/cjs/services/chain-service/handler/EvmChainHandler.js +6 -3
  20. package/cjs/services/earning-service/handlers/base.js +7 -1
  21. package/cjs/services/nft-service/index.js +173 -0
  22. package/cjs/services/swap-service/handler/base-handler.js +18 -21
  23. package/cjs/services/transaction-service/index.js +1 -1
  24. package/cjs/types/balance/index.js +26 -1
  25. package/cjs/utils/fee/transfer.js +5 -2
  26. package/cjs/utils/index.js +25 -2
  27. package/cjs/utils/setup-api-sdk.js +0 -5
  28. package/constants/environment.d.ts +0 -1
  29. package/constants/environment.js +0 -1
  30. package/constants/index.d.ts +1 -0
  31. package/constants/index.js +1 -0
  32. package/core/substrate/system-pallet.d.ts +1 -0
  33. package/core/substrate/system-pallet.js +3 -0
  34. package/core/substrate/types.d.ts +14 -0
  35. package/core/substrate/xcm-parser.d.ts +1 -49
  36. package/core/substrate/xcm-parser.js +1 -173
  37. package/koni/api/nft/rari/index.js +1 -1
  38. package/koni/background/cron.d.ts +1 -0
  39. package/koni/background/cron.js +17 -1
  40. package/koni/background/handlers/Extension.d.ts +3 -0
  41. package/koni/background/handlers/Extension.js +88 -14
  42. package/koni/background/handlers/State.d.ts +4 -0
  43. package/koni/background/handlers/State.js +25 -0
  44. package/package.json +16 -21
  45. package/packageInfo.js +1 -1
  46. package/services/balance-service/helpers/group.js +31 -2
  47. package/services/balance-service/helpers/subscribe/substrate/index.js +51 -13
  48. package/services/balance-service/helpers/subscribe/substrate/utils.d.ts +7 -0
  49. package/services/balance-service/helpers/subscribe/substrate/utils.js +58 -0
  50. package/services/balance-service/index.d.ts +4 -2
  51. package/services/balance-service/index.js +26 -6
  52. package/services/balance-service/transfer/smart-contract.d.ts +4 -0
  53. package/services/balance-service/transfer/smart-contract.js +54 -23
  54. package/services/balance-service/transfer/xcm/index.d.ts +2 -2
  55. package/services/balance-service/transfer/xcm/index.js +18 -32
  56. package/services/balance-service/transfer/xcm/utils.d.ts +1 -2
  57. package/services/balance-service/transfer/xcm/utils.js +51 -15
  58. package/services/chain-service/constants.d.ts +5 -24
  59. package/services/chain-service/constants.js +6 -35
  60. package/services/chain-service/handler/EvmChainHandler.js +6 -3
  61. package/services/earning-service/handlers/base.js +7 -1
  62. package/services/nft-service/index.d.ts +9 -0
  63. package/services/nft-service/index.js +165 -0
  64. package/services/swap-service/handler/base-handler.d.ts +0 -1
  65. package/services/swap-service/handler/base-handler.js +19 -22
  66. package/services/transaction-service/index.js +1 -1
  67. package/services/transaction-service/types.d.ts +2 -1
  68. package/types/balance/index.d.ts +14 -0
  69. package/types/balance/index.js +21 -1
  70. package/utils/fee/transfer.js +6 -3
  71. package/utils/index.js +25 -2
  72. package/utils/setup-api-sdk.js +1 -6
  73. package/cjs/services/balance-service/transfer/xcm/polkadotXcm.js +0 -30
  74. package/cjs/services/balance-service/transfer/xcm/xTokens.js +0 -32
  75. package/cjs/services/balance-service/transfer/xcm/xcmPallet.js +0 -23
  76. package/services/balance-service/transfer/xcm/polkadotXcm.d.ts +0 -3
  77. package/services/balance-service/transfer/xcm/polkadotXcm.js +0 -24
  78. package/services/balance-service/transfer/xcm/xTokens.d.ts +0 -3
  79. package/services/balance-service/transfer/xcm/xTokens.js +0 -26
  80. package/services/balance-service/transfer/xcm/xcmPallet.d.ts +0 -3
  81. package/services/balance-service/transfer/xcm/xcmPallet.js +0 -17
@@ -47,7 +47,7 @@ import { DEFAULT_AUTO_LOCK_TIME } from '@subwallet/extension-base/services/setti
47
47
  import { isProposalExpired, isSupportWalletConnectChain, isSupportWalletConnectNamespace } from '@subwallet/extension-base/services/wallet-connect-service/helpers';
48
48
  import { SWStorage } from '@subwallet/extension-base/storage';
49
49
  import { AccountsStore } from '@subwallet/extension-base/stores';
50
- import { AccountChainType, AccountSignMode, BasicTxErrorType, BasicTxWarningCode, CommonStepType, EarningProcessType, ProcessType, StakingTxErrorType, StepStatus, SwapFeeType, YieldPoolType, YieldStepType } from '@subwallet/extension-base/types';
50
+ import { AccountChainType, AccountSignMode, BalanceType, BasicTxErrorType, BasicTxWarningCode, CommonStepType, EarningProcessType, ProcessType, StakingTxErrorType, StepStatus, SwapFeeType, YieldPoolType, YieldStepType } from '@subwallet/extension-base/types';
51
51
  import { _analyzeAddress, calculateMaxTransferable, combineAllAccountProxy, combineBitcoinFee, createPromiseHandler, createTransactionFromRLP, detectTransferTxType, filterUneconomicalUtxos, getAccountSignMode, getSizeInfo, getTransferableBitcoinUtxos, isSameAddress, isSubstrateEcdsaLedgerAssetSupported, MODULE_SUPPORT, reformatAddress, signatureToHex, transformAccounts, transformAddresses, uniqueStringArray } from '@subwallet/extension-base/utils';
52
52
  import { parseContractInput, parseEvmRlp } from '@subwallet/extension-base/utils/eth/parseTransaction';
53
53
  import { getId } from '@subwallet/extension-base/utils/getId';
@@ -1144,6 +1144,9 @@ export default class KoniExtension {
1144
1144
  });
1145
1145
  return this.getNft();
1146
1146
  }
1147
+ async handleGetNftFullList(request) {
1148
+ return this.#koniState.nftDetectionService.getFullNftInstancesByCollection(request);
1149
+ }
1147
1150
  getStakingReward() {
1148
1151
  return new Promise((resolve, reject) => {
1149
1152
  this.#koniState.getStakingReward(rs => {
@@ -1644,7 +1647,7 @@ export default class KoniExtension {
1644
1647
  error.length && inputTransaction.errors.push(...error);
1645
1648
  }
1646
1649
  if (isSubstrateXcm) {
1647
- const isDryRunSuccess = await dryRunXcmExtrinsicV2(params);
1650
+ const isDryRunSuccess = await dryRunXcmExtrinsicV2(params, false);
1648
1651
  if (!isDryRunSuccess) {
1649
1652
  inputTransaction.errors.push(new TransactionError(BasicTxErrorType.UNABLE_TO_SEND, 'Unable to perform transaction. Select another token or destination chain and try again'));
1650
1653
  }
@@ -2033,20 +2036,40 @@ export default class KoniExtension {
2033
2036
  var _data$metadata;
2034
2037
  const evmApi = this.#koniState.getEvmApi(data.originChain);
2035
2038
  const contractAddress = (_data$metadata = data.metadata) === null || _data$metadata === void 0 ? void 0 : _data$metadata.contractAddress;
2036
-
2037
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
2038
2039
  const tokenContract = new evmApi.api.eth.Contract(_ERC721_ABI, contractAddress);
2039
2040
  try {
2040
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
2041
- await tokenContract.methods.tokenOfOwnerByIndex('0xB7fdD27a8Df011816205a6e3cAA097DC4D8C2C5d', 1).call();
2042
- return true;
2043
- } catch (err) {
2044
- const error = err;
2045
- if (error.message.includes('index out of bounds')) {
2046
- return true;
2047
- } else {
2041
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
2042
+ const supports1155 = await tokenContract.methods.supportsInterface('0xd9b67a26').call().catch(() => false);
2043
+ if (supports1155) {
2048
2044
  return false;
2049
2045
  }
2046
+
2047
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment
2048
+ const supports721 = await tokenContract.methods.supportsInterface('0x80ac58cd').call().catch(() => false);
2049
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment
2050
+ const supportsMetadata = await tokenContract.methods.supportsInterface('0x5b5e139f').call().catch(() => false);
2051
+ if (supports721 || supportsMetadata) {
2052
+ return true;
2053
+ }
2054
+
2055
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
2056
+ if (tokenContract.methods.ownerOf) {
2057
+ try {
2058
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
2059
+ await tokenContract.methods.ownerOf(1).call();
2060
+ return true;
2061
+ } catch (err) {
2062
+ var _err$message, _err$message2;
2063
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
2064
+ if ((_err$message = err.message) !== null && _err$message !== void 0 && _err$message.includes('nonexistent token') || (_err$message2 = err.message) !== null && _err$message2 !== void 0 && _err$message2.includes('invalid token ID')) {
2065
+ return true;
2066
+ }
2067
+ }
2068
+ }
2069
+ return false;
2070
+ } catch (err) {
2071
+ const error = err;
2072
+ return error.message.includes('index out of bounds');
2050
2073
  }
2051
2074
  }
2052
2075
  async upsertCustomToken(data) {
@@ -2102,6 +2125,21 @@ export default class KoniExtension {
2102
2125
  }
2103
2126
  return await this.#koniState.balanceService.getTransferableBalance(address, networkKey, token, extrinsicType);
2104
2127
  }
2128
+ async getAddressAvailableBalanceByType({
2129
+ address,
2130
+ balanceType,
2131
+ extrinsicType,
2132
+ networkKey,
2133
+ token
2134
+ }) {
2135
+ if (token && _MANTA_ZK_CHAIN_GROUP.includes(networkKey)) {
2136
+ const tokenInfo = this.#koniState.chainService.getAssetBySlug(token);
2137
+ if (tokenInfo.symbol.startsWith(_ZK_ASSET_PREFIX)) {
2138
+ return await this.#koniState.getMantaPayZkBalance(address, tokenInfo);
2139
+ }
2140
+ }
2141
+ return await this.#koniState.balanceService.getBalanceByType(address, networkKey, token, balanceType, extrinsicType);
2142
+ }
2105
2143
  async getAddressTotalBalance({
2106
2144
  address,
2107
2145
  extrinsicType,
@@ -2173,7 +2211,7 @@ export default class KoniExtension {
2173
2211
  });
2174
2212
  const [unsubBalance, freeBalance] = await (async () => {
2175
2213
  try {
2176
- return await this.#koniState.balanceService.subscribeBalance(address, chain, token, 'transferable', extrinsicType, data => {
2214
+ return await this.#koniState.balanceService.subscribeBalance(address, chain, token, BalanceType.TRANSFERABLE, extrinsicType, data => {
2177
2215
  freeBalanceSubject.next(data); // Must be called after subscription
2178
2216
  });
2179
2217
  } catch (e) {
@@ -2311,7 +2349,7 @@ export default class KoniExtension {
2311
2349
  convertData(freeBalance, fee, _feeOptions, feeCustom).then(cb).catch(console.error);
2312
2350
  }
2313
2351
  });
2314
- const [unsubBalance, freeBalance] = await this.#koniState.balanceService.subscribeBalance(address, chain, token, 'transferable', ExtrinsicType.TRANSFER_BALANCE, data => {
2352
+ const [unsubBalance, freeBalance] = await this.#koniState.balanceService.subscribeBalance(address, chain, token, BalanceType.TRANSFERABLE, ExtrinsicType.TRANSFER_BALANCE, data => {
2315
2353
  freeBalanceSubject.next(data); // Must be called after subscription
2316
2354
  });
2317
2355
 
@@ -2354,6 +2392,31 @@ export default class KoniExtension {
2354
2392
  });
2355
2393
  return convertData(currentFreeBalance);
2356
2394
  }
2395
+ async subscribeAddressAvailableBalanceByType({
2396
+ address,
2397
+ balanceType,
2398
+ extrinsicType,
2399
+ networkKey,
2400
+ token
2401
+ }, id, port) {
2402
+ const cb = createSubscription(id, port);
2403
+ const convertData = data => {
2404
+ return {
2405
+ ...data,
2406
+ id
2407
+ };
2408
+ };
2409
+ const _cb = data => {
2410
+ // eslint-disable-next-line node/no-callback-literal
2411
+ cb(convertData(data));
2412
+ };
2413
+ const [unsub, currentFreeBalance] = await this.#koniState.balanceService.subscribeBalanceByType(address, networkKey, token, balanceType, extrinsicType, _cb);
2414
+ this.createUnsubscriptionHandle(id, unsub);
2415
+ port.onDisconnect.addListener(() => {
2416
+ this.cancelSubscription(id);
2417
+ });
2418
+ return convertData(currentFreeBalance);
2419
+ }
2357
2420
  async substrateNftSubmitTransaction(inputData) {
2358
2421
  const {
2359
2422
  params,
@@ -3799,6 +3862,10 @@ export default class KoniExtension {
3799
3862
  });
3800
3863
  }
3801
3864
  }
3865
+ let balanceTypeForPool = BalanceType.TRANSFERABLE;
3866
+ if (!!poolHandler && [YieldPoolType.NATIVE_STAKING, YieldPoolType.NOMINATION_POOL].includes(poolHandler.type)) {
3867
+ balanceTypeForPool = BalanceType.TOTAL_MINUS_RESERVED;
3868
+ }
3802
3869
  return await this.#koniState.transactionService.handleTransaction({
3803
3870
  address,
3804
3871
  chain: txChain,
@@ -3810,6 +3877,7 @@ export default class KoniExtension {
3810
3877
  chainType,
3811
3878
  resolveOnDone: !isLastStep,
3812
3879
  transferNativeAmount,
3880
+ balanceType: balanceTypeForPool,
3813
3881
  skipFeeValidation: isMintingStep && isPoolSupportAlternativeFee,
3814
3882
  errorOnTimeOut,
3815
3883
  ...this.createPassConfirmationParams(isPassConfirmation),
@@ -4807,6 +4875,8 @@ export default class KoniExtension {
4807
4875
  return await this.getNftCollection();
4808
4876
  case 'pri(nftCollection.getSubscription)':
4809
4877
  return await this.subscribeNftCollection(id, port);
4878
+ case 'pri(nft.getFullList)':
4879
+ return await this.handleGetNftFullList(request);
4810
4880
  case 'pri(staking.getStaking)':
4811
4881
  return this.getStaking();
4812
4882
  case 'pri(staking.getSubscription)':
@@ -5015,6 +5085,10 @@ export default class KoniExtension {
5015
5085
  return this.getAddressTransferableBalance(request);
5016
5086
  case 'pri(freeBalance.subscribe)':
5017
5087
  return this.subscribeAddressTransferableBalance(request, id, port);
5088
+ case 'pri(availableBalance.getBalanceByType)':
5089
+ return this.getAddressAvailableBalanceByType(request);
5090
+ case 'pri(availableBalance.subscribeBalanceByType)':
5091
+ return this.subscribeAddressAvailableBalanceByType(request, id, port);
5018
5092
  case 'pri(subscription.cancel)':
5019
5093
  return this.cancelSubscription(request);
5020
5094
  case 'pri(chainService.recoverSubstrateApi)':
@@ -19,6 +19,7 @@ import { KeyringService } from '@subwallet/extension-base/services/keyring-servi
19
19
  import MigrationService from '@subwallet/extension-base/services/migration-service';
20
20
  import MintCampaignService from '@subwallet/extension-base/services/mint-campaign-service';
21
21
  import MktCampaignService from '@subwallet/extension-base/services/mkt-campaign-service';
22
+ import NftService from '@subwallet/extension-base/services/nft-service';
22
23
  import NotificationService from '@subwallet/extension-base/services/notification-service/NotificationService';
23
24
  import { PriceService } from '@subwallet/extension-base/services/price-service';
24
25
  import RequestService from '@subwallet/extension-base/services/request-service';
@@ -73,6 +74,7 @@ export default class KoniState {
73
74
  readonly mintCampaignService: MintCampaignService;
74
75
  readonly campaignService: CampaignService;
75
76
  readonly mktCampaignService: MktCampaignService;
77
+ readonly nftDetectionService: NftService;
76
78
  readonly buyService: BuyService;
77
79
  readonly earningService: EarningService;
78
80
  readonly feeService: FeeService;
@@ -133,6 +135,8 @@ export default class KoniState {
133
135
  resetNft(newAddress: string): void;
134
136
  updateNftData(network: string, nftData: NftItem, address: string, callback?: (nftData: NftItem) => void): void;
135
137
  deleteNftCollection(chain: string, collectionId: string): Promise<void>;
138
+ handleDetectedNfts(address: string, nftItems: NftItem[]): Promise<void>;
139
+ handleDetectedNftCollections(collections: NftCollection[]): Promise<void>;
136
140
  cleanUpNfts(chain: string, owner: string, collectionId: string[], nftIds: string[], ownNothing?: boolean): void;
137
141
  getNft(): Promise<NftJson | undefined>;
138
142
  subscribeNft(): Subject<NftJson>;
@@ -28,6 +28,7 @@ import { KeyringService } from '@subwallet/extension-base/services/keyring-servi
28
28
  import MigrationService from '@subwallet/extension-base/services/migration-service';
29
29
  import MintCampaignService from '@subwallet/extension-base/services/mint-campaign-service';
30
30
  import MktCampaignService from '@subwallet/extension-base/services/mkt-campaign-service';
31
+ import NftService from '@subwallet/extension-base/services/nft-service';
31
32
  import NotificationService from '@subwallet/extension-base/services/notification-service/NotificationService';
32
33
  import { PriceService } from '@subwallet/extension-base/services/price-service';
33
34
  import RequestService from '@subwallet/extension-base/services/request-service';
@@ -112,6 +113,7 @@ export default class KoniState {
112
113
  this.migrationService = new MigrationService(this, this.eventService);
113
114
  this.campaignService = new CampaignService(this);
114
115
  this.mktCampaignService = new MktCampaignService(this);
116
+ this.nftDetectionService = new NftService(this);
115
117
  this.buyService = new BuyService(this);
116
118
  this.earningService = new EarningService(this);
117
119
  this.swapService = new SwapService(this);
@@ -393,6 +395,29 @@ export default class KoniState {
393
395
  deleteNftCollection(chain, collectionId) {
394
396
  return this.dbService.deleteNftCollection(chain, collectionId);
395
397
  }
398
+ async handleDetectedNfts(address, nftItems) {
399
+ try {
400
+ const chainSlugs = this.activeChainSlugs;
401
+ const currentNfts = await this.dbService.getNft([address], chainSlugs);
402
+ const newNfts = nftItems.filter(n => !currentNfts.some(c => c.id === n.id));
403
+ for (const nft of newNfts) {
404
+ this.updateNftData(nft.chain, nft, address);
405
+ }
406
+ } catch (e) {
407
+ this.logger.warn('handleDetectedNfts error:', e);
408
+ }
409
+ }
410
+ async handleDetectedNftCollections(collections) {
411
+ try {
412
+ const currentCollections = await this.getNftCollection();
413
+ const newCollections = collections.filter(col => !currentCollections.some(c => c.collectionId === col.collectionId && c.chain === col.chain));
414
+ for (const col of newCollections) {
415
+ this.setNftCollection(col.chain, col);
416
+ }
417
+ } catch (e) {
418
+ this.logger.warn('handleDetectedNftCollections error:', e);
419
+ }
420
+ }
396
421
  cleanUpNfts(chain, owner, collectionId, nftIds, ownNothing) {
397
422
  this.dbService.cleanUpNft(chain, owner, collectionId, nftIds, ownNothing).catch(e => this.logger.warn(e));
398
423
  }
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "./cjs/detectPackage.js"
18
18
  ],
19
19
  "type": "module",
20
- "version": "1.3.66-0",
20
+ "version": "1.3.68-0",
21
21
  "main": "./cjs/index.js",
22
22
  "module": "./index.js",
23
23
  "types": "./index.d.ts",
@@ -739,6 +739,11 @@
739
739
  "require": "./cjs/services/balance-service/helpers/subscribe/substrate/gear.js",
740
740
  "default": "./services/balance-service/helpers/subscribe/substrate/gear.js"
741
741
  },
742
+ "./services/balance-service/helpers/subscribe/substrate/utils": {
743
+ "types": "./services/balance-service/helpers/subscribe/substrate/utils.d.ts",
744
+ "require": "./cjs/services/balance-service/helpers/subscribe/substrate/utils.js",
745
+ "default": "./services/balance-service/helpers/subscribe/substrate/utils.js"
746
+ },
742
747
  "./services/balance-service/helpers/subscribe/ton/consts": {
743
748
  "types": "./services/balance-service/helpers/subscribe/ton/consts.d.ts",
744
749
  "require": "./cjs/services/balance-service/helpers/subscribe/ton/consts.js",
@@ -799,11 +804,6 @@
799
804
  "require": "./cjs/services/balance-service/transfer/xcm/availBridge.js",
800
805
  "default": "./services/balance-service/transfer/xcm/availBridge.js"
801
806
  },
802
- "./services/balance-service/transfer/xcm/polkadotXcm": {
803
- "types": "./services/balance-service/transfer/xcm/polkadotXcm.d.ts",
804
- "require": "./cjs/services/balance-service/transfer/xcm/polkadotXcm.js",
805
- "default": "./services/balance-service/transfer/xcm/polkadotXcm.js"
806
- },
807
807
  "./services/balance-service/transfer/xcm/polygonBridge": {
808
808
  "types": "./services/balance-service/transfer/xcm/polygonBridge.d.ts",
809
809
  "require": "./cjs/services/balance-service/transfer/xcm/polygonBridge.js",
@@ -824,16 +824,6 @@
824
824
  "require": "./cjs/services/balance-service/transfer/xcm/utils.js",
825
825
  "default": "./services/balance-service/transfer/xcm/utils.js"
826
826
  },
827
- "./services/balance-service/transfer/xcm/xcmPallet": {
828
- "types": "./services/balance-service/transfer/xcm/xcmPallet.d.ts",
829
- "require": "./cjs/services/balance-service/transfer/xcm/xcmPallet.js",
830
- "default": "./services/balance-service/transfer/xcm/xcmPallet.js"
831
- },
832
- "./services/balance-service/transfer/xcm/xTokens": {
833
- "types": "./services/balance-service/transfer/xcm/xTokens.d.ts",
834
- "require": "./cjs/services/balance-service/transfer/xcm/xTokens.js",
835
- "default": "./services/balance-service/transfer/xcm/xTokens.js"
836
- },
837
827
  "./services/base/types": {
838
828
  "types": "./services/base/types.d.ts",
839
829
  "require": "./cjs/services/base/types.js",
@@ -1721,6 +1711,11 @@
1721
1711
  "require": "./cjs/services/mkt-campaign-service/types.js",
1722
1712
  "default": "./services/mkt-campaign-service/types.js"
1723
1713
  },
1714
+ "./services/nft-service": {
1715
+ "types": "./services/nft-service/index.d.ts",
1716
+ "require": "./cjs/services/nft-service/index.js",
1717
+ "default": "./services/nft-service/index.js"
1718
+ },
1724
1719
  "./services/notification-service/NotificationService": {
1725
1720
  "types": "./services/notification-service/NotificationService.d.ts",
1726
1721
  "require": "./cjs/services/notification-service/NotificationService.js",
@@ -2922,12 +2917,12 @@
2922
2917
  "@snowbridge/registry": "^0.2.0",
2923
2918
  "@sora-substrate/type-definitions": "^1.17.7",
2924
2919
  "@substrate/connect": "^0.8.9",
2925
- "@subwallet-monorepos/subwallet-services-sdk": "0.1.13",
2920
+ "@subwallet-monorepos/subwallet-services-sdk": "0.1.14",
2926
2921
  "@subwallet/chain-list": "0.2.121",
2927
- "@subwallet/extension-base": "^1.3.66-0",
2928
- "@subwallet/extension-chains": "^1.3.66-0",
2929
- "@subwallet/extension-dapp": "^1.3.66-0",
2930
- "@subwallet/extension-inject": "^1.3.66-0",
2922
+ "@subwallet/extension-base": "^1.3.68-0",
2923
+ "@subwallet/extension-chains": "^1.3.68-0",
2924
+ "@subwallet/extension-dapp": "^1.3.68-0",
2925
+ "@subwallet/extension-inject": "^1.3.68-0",
2931
2926
  "@subwallet/keyring": "^0.1.13",
2932
2927
  "@subwallet/ui-keyring": "^0.1.13",
2933
2928
  "@ton/core": "^0.56.3",
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.3.66-0'
10
+ version: '1.3.68-0'
11
11
  };
@@ -13,11 +13,40 @@ import BigN from 'bignumber.js';
13
13
  */
14
14
  export const groupBalance = (items, address, token) => {
15
15
  const states = items.map(item => item.state);
16
+ const sum = selector => BigN.sum.apply(null, items.map(selector)).toFixed();
17
+ const staking = sum(i => {
18
+ var _i$lockedDetails$stak, _i$lockedDetails;
19
+ return (_i$lockedDetails$stak = (_i$lockedDetails = i.lockedDetails) === null || _i$lockedDetails === void 0 ? void 0 : _i$lockedDetails.staking) !== null && _i$lockedDetails$stak !== void 0 ? _i$lockedDetails$stak : '0';
20
+ });
21
+ const governance = sum(i => {
22
+ var _i$lockedDetails$gove, _i$lockedDetails2;
23
+ return (_i$lockedDetails$gove = (_i$lockedDetails2 = i.lockedDetails) === null || _i$lockedDetails2 === void 0 ? void 0 : _i$lockedDetails2.governance) !== null && _i$lockedDetails$gove !== void 0 ? _i$lockedDetails$gove : '0';
24
+ });
25
+ const democracy = sum(i => {
26
+ var _i$lockedDetails$demo, _i$lockedDetails3;
27
+ return (_i$lockedDetails$demo = (_i$lockedDetails3 = i.lockedDetails) === null || _i$lockedDetails3 === void 0 ? void 0 : _i$lockedDetails3.democracy) !== null && _i$lockedDetails$demo !== void 0 ? _i$lockedDetails$demo : '0';
28
+ });
29
+ const reserved = sum(i => {
30
+ var _i$lockedDetails$rese, _i$lockedDetails4;
31
+ return (_i$lockedDetails$rese = (_i$lockedDetails4 = i.lockedDetails) === null || _i$lockedDetails4 === void 0 ? void 0 : _i$lockedDetails4.reserved) !== null && _i$lockedDetails$rese !== void 0 ? _i$lockedDetails$rese : '0';
32
+ });
33
+ const others = sum(i => {
34
+ var _i$lockedDetails$othe, _i$lockedDetails5;
35
+ return (_i$lockedDetails$othe = (_i$lockedDetails5 = i.lockedDetails) === null || _i$lockedDetails5 === void 0 ? void 0 : _i$lockedDetails5.others) !== null && _i$lockedDetails$othe !== void 0 ? _i$lockedDetails$othe : '0';
36
+ });
37
+ const hasLockedDetails = new BigN(staking).gt(0) || new BigN(governance).gt(0) || new BigN(democracy).gt(0) || new BigN(others).gt(0);
16
38
  return {
17
39
  address,
18
40
  tokenSlug: token,
19
- free: BigN.sum.apply(null, items.map(item => item.free)).toFixed(),
20
- locked: BigN.sum.apply(null, items.map(item => item.locked)).toFixed(),
41
+ free: sum(i => i.free),
42
+ locked: sum(i => i.locked),
43
+ lockedDetails: hasLockedDetails ? {
44
+ staking,
45
+ governance,
46
+ democracy,
47
+ reserved,
48
+ others
49
+ } : undefined,
21
50
  state: states.every(item => item === APIItemState.NOT_SUPPORT) ? APIItemState.NOT_SUPPORT : states.some(item => item === APIItemState.READY) ? APIItemState.READY : APIItemState.PENDING
22
51
  };
23
52
  };
@@ -8,7 +8,7 @@ import { _getAssetsPalletLocked, _getAssetsPalletTransferable } from '@subwallet
8
8
  import { _getForeignAssetPalletLockedBalance, _getForeignAssetPalletTransferable } from '@subwallet/extension-base/core/substrate/foreign-asset-pallet';
9
9
  import { _getTotalStakeInNominationPool } from '@subwallet/extension-base/core/substrate/nominationpools-pallet';
10
10
  import { _getOrmlTokensPalletLockedBalance, _getOrmlTokensPalletTransferable } from '@subwallet/extension-base/core/substrate/ormlTokens-pallet';
11
- import { _getSystemPalletTotalBalance, _getSystemPalletTransferable } from '@subwallet/extension-base/core/substrate/system-pallet';
11
+ import { _getSystemPalletReservedBalance, _getSystemPalletTotalBalance, _getSystemPalletTransferable } from '@subwallet/extension-base/core/substrate/system-pallet';
12
12
  import { _getTokensPalletLocked, _getTokensPalletTransferable } from '@subwallet/extension-base/core/substrate/tokens-pallet';
13
13
  import { _adaptX1Interior } from '@subwallet/extension-base/core/substrate/xcm-parser';
14
14
  import { getPSP22ContractPromise } from '@subwallet/extension-base/koni/api/contract-handler/wasm';
@@ -21,6 +21,7 @@ import { timer } from 'rxjs';
21
21
  import { subscribeERC20Interval } from "../evm.js";
22
22
  import { subscribeEquilibriumTokenBalance } from "./equilibrium.js";
23
23
  import { subscribeGRC20Balance, subscribeVftBalance } from "./gear.js";
24
+ import { buildLockedDetails, getSpecialStakingBalances } from "./utils.js";
24
25
  export const subscribeSubstrateBalance = async (addresses, chainInfo, assetMap, substrateApi, evmApi, callback, extrinsicType) => {
25
26
  let unsubNativeToken;
26
27
  let unsubLocalToken;
@@ -109,7 +110,6 @@ export const subscribeSubstrateBalance = async (addresses, chainInfo, assetMap,
109
110
  };
110
111
  };
111
112
 
112
- // handler according to different logic
113
113
  // eslint-disable-next-line @typescript-eslint/require-await
114
114
  const subscribeWithSystemAccountPallet = async ({
115
115
  addresses,
@@ -140,15 +140,10 @@ const subscribeWithSystemAccountPallet = async ({
140
140
  const subscription = substrateApi.subscribeDataWithMulti(params, async rs => {
141
141
  const balances = rs[systemAccountKey];
142
142
  const poolMemberInfos = rs[poolMembersKey];
143
- let bittensorStakingBalances = new Array(addresses.length).fill(new BigN(0));
144
- if (_BALANCE_CHAIN_GROUP.bittensor.includes(chainInfo.slug)) {
145
- const rawData = await substrateApi.api.call.stakeInfoRuntimeApi.getStakeInfoForColdkeys(addresses);
146
- const values = rawData.toPrimitive();
147
- bittensorStakingBalances = values.map(([, stakes]) => {
148
- return stakes.filter(i => i.netuid === 0).reduce((previousValue, currentValue) => previousValue.plus(currentValue.stake), BigN(0));
149
- });
150
- }
151
- const items = balances.map((_balance, index) => {
143
+ const bittensorStakingBalances = await getSpecialStakingBalances(chainInfo, addresses, substrateApi);
144
+
145
+ // Precompute totalLockedFromTransfer for each account to decide if need fetch locks/holds
146
+ const preItems = balances.map((_balance, index) => {
152
147
  const balanceInfo = _balance;
153
148
  const transferableBalance = _getSystemPalletTransferable(balanceInfo, _getChainExistentialDeposit(chainInfo), extrinsicType);
154
149
  const totalBalance = _getSystemPalletTotalBalance(balanceInfo);
@@ -158,14 +153,57 @@ const subscribeWithSystemAccountPallet = async ({
158
153
  const nominationPoolBalance = poolMemberInfo ? _getTotalStakeInNominationPool(poolMemberInfo) : BigInt(0);
159
154
  totalLockedFromTransfer += nominationPoolBalance;
160
155
  }
161
- const stakeValue = BigInt(bittensorStakingBalances[index].toString());
162
- totalLockedFromTransfer += stakeValue;
156
+ totalLockedFromTransfer += BigInt(bittensorStakingBalances[index].toString());
157
+ return {
158
+ index,
159
+ totalLockedFromTransfer,
160
+ balanceInfo
161
+ };
162
+ });
163
+
164
+ // Filter account's locked > 0
165
+ const accountsWithLocks = preItems.filter(i => i.totalLockedFromTransfer > 0).map(i => addresses[i.index]);
166
+ let locks = [];
167
+ let holds = [];
168
+ let freezes = [];
169
+
170
+ // Fetch locks/holds only for accounts that have locked balances
171
+ if (accountsWithLocks.length > 0) {
172
+ const [rawLocks, rawHolds, rawFreezes] = await Promise.all([substrateApi.api.query.balances.locks.multi(accountsWithLocks), substrateApi.api.query.balances.holds.multi(accountsWithLocks), substrateApi.api.query.balances.freezes.multi(accountsWithLocks)]);
173
+ locks = rawLocks.map(lockArr => lockArr.map(l => ({
174
+ id: l.id.toPrimitive(),
175
+ amount: l.amount.toString()
176
+ })));
177
+ holds = rawHolds.map(holdArr => holdArr.map(h => ({
178
+ id: h.id.toPrimitive(),
179
+ amount: h.amount.toString()
180
+ })));
181
+ freezes = rawFreezes.map(freezeArr => freezeArr.map(f => ({
182
+ id: f.id.toPrimitive(),
183
+ amount: f.amount.toString()
184
+ })));
185
+ }
186
+
187
+ // Map locks/holds back to original index
188
+ const items = preItems.map(({
189
+ balanceInfo,
190
+ index,
191
+ totalLockedFromTransfer
192
+ }) => {
193
+ const lockIndex = accountsWithLocks.indexOf(addresses[index]);
194
+ const lockItems = lockIndex >= 0 ? locks[lockIndex] || [] : [];
195
+ const holdItems = lockIndex >= 0 ? holds[lockIndex] || [] : [];
196
+ const freezeItems = lockIndex >= 0 ? freezes[lockIndex] || [] : [];
197
+ const allLockEntries = [...lockItems, ...holdItems, ...freezeItems];
198
+ const lockedDetails = buildLockedDetails(allLockEntries, totalLockedFromTransfer, _getSystemPalletReservedBalance(balanceInfo), bittensorStakingBalances[index]);
199
+ const transferableBalance = _getSystemPalletTransferable(balanceInfo, _getChainExistentialDeposit(chainInfo), extrinsicType);
163
200
  return {
164
201
  address: addresses[index],
165
202
  tokenSlug: _getChainNativeTokenSlug(chainInfo),
166
203
  free: transferableBalance.toString(),
167
204
  locked: totalLockedFromTransfer.toString(),
168
205
  state: APIItemState.READY,
206
+ lockedDetails,
169
207
  metadata: balanceInfo
170
208
  };
171
209
  });
@@ -0,0 +1,7 @@
1
+ import { _ChainInfo } from '@subwallet/chain-list/types';
2
+ import { FrameBalancesFreezesInfo, FrameBalancesHoldsInfo, FrameBalancesLocksInfo } from '@subwallet/extension-base/core/substrate/types';
3
+ import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types';
4
+ import { LockedBalanceDetails } from '@subwallet/extension-base/types';
5
+ import BigN from 'bignumber.js';
6
+ export declare function getSpecialStakingBalances(chainInfo: _ChainInfo, addresses: string[], substrateApi: _SubstrateApi): Promise<BigN[]>;
7
+ export declare function buildLockedDetails(item: (FrameBalancesLocksInfo | FrameBalancesHoldsInfo | FrameBalancesFreezesInfo)[], totalLockedFromTransfer: bigint, reserved: bigint, externalStaking?: BigN): LockedBalanceDetails;
@@ -0,0 +1,58 @@
1
+ // Copyright 2019-2022 @subwallet/extension-base
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { _BALANCE_CHAIN_GROUP, _BALANCE_LOCKED_ID_GROUP } from '@subwallet/extension-base/services/chain-service/constants';
5
+ import BigN from 'bignumber.js';
6
+ export async function getSpecialStakingBalances(chainInfo, addresses, substrateApi) {
7
+ // Default: 0 for all addresses
8
+ let balances = new Array(addresses.length).fill(new BigN(0));
9
+
10
+ // --- Bittensor ----------------------------------------------------------------
11
+ if (_BALANCE_CHAIN_GROUP.bittensor.includes(chainInfo.slug)) {
12
+ const rawData = await substrateApi.api.call.stakeInfoRuntimeApi.getStakeInfoForColdkeys(addresses);
13
+ const values = rawData.toPrimitive();
14
+ balances = values.map(([, stakes]) => stakes.filter(i => i.netuid === 0).reduce((prev, curr) => prev.plus(curr.stake), BigN(0)));
15
+ return balances;
16
+ }
17
+ return balances;
18
+ }
19
+
20
+ // handler according to different logic
21
+ const extractId = id => {
22
+ if (!id) {
23
+ return '';
24
+ }
25
+ if (typeof id === 'string') {
26
+ return id.replace(/\0/g, '').trim();
27
+ }
28
+ const keys = Object.keys(id);
29
+ return keys.length ? keys[0] : '';
30
+ };
31
+ export function buildLockedDetails(item, totalLockedFromTransfer, reserved, externalStaking) {
32
+ let stakingBalance = externalStaking || new BigN(0);
33
+ let govBalance = new BigN(0);
34
+ let democracyBalance = new BigN(0);
35
+ const reservedBN = new BigN(reserved.toString());
36
+ for (const entry of item) {
37
+ const id = extractId(entry.id);
38
+ const amount = new BigN(String(entry.amount || 0));
39
+ if (_BALANCE_LOCKED_ID_GROUP.staking.includes(id)) {
40
+ stakingBalance = stakingBalance.plus(amount);
41
+ } else if (_BALANCE_LOCKED_ID_GROUP.gov.includes(id)) {
42
+ govBalance = govBalance.plus(amount);
43
+ } else if (_BALANCE_LOCKED_ID_GROUP.democracy.includes(id)) {
44
+ democracyBalance = democracyBalance.plus(amount);
45
+ }
46
+ }
47
+
48
+ // others = total locked - max(staking, gov, democracy, reserved)
49
+ const maxMain = BigN.max(stakingBalance, govBalance, democracyBalance, reservedBN);
50
+ const others = new BigN(totalLockedFromTransfer.toString()).minus(maxMain);
51
+ return {
52
+ staking: stakingBalance.toFixed(),
53
+ governance: govBalance.toFixed(),
54
+ democracy: democracyBalance.toFixed(),
55
+ reserved: reservedBN.toFixed(),
56
+ others: others.gt(0) ? others.toFixed() : '0'
57
+ };
58
+ }
@@ -3,7 +3,7 @@ import KoniState from '@subwallet/extension-base/koni/background/handlers/State'
3
3
  import { RequestOptimalTransferProcess } from '@subwallet/extension-base/services/balance-service/helpers/process';
4
4
  import { ServiceStatus, StoppableServiceInterface } from '@subwallet/extension-base/services/base/types';
5
5
  import { EventItem, EventType } from '@subwallet/extension-base/services/event-service/types';
6
- import { BalanceItem, BalanceJson, CommonOptimalTransferPath } from '@subwallet/extension-base/types';
6
+ import { BalanceItem, BalanceJson, BalanceType, CommonOptimalTransferPath } from '@subwallet/extension-base/types';
7
7
  import { PromiseHandler } from '@subwallet/extension-base/utils';
8
8
  import { BehaviorSubject } from 'rxjs';
9
9
  /**
@@ -48,9 +48,10 @@ export declare class BalanceService implements StoppableServiceInterface {
48
48
  getBalanceDetectCache(update: (value: DetectBalanceCache) => void): void;
49
49
  setBalanceDetectCache(addresses: string[]): void;
50
50
  /** Subscribe token free balance of an address on chain */
51
- subscribeBalance(address: string, chain: string, tokenSlug: string | undefined, balanceType?: 'transferable' | 'total' | 'keepAlive', extrinsicType?: ExtrinsicType, callback?: (rs: AmountData) => void): Promise<[() => void, AmountData]>;
51
+ subscribeBalance(address: string, chain: string, tokenSlug: string | undefined, balanceType?: BalanceType, extrinsicType?: ExtrinsicType, callback?: (rs: AmountData) => void): Promise<[() => void, AmountData]>;
52
52
  subscribeTransferableBalance(address: string, chain: string, tokenSlug: string | undefined, extrinsicType?: ExtrinsicType, callback?: (rs: AmountData) => void): Promise<[() => void, AmountData]>;
53
53
  subscribeTotalBalance(address: string, chain: string, tokenSlug: string | undefined, extrinsicType?: ExtrinsicType, callback?: (rs: AmountData) => void): Promise<[() => void, AmountData]>;
54
+ subscribeBalanceByType(address: string, chain: string, tokenSlug: string | undefined, balanceType?: BalanceType, extrinsicType?: ExtrinsicType, callback?: (rs: AmountData) => void): Promise<[() => void, AmountData]>;
54
55
  /**
55
56
  * @public
56
57
  * @async
@@ -64,6 +65,7 @@ export declare class BalanceService implements StoppableServiceInterface {
64
65
  */
65
66
  getTransferableBalance(address: string, chain: string, tokenSlug?: string, extrinsicType?: ExtrinsicType): Promise<AmountData>;
66
67
  getTotalBalance(address: string, chain: string, tokenSlug?: string, extrinsicType?: ExtrinsicType): Promise<AmountData>;
68
+ getBalanceByType(address: string, chain: string, tokenSlug?: string, balanceType?: BalanceType, extrinsicType?: ExtrinsicType): Promise<AmountData>;
67
69
  /** Remove balance from the subject object by addresses */
68
70
  removeBalanceByAddresses(addresses: string[]): void;
69
71
  /** Remove inactive asset from the balance map */