@subwallet/extension-base 1.3.67-0 → 1.3.68-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) 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/koni/api/nft/rari/index.js +1 -1
  6. package/cjs/koni/background/cron.js +16 -0
  7. package/cjs/koni/background/handlers/Extension.js +165 -89
  8. package/cjs/koni/background/handlers/State.js +25 -0
  9. package/cjs/packageInfo.js +1 -1
  10. package/cjs/services/balance-service/helpers/group.js +31 -2
  11. package/cjs/services/balance-service/helpers/subscribe/substrate/index.js +51 -13
  12. package/cjs/services/balance-service/helpers/subscribe/substrate/utils.js +69 -0
  13. package/cjs/services/balance-service/index.js +36 -11
  14. package/cjs/services/balance-service/transfer/smart-contract.js +2 -0
  15. package/cjs/services/chain-service/constants.js +8 -46
  16. package/cjs/services/chain-service/handler/EvmChainHandler.js +6 -3
  17. package/cjs/services/earning-service/handlers/base.js +7 -1
  18. package/cjs/services/nft-service/index.js +173 -0
  19. package/cjs/services/transaction-service/index.js +1 -1
  20. package/cjs/types/balance/index.js +26 -1
  21. package/cjs/utils/index.js +25 -2
  22. package/cjs/utils/setup-api-sdk.js +0 -5
  23. package/constants/environment.d.ts +0 -1
  24. package/constants/environment.js +0 -1
  25. package/constants/index.d.ts +1 -0
  26. package/constants/index.js +1 -0
  27. package/core/substrate/system-pallet.d.ts +1 -0
  28. package/core/substrate/system-pallet.js +3 -0
  29. package/core/substrate/types.d.ts +14 -0
  30. package/koni/api/nft/rari/index.js +1 -1
  31. package/koni/background/cron.d.ts +1 -0
  32. package/koni/background/cron.js +17 -1
  33. package/koni/background/handlers/Extension.d.ts +3 -0
  34. package/koni/background/handlers/Extension.js +87 -13
  35. package/koni/background/handlers/State.d.ts +4 -0
  36. package/koni/background/handlers/State.js +25 -0
  37. package/package.json +16 -6
  38. package/packageInfo.js +1 -1
  39. package/services/balance-service/helpers/group.js +31 -2
  40. package/services/balance-service/helpers/subscribe/substrate/index.js +51 -13
  41. package/services/balance-service/helpers/subscribe/substrate/utils.d.ts +7 -0
  42. package/services/balance-service/helpers/subscribe/substrate/utils.js +58 -0
  43. package/services/balance-service/index.d.ts +4 -2
  44. package/services/balance-service/index.js +26 -6
  45. package/services/balance-service/transfer/smart-contract.js +2 -0
  46. package/services/chain-service/constants.d.ts +5 -24
  47. package/services/chain-service/constants.js +6 -35
  48. package/services/chain-service/handler/EvmChainHandler.js +6 -3
  49. package/services/earning-service/handlers/base.js +7 -1
  50. package/services/nft-service/index.d.ts +9 -0
  51. package/services/nft-service/index.js +165 -0
  52. package/services/transaction-service/index.js +1 -1
  53. package/services/transaction-service/types.d.ts +2 -1
  54. package/types/balance/index.d.ts +14 -0
  55. package/types/balance/index.js +21 -1
  56. package/utils/index.js +25 -2
  57. package/utils/setup-api-sdk.js +1 -6
@@ -5,6 +5,7 @@ import { ChainType, ExtrinsicType } from '@subwallet/extension-base/background/K
5
5
  import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants';
6
6
  import { DEFAULT_YIELD_FIRST_STEP, STAKING_IDENTITY_API_SLUG } from '@subwallet/extension-base/services/earning-service/constants';
7
7
  import { createClaimNotification, createWithdrawNotifications } from '@subwallet/extension-base/services/inapp-notification-service/utils';
8
+ import { BalanceType, YieldPoolType } from '@subwallet/extension-base/types';
8
9
  import { formatNumber, reformatAddress } from '@subwallet/extension-base/utils';
9
10
  import { BN, BN_TEN } from '@polkadot/util';
10
11
  /**
@@ -154,7 +155,12 @@ export default class BasePoolHandler {
154
155
  }
155
156
  const nativeTokenInfo = this.state.chainService.getNativeTokenInfo(this.chain);
156
157
  // Use TRANSFER_BALANCE extrinsic in order to get transferable balanace without minus ED
157
- const nativeTokenBalance = await this.state.balanceService.getTransferableBalance(request.address, this.chain, undefined, ExtrinsicType.TRANSFER_BALANCE);
158
+ let nativeTokenBalance;
159
+ if ([YieldPoolType.NATIVE_STAKING, YieldPoolType.NOMINATION_POOL].includes(poolInfo.type)) {
160
+ nativeTokenBalance = await this.state.balanceService.getBalanceByType(request.address, this.chain, undefined, BalanceType.TOTAL_MINUS_RESERVED, ExtrinsicType.TRANSFER_BALANCE);
161
+ } else {
162
+ nativeTokenBalance = await this.state.balanceService.getTransferableBalance(request.address, this.chain, undefined, ExtrinsicType.TRANSFER_BALANCE);
163
+ }
158
164
  const bnNativeTokenBalance = new BN(nativeTokenBalance.value);
159
165
  const bnMinBalanceToJoin = new BN(((_poolInfo$statistic2 = poolInfo.statistic) === null || _poolInfo$statistic2 === void 0 ? void 0 : (_poolInfo$statistic2$ = _poolInfo$statistic2.earningThreshold) === null || _poolInfo$statistic2$ === void 0 ? void 0 : _poolInfo$statistic2$.join) || '0').add(new BN(poolInfo.metadata.maintainBalance));
160
166
  if (bnNativeTokenBalance.lte(bnMinBalanceToJoin)) {
@@ -0,0 +1,9 @@
1
+ import { NftFullListRequest } from '@subwallet/extension-base/background/KoniTypes';
2
+ import KoniState from '@subwallet/extension-base/koni/background/handlers/State';
3
+ export default class NftService {
4
+ private inProgress;
5
+ private state;
6
+ constructor(state: KoniState);
7
+ fetchEvmCollectionsWithPreview(addresses: string[]): Promise<void>;
8
+ getFullNftInstancesByCollection(request: NftFullListRequest): Promise<boolean>;
9
+ }
@@ -0,0 +1,165 @@
1
+ // Copyright 2019-2022 @subwallet/extension-base authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { _AssetType } from '@subwallet/chain-list/types';
5
+ import { _getEvmChainId } from '@subwallet/extension-base/services/chain-service/utils';
6
+ import { baseParseIPFSUrl } from '@subwallet/extension-base/utils';
7
+ import { getKeypairTypeByAddress } from '@subwallet/keyring';
8
+ import { EthereumKeypairTypes } from '@subwallet/keyring/types';
9
+ import subwalletApiSdk from '@subwallet-monorepos/subwallet-services-sdk';
10
+ function mapSdkToNftItem(rawInstance, chain, collectionId, owner) {
11
+ var _rawInstance$token_ty, _rawInstance$token_ty2, _rawInstance$id;
12
+ const metadata = rawInstance.metadata || {};
13
+ const image = metadata.image || rawInstance.image_url || rawInstance.media_url || '';
14
+ const attributes = Array.isArray(metadata.attributes) ? metadata.attributes : [];
15
+ let rarity;
16
+ const properties = {};
17
+ for (const attr of attributes) {
18
+ try {
19
+ var _attr$trait_type;
20
+ const key = (_attr$trait_type = attr.trait_type) === null || _attr$trait_type === void 0 ? void 0 : _attr$trait_type.trim();
21
+ if (!key) {
22
+ continue;
23
+ }
24
+ let value = attr.value;
25
+ if (typeof value === 'string') {
26
+ const lower = value.toLowerCase();
27
+ if (lower === 'true') {
28
+ value = true;
29
+ } else if (lower === 'false') {
30
+ value = false;
31
+ }
32
+ }
33
+ properties[key] = value;
34
+ if (key.toLowerCase() === 'rarity') {
35
+ rarity = String(value);
36
+ }
37
+ } catch {}
38
+ }
39
+ const hasProperties = Object.keys(properties).length > 0;
40
+ const normalizedType = (_rawInstance$token_ty = rawInstance.token_type) === null || _rawInstance$token_ty === void 0 ? void 0 : (_rawInstance$token_ty2 = _rawInstance$token_ty.replace('-', '')) === null || _rawInstance$token_ty2 === void 0 ? void 0 : _rawInstance$token_ty2.toUpperCase();
41
+
42
+ // Only support ERC721
43
+ if (normalizedType !== 'ERC721') {
44
+ return null;
45
+ }
46
+ return {
47
+ id: (_rawInstance$id = rawInstance.id) === null || _rawInstance$id === void 0 ? void 0 : _rawInstance$id.toString(),
48
+ chain,
49
+ collectionId,
50
+ owner: rawInstance.owner || owner,
51
+ originAsset: undefined,
52
+ name: metadata.name || `#${rawInstance.id}`,
53
+ image: baseParseIPFSUrl(image),
54
+ externalUrl: rawInstance.external_app_url || undefined,
55
+ rarity,
56
+ description: metadata.description || undefined,
57
+ properties: hasProperties ? properties : null,
58
+ type: normalizedType === 'ERC721' ? _AssetType.ERC721 : _AssetType.ERC721,
59
+ // currently only support ERC721
60
+ rmrk_ver: undefined,
61
+ onChainOption: undefined,
62
+ assetHubType: undefined
63
+ };
64
+ }
65
+ function mapSdkToCollection(raw, chain) {
66
+ var _raw$token_instances;
67
+ const token = raw.token || {};
68
+ return {
69
+ // must-have
70
+ collectionId: token.address_hash,
71
+ chain,
72
+ originAsset: undefined,
73
+ // optional
74
+ collectionName: token.name || token.symbol || 'Unknown Collection',
75
+ image: token.icon_url || undefined,
76
+ itemCount: Number(raw.amount) || ((_raw$token_instances = raw.token_instances) === null || _raw$token_instances === void 0 ? void 0 : _raw$token_instances.length) || 0,
77
+ externalUrl: undefined
78
+ };
79
+ }
80
+ export default class NftService {
81
+ inProgress = new Set();
82
+ constructor(state) {
83
+ this.state = state;
84
+ }
85
+ async fetchEvmCollectionsWithPreview(addresses) {
86
+ for (const address of addresses) {
87
+ const type = getKeypairTypeByAddress(address);
88
+ const typeValid = [...EthereumKeypairTypes].includes(type);
89
+ if (typeValid) {
90
+ if (this.inProgress.has(address)) {
91
+ console.log(`[NftService] ${address} already running`);
92
+ continue;
93
+ }
94
+ this.inProgress.add(address);
95
+ try {
96
+ const nftDetectionApi = subwalletApiSdk.nftDetectionApi;
97
+ if (!(nftDetectionApi !== null && nftDetectionApi !== void 0 && nftDetectionApi.getEvmNftCollectionsByAddress)) {
98
+ console.warn('[NftService] NftDetectionApi not available');
99
+ continue;
100
+ }
101
+ const rawData = await nftDetectionApi.getEvmNftCollectionsByAddress(address);
102
+ const allItems = [];
103
+ const allCollections = [];
104
+ for (const [chain, collections] of Object.entries(rawData)) {
105
+ if (!Array.isArray(collections)) {
106
+ continue;
107
+ }
108
+ for (const col of collections) {
109
+ const mappedCollection = mapSdkToCollection(col, chain);
110
+ allCollections.push(mappedCollection);
111
+ if (Array.isArray(col.token_instances)) {
112
+ const items = col.token_instances.map(inst => mapSdkToNftItem(inst, chain, mappedCollection.collectionId, address)).filter(i => Boolean(i));
113
+ allItems.push(...items);
114
+ }
115
+ }
116
+ }
117
+ await this.state.handleDetectedNftCollections(allCollections);
118
+ await this.state.handleDetectedNfts(address, allItems);
119
+ } catch (err) {
120
+ console.warn(`[NftService] detect error for ${address}`, err);
121
+ } finally {
122
+ this.inProgress.delete(address);
123
+ }
124
+ }
125
+ }
126
+ }
127
+ async getFullNftInstancesByCollection(request) {
128
+ const {
129
+ chainInfo,
130
+ contractAddress,
131
+ owners
132
+ } = request;
133
+ const chainId = _getEvmChainId(chainInfo);
134
+ if (!contractAddress || !owners || !chainId) {
135
+ console.warn('[NftService] missing params for getFullNftInstancesByCollection');
136
+ return false;
137
+ }
138
+ try {
139
+ const nftDetectionApi = subwalletApiSdk.nftDetectionApi;
140
+ if (!(nftDetectionApi !== null && nftDetectionApi !== void 0 && nftDetectionApi.getAllNftInstances)) {
141
+ console.warn('[NftService] getAllNftInstances not available');
142
+ return false;
143
+ }
144
+ const ownerList = Array.isArray(owners) ? owners : [owners];
145
+ for (const eachOwner of ownerList) {
146
+ try {
147
+ const instances = await nftDetectionApi.getAllNftInstances(contractAddress, eachOwner, chainId.toString());
148
+ if (!Array.isArray(instances)) {
149
+ continue;
150
+ }
151
+ console.log('FOR TESTER (before)', instances);
152
+ const nftList = instances.map(inst => mapSdkToNftItem(inst, chainInfo.slug, contractAddress, eachOwner)).filter(i => Boolean(i));
153
+ console.log('FOR TESTER (after)', nftList);
154
+ await this.state.handleDetectedNfts(eachOwner, nftList);
155
+ } catch (innerErr) {
156
+ console.warn(`[NftService] getAllNftInstances failed for ${eachOwner}`, innerErr);
157
+ }
158
+ }
159
+ return true;
160
+ } catch (err) {
161
+ console.error(`[NftDetectionService] getFullNftInstancesByCollection error for ${contractAddress}`, err);
162
+ return false;
163
+ }
164
+ }
165
+ }
@@ -127,7 +127,7 @@ export default class TransactionService {
127
127
  // Check account signing transaction
128
128
 
129
129
  checkSigningAccountForTransaction(validationResponse, chainInfoMap);
130
- const nativeTokenAvailable = await this.state.balanceService.getTransferableBalance(address, chain, nativeTokenInfo.slug, extrinsicType);
130
+ const nativeTokenAvailable = await this.state.balanceService.getBalanceByType(address, chain, nativeTokenInfo.slug, transactionInput.balanceType, extrinsicType);
131
131
 
132
132
  // Check available balance against transaction fee
133
133
  checkBalanceWithTransactionFee(validationResponse, transactionInput, nativeTokenInfo, nativeTokenAvailable);
@@ -2,7 +2,7 @@ import { ChainType, ExtrinsicDataTypeMap, ExtrinsicStatus, ExtrinsicType, FeeDat
2
2
  import { SignTypedDataMessageV3V4 } from '@subwallet/extension-base/core/logic-validation';
3
3
  import { TonTransactionConfig } from '@subwallet/extension-base/services/balance-service/transfer/ton-transfer';
4
4
  import { UniswapOrderInfo } from '@subwallet/extension-base/services/swap-service/handler/uniswap-handler';
5
- import { BaseRequestSign, BriefProcessStep, ProcessTransactionData, TransactionFee } from '@subwallet/extension-base/types';
5
+ import { BalanceType, BaseRequestSign, BriefProcessStep, ProcessTransactionData, TransactionFee } from '@subwallet/extension-base/types';
6
6
  import { Psbt } from 'bitcoinjs-lib';
7
7
  import EventEmitter from 'eventemitter3';
8
8
  import { TransactionConfig } from 'web3-core';
@@ -61,6 +61,7 @@ export interface SWTransactionInput extends SwInputBase, Partial<Pick<SWTransact
61
61
  resolveOnDone?: boolean;
62
62
  skipFeeValidation?: boolean;
63
63
  skipFeeRecalculation?: boolean;
64
+ balanceType?: BalanceType;
64
65
  }
65
66
  export interface SWPermitTransactionInput extends Omit<SWTransactionInput, 'transaction'> {
66
67
  transaction?: SWPermitTransaction['transaction'] | null;
@@ -8,6 +8,12 @@ export interface TokenBalanceRaw {
8
8
  frozen: BN;
9
9
  free: BN;
10
10
  }
11
+ export declare enum BalanceType {
12
+ TRANSFERABLE = "transferable",
13
+ TOTAL = "total",
14
+ TOTAL_MINUS_RESERVED = "totalMinusReserved",
15
+ KEEP_ALIVE = "keepAlive"
16
+ }
11
17
  /**
12
18
  * Balance info of a token on an address
13
19
  * @property {string} address - Address
@@ -18,6 +24,13 @@ export interface TokenBalanceRaw {
18
24
  * @property {string} locked - Locked balance, cannot be transferred, locked here is only meaningful in the context of token transfer
19
25
  * @property {metadata} [metadata] - Could be anything, supposed to be generic to handle various contexts
20
26
  */
27
+ export interface LockedBalanceDetails {
28
+ staking: string;
29
+ governance: string;
30
+ democracy: string;
31
+ reserved: string;
32
+ others: string;
33
+ }
21
34
  export interface BalanceItem {
22
35
  address: string;
23
36
  tokenSlug: string;
@@ -25,6 +38,7 @@ export interface BalanceItem {
25
38
  timestamp?: number;
26
39
  free: string;
27
40
  locked: string;
41
+ lockedDetails?: LockedBalanceDetails;
28
42
  metadata?: _BalanceMetadata;
29
43
  }
30
44
  /** Balance info of all tokens on an address */
@@ -1 +1,21 @@
1
- export {};
1
+ // Copyright 2019-2022 @subwallet/extension-koni-ui authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ export let BalanceType;
5
+
6
+ /**
7
+ * Balance info of a token on an address
8
+ * @property {string} address - Address
9
+ * @property {string} tokenSlug - Slug of token
10
+ * @property {APIItemState} state - State of information
11
+ * @property {number} [timestamp] - Time to get information
12
+ * @property {string} free - Transferable balance
13
+ * @property {string} locked - Locked balance, cannot be transferred, locked here is only meaningful in the context of token transfer
14
+ * @property {metadata} [metadata] - Could be anything, supposed to be generic to handle various contexts
15
+ */
16
+ (function (BalanceType) {
17
+ BalanceType["TRANSFERABLE"] = "transferable";
18
+ BalanceType["TOTAL"] = "total";
19
+ BalanceType["TOTAL_MINUS_RESERVED"] = "totalMinusReserved";
20
+ BalanceType["KEEP_ALIVE"] = "keepAlive";
21
+ })(BalanceType || (BalanceType = {}));
package/utils/index.js CHANGED
@@ -273,13 +273,36 @@ export const stripUrl = url => {
273
273
  return parts[2];
274
274
  };
275
275
  export const baseParseIPFSUrl = (input, customDomain) => {
276
- const selectedDomain = customDomain || getRandomIpfsGateway();
277
276
  if (!input || input.length === 0) {
278
277
  return undefined;
279
278
  }
280
- if (isUrl(input)) {
279
+
280
+ // Case 1: Return as-is for inline data URLs (e.g. base64-encoded images)
281
+ if (input.startsWith('data:')) {
281
282
  return input;
282
283
  }
284
+ const selectedDomain = customDomain || getRandomIpfsGateway();
285
+
286
+ // Case 2: Replace Pinata private gateways with a public IPFS gateway
287
+ // ==== EX: https://ikzttp.mypinata.cloud/ipfs/QmYDvPAXtiJg7s8JdRBSLWdgSphQdac8j1YuQNNxcGE1hg/9586.png
288
+ // Case 2b: Blockscout IPFS debug gateway -> rewrite to public gateway
289
+ // ==== EX: http://ipfs-debug.node.blockscout.com/ipfs/QmX2qHy1o27KgmHJSG2wKj2qLiv1gMCJCTn4nxzEVtTdgF
290
+ // Case 2c: http://ipfs.node.blockscout.com/ipfs/QmeTETrnJcG3iowfT3tXtz2jKmyeYbeag3AeYfDk5pBjGg
291
+
292
+ const privateGatewayPattern = /https?:\/\/([^/]*pinata\.cloud|[^/]*\.node\.blockscout\.com)\/ipfs\//;
293
+ if (privateGatewayPattern.test(input)) {
294
+ return input.replace(privateGatewayPattern, selectedDomain);
295
+ }
296
+
297
+ // Case 3: Handle NFT.storage subdomain links (e.g. https://<cid>.ipfs.nftstorage.link/...)
298
+ // Always redirect to selectedDomain to avoid SSL version/cipher mismatch errors
299
+ // ==== EX: https://bafybeias6as7k66hkghst3w4jwk6x5dkfk56oglqh44x6jmok6n7kcvg7m.ipfs.nftstorage.link/0.gif?ext=gif
300
+ const nftStorageMatch = input.match(/^https?:\/\/([a-zA-Z0-9]+)\.ipfs\.nftstorage\.link\/(.*)$/);
301
+ if (nftStorageMatch) {
302
+ const cid = nftStorageMatch[1];
303
+ const pathAndQuery = nftStorageMatch[2] || '';
304
+ return `${selectedDomain}${cid}/${pathAndQuery}`;
305
+ }
283
306
  if (isUrl(input) || input.includes('https://') || input.includes('http')) {
284
307
  return input;
285
308
  }
@@ -1,7 +1,7 @@
1
1
  // Copyright 2019-2022 @subwallet/extension-koni authors & contributors
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
- import { APP_VERSION, BACKEND_API_URL, BACKEND_PRICE_HISTORY_URL } from '@subwallet/extension-base/constants';
4
+ import { APP_VERSION, BACKEND_API_URL } from '@subwallet/extension-base/constants';
5
5
  import subwalletApiSdk from '@subwallet-monorepos/subwallet-services-sdk';
6
6
  import { TARGET_ENV } from "./environment.js";
7
7
  const CHAIN_LIST_VERSION = process.env.CHAIN_LIST_VERSION;
@@ -12,9 +12,4 @@ export function setupApiSDK() {
12
12
  platform: TARGET_ENV,
13
13
  chainListVersion: CHAIN_LIST_VERSION
14
14
  });
15
-
16
- // Custom the price history API with other different base URL
17
- subwalletApiSdk.priceHistoryApi.updateConfig({
18
- baseUrl: BACKEND_PRICE_HISTORY_URL
19
- });
20
15
  }