@subwallet/extension-base 1.3.79-1 → 1.3.80-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 (48) hide show
  1. package/background/KoniTypes.d.ts +13 -3
  2. package/cjs/core/substrate/system-pallet.js +3 -0
  3. package/cjs/koni/api/nft/index.js +0 -14
  4. package/cjs/koni/background/cron.js +0 -17
  5. package/cjs/koni/background/handlers/Extension.js +6 -5
  6. package/cjs/koni/background/handlers/State.js +24 -6
  7. package/cjs/packageInfo.js +1 -1
  8. package/cjs/services/balance-service/helpers/process.js +49 -21
  9. package/cjs/services/balance-service/index.js +2 -2
  10. package/cjs/services/chain-service/constants.js +6 -2
  11. package/cjs/services/earning-service/handlers/special.js +3 -2
  12. package/cjs/services/nft-service/index.js +219 -150
  13. package/cjs/services/nft-service/multi-chain-nft-fetcher.js +145 -0
  14. package/cjs/services/nft-service/nft-handlers/base-nft-handler.js +28 -0
  15. package/cjs/services/nft-service/nft-handlers/evm/evm-nft-handler.js +179 -0
  16. package/cjs/services/nft-service/nft-handlers/registry.js +37 -0
  17. package/cjs/services/nft-service/nft-handlers/unique/unique-nft-handler.js +187 -0
  18. package/cjs/services/storage-service/DatabaseService.js +1 -1
  19. package/core/substrate/system-pallet.js +3 -0
  20. package/koni/api/nft/index.js +1 -15
  21. package/koni/background/cron.d.ts +0 -1
  22. package/koni/background/cron.js +1 -18
  23. package/koni/background/handlers/Extension.d.ts +1 -0
  24. package/koni/background/handlers/Extension.js +6 -5
  25. package/koni/background/handlers/State.d.ts +8 -2
  26. package/koni/background/handlers/State.js +24 -6
  27. package/package.json +31 -6
  28. package/packageInfo.js +1 -1
  29. package/services/balance-service/helpers/process.d.ts +1 -1
  30. package/services/balance-service/helpers/process.js +48 -21
  31. package/services/balance-service/index.js +2 -2
  32. package/services/chain-service/constants.d.ts +3 -0
  33. package/services/chain-service/constants.js +3 -0
  34. package/services/earning-service/handlers/special.js +4 -3
  35. package/services/nft-service/index.d.ts +42 -6
  36. package/services/nft-service/index.js +219 -151
  37. package/services/nft-service/multi-chain-nft-fetcher.d.ts +13 -0
  38. package/services/nft-service/multi-chain-nft-fetcher.js +138 -0
  39. package/services/nft-service/nft-handlers/base-nft-handler.d.ts +13 -0
  40. package/services/nft-service/nft-handlers/base-nft-handler.js +21 -0
  41. package/services/nft-service/nft-handlers/evm/evm-nft-handler.d.ts +9 -0
  42. package/services/nft-service/nft-handlers/evm/evm-nft-handler.js +171 -0
  43. package/services/nft-service/nft-handlers/registry.d.ts +11 -0
  44. package/services/nft-service/nft-handlers/registry.js +29 -0
  45. package/services/nft-service/nft-handlers/unique/unique-nft-handler.d.ts +12 -0
  46. package/services/nft-service/nft-handlers/unique/unique-nft-handler.js +177 -0
  47. package/services/storage-service/DatabaseService.d.ts +1 -1
  48. package/services/storage-service/DatabaseService.js +1 -1
@@ -0,0 +1,171 @@
1
+ // Copyright 2019-2022 @subwallet/extension-koni authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { _AssetType } from '@subwallet/chain-list/types';
5
+ import { ChainType } from '@subwallet/extension-base/background/KoniTypes';
6
+ import { _getEvmChainId } from '@subwallet/extension-base/services/chain-service/utils';
7
+ import { baseParseIPFSUrl, getAddressesByChainType } from '@subwallet/extension-base/utils';
8
+ import subwalletApiSdk from '@subwallet-monorepos/subwallet-services-sdk';
9
+ import { BaseNftHandler } from "../base-nft-handler.js";
10
+ export class EvmNftHandler extends BaseNftHandler {
11
+ filterAddresses(addresses) {
12
+ return getAddressesByChainType(addresses, [ChainType.EVM]);
13
+ }
14
+ mapSdkToNftItem(rawInstance, collectionId, owner) {
15
+ var _rawInstance$token_ty, _rawInstance$id;
16
+ const metadata = rawInstance.metadata || {};
17
+ const image = metadata.image || rawInstance.image_url || rawInstance.media_url || '';
18
+ const attributes = Array.isArray(metadata.attributes) ? metadata.attributes : [];
19
+ let rarity;
20
+ const properties = {};
21
+ for (const attr of attributes) {
22
+ try {
23
+ var _attr$trait_type;
24
+ const key = (_attr$trait_type = attr.trait_type) === null || _attr$trait_type === void 0 ? void 0 : _attr$trait_type.trim();
25
+ if (!key) {
26
+ continue;
27
+ }
28
+ let value = attr.value;
29
+ if (typeof value === 'string') {
30
+ const lower = value.toLowerCase();
31
+ if (lower === 'true') {
32
+ value = true;
33
+ }
34
+ if (lower === 'false') {
35
+ value = false;
36
+ }
37
+ }
38
+ properties[key] = value;
39
+ if (key.toLowerCase() === 'rarity') {
40
+ rarity = String(value);
41
+ }
42
+ } catch {
43
+ // ignore
44
+ }
45
+ }
46
+ const normalizedType = (_rawInstance$token_ty = rawInstance.token_type) === null || _rawInstance$token_ty === void 0 ? void 0 : _rawInstance$token_ty.replace('-', '').toUpperCase();
47
+ if (!['ERC721'].includes(normalizedType)) {
48
+ return null;
49
+ }
50
+ return {
51
+ id: ((_rawInstance$id = rawInstance.id) === null || _rawInstance$id === void 0 ? void 0 : _rawInstance$id.toString()) || '',
52
+ chain: this.chain,
53
+ collectionId,
54
+ owner: rawInstance.owner || owner,
55
+ name: metadata.name || `#${rawInstance.id}`,
56
+ image: baseParseIPFSUrl(image),
57
+ externalUrl: rawInstance.external_app_url || undefined,
58
+ rarity,
59
+ description: metadata.description || undefined,
60
+ properties: Object.keys(properties).length > 0 ? properties : null,
61
+ type: normalizedType === 'ERC721' ? _AssetType.ERC721 : _AssetType.ERC721,
62
+ originAsset: undefined,
63
+ rmrk_ver: undefined,
64
+ onChainOption: undefined,
65
+ assetHubType: undefined
66
+ };
67
+ }
68
+ mapSdkToCollection(raw) {
69
+ var _raw$token_instances;
70
+ const token = raw.token || {};
71
+ return {
72
+ collectionId: token.address_hash,
73
+ chain: this.chain,
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
+ originAsset: undefined
79
+ };
80
+ }
81
+
82
+ // ==================== 1. PREVIEW – Used for cron / background ====================
83
+ async fetchPreview(addresses) {
84
+ const items = [];
85
+ const collections = [];
86
+ const api = subwalletApiSdk.nftDetectionApi;
87
+ if (!(api !== null && api !== void 0 && api.getEvmNftCollectionsByAddress)) {
88
+ console.warn('[EvmNftHandler] Preview API not available');
89
+ return {
90
+ items,
91
+ collections
92
+ };
93
+ }
94
+ for (const address of addresses) {
95
+ try {
96
+ const rawData = await api.getEvmNftCollectionsByAddress(address);
97
+ for (const [chain, sdkCollections] of Object.entries(rawData)) {
98
+ if (chain !== this.chain || !Array.isArray(sdkCollections)) {
99
+ continue;
100
+ }
101
+ for (const col of sdkCollections) {
102
+ const collection = this.mapSdkToCollection(col);
103
+ collections.push(collection);
104
+ if (Array.isArray(col.token_instances)) {
105
+ const mapped = col.token_instances.map(inst => this.mapSdkToNftItem(inst, collection.collectionId, address)).filter(i => i !== null);
106
+ items.push(...mapped);
107
+ }
108
+ }
109
+ }
110
+ } catch (error) {
111
+ console.error(`[EvmNftHandler] Preview failed for ${address}`, error);
112
+ }
113
+ }
114
+ return {
115
+ items: items,
116
+ collections: collections
117
+ };
118
+ }
119
+
120
+ // ==================== 2. FULL – At collection details screen ====================
121
+ async fetchFullListNftOfACollection(request) {
122
+ const items = [];
123
+ const collections = [];
124
+ const {
125
+ chainInfo,
126
+ collectionId,
127
+ owners
128
+ } = request;
129
+ const chainId = _getEvmChainId(chainInfo);
130
+ if (!collectionId || !owners || !chainId) {
131
+ console.warn('[NftService] missing params for getFullNftInstancesByCollection');
132
+ return {
133
+ items,
134
+ collections
135
+ };
136
+ }
137
+ try {
138
+ const nftDetectionApi = subwalletApiSdk.nftDetectionApi;
139
+ if (!(nftDetectionApi !== null && nftDetectionApi !== void 0 && nftDetectionApi.getAllNftInstances)) {
140
+ console.warn('[NftService] getAllNftInstances not available');
141
+ return {
142
+ items,
143
+ collections
144
+ };
145
+ }
146
+ const ownerList = Array.isArray(owners) ? owners : [owners];
147
+ for (const eachOwner of ownerList) {
148
+ try {
149
+ const instances = await nftDetectionApi.getAllNftInstances(collectionId, eachOwner, chainId.toString());
150
+ if (!Array.isArray(instances)) {
151
+ continue;
152
+ }
153
+ const mappedItems = instances.map(inst => this.mapSdkToNftItem(inst, collectionId, eachOwner)).filter(i => Boolean(i));
154
+ items.push(...mappedItems);
155
+ } catch (innerErr) {
156
+ console.warn(`[NftService] getAllNftInstances failed for ${eachOwner}`, innerErr);
157
+ }
158
+ }
159
+ } catch (err) {
160
+ console.error(`[NftDetectionService] getFullNftInstancesByCollection error for ${collectionId}`, err);
161
+ return {
162
+ items: [],
163
+ collections: []
164
+ };
165
+ }
166
+ return {
167
+ items: items,
168
+ collections: collections
169
+ };
170
+ }
171
+ }
@@ -0,0 +1,11 @@
1
+ import { _ChainInfo } from '@subwallet/chain-list/types';
2
+ import KoniState from '@subwallet/extension-base/koni/background/handlers/State';
3
+ import { BaseNftHandler } from '@subwallet/extension-base/services/nft-service/nft-handlers/base-nft-handler';
4
+ export interface NftHandlerDescriptor {
5
+ id: string;
6
+ supports(chainInfo: _ChainInfo): boolean;
7
+ supportsFetchFullNftList: boolean;
8
+ create(chainSlug: string, state: KoniState): BaseNftHandler;
9
+ }
10
+ export declare function isNftV2Chain(chainInfo: _ChainInfo, registry: NftHandlerDescriptor[]): boolean;
11
+ export declare const NFT_HANDLER_REGISTRY: NftHandlerDescriptor[];
@@ -0,0 +1,29 @@
1
+ // Copyright 2019-2022 @subwallet/extension-base authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { NFT_CHAIN_GROUPS_MIGRATED } from '@subwallet/extension-base/services/chain-service/constants';
5
+ import { _isChainSupportEvmNft } from '@subwallet/extension-base/services/chain-service/utils';
6
+ import { EvmNftHandler } from '@subwallet/extension-base/services/nft-service/nft-handlers/evm/evm-nft-handler';
7
+ import { UniqueNftHandler } from '@subwallet/extension-base/services/nft-service/nft-handlers/unique/unique-nft-handler';
8
+ export function isNftV2Chain(chainInfo, registry) {
9
+ return registry.some(desc => desc.supports(chainInfo));
10
+ }
11
+
12
+ // todo list: only update into when migration
13
+ export const NFT_HANDLER_REGISTRY = [{
14
+ id: 'evm',
15
+ supports: chainInfo => _isChainSupportEvmNft(chainInfo),
16
+ supportsFetchFullNftList: true,
17
+ create: chain => new EvmNftHandler(chain)
18
+ }, {
19
+ id: 'unique_network',
20
+ supports: chainInfo => NFT_CHAIN_GROUPS_MIGRATED.unique_network.includes(chainInfo.slug),
21
+ supportsFetchFullNftList: false,
22
+ create: chain => new UniqueNftHandler(chain)
23
+ }
24
+ // {
25
+ // id: 'ordinal',
26
+ // supports: (chainInfo) => _isSupportOrdinal(chainInfo.slug),
27
+ // create: (chain, state) => new OrdinalNftHandler(chain, state)
28
+ // }
29
+ ];
@@ -0,0 +1,12 @@
1
+ import { NftDetailRequest, NftFullListRequest, NftItem } from '@subwallet/extension-base/background/KoniTypes';
2
+ import { BaseNftHandler, NftHandlerResult } from '../base-nft-handler';
3
+ export declare class UniqueNftHandler extends BaseNftHandler {
4
+ filterAddresses(addresses: string[]): string[];
5
+ private mapUniqueCollections;
6
+ private mapUniqueRootNftToItem;
7
+ private mapBundleTreeToNftItem;
8
+ fetchNftBundle(collectionId: number | string, tokenId: string, topmostOwner: string): Promise<NftItem | null>;
9
+ fetchPreview(addresses: string[]): Promise<NftHandlerResult>;
10
+ fetchFullListNftOfACollection(request: NftFullListRequest): Promise<NftHandlerResult>;
11
+ fetchNftDetail(request: NftDetailRequest): Promise<NftHandlerResult>;
12
+ }
@@ -0,0 +1,177 @@
1
+ // Copyright 2019-2022 @subwallet/extension-koni authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { ChainType } from '@subwallet/extension-base/background/KoniTypes';
5
+ import { getAddressesByChainType } from '@subwallet/extension-base/utils';
6
+ import subwalletApiSdk from '@subwallet-monorepos/subwallet-services-sdk';
7
+ import { BaseNftHandler } from "../base-nft-handler.js";
8
+ export class UniqueNftHandler extends BaseNftHandler {
9
+ filterAddresses(addresses) {
10
+ return getAddressesByChainType(addresses, [ChainType.SUBSTRATE]);
11
+ }
12
+ mapUniqueCollections(raws) {
13
+ var _raws$collectionCover;
14
+ return {
15
+ collectionId: raws.collectionId.toString(),
16
+ chain: this.chain,
17
+ collectionName: raws.collectionName || 'Unknown Collection',
18
+ image: ((_raws$collectionCover = raws.collectionCover) === null || _raws$collectionCover === void 0 ? void 0 : _raws$collectionCover.url) || undefined,
19
+ externalUrl: undefined,
20
+ originAsset: undefined
21
+ };
22
+ }
23
+ mapUniqueRootNftToItem(raw, owner) {
24
+ return {
25
+ id: raw.tokenId.toString(),
26
+ chain: this.chain,
27
+ collectionId: raw.collectionId.toString(),
28
+ name: raw.name || `#${raw.tokenId}`,
29
+ image: raw.image || undefined,
30
+ description: raw.description || undefined,
31
+ owner: owner,
32
+ isBundle: false,
33
+ properties: null
34
+ };
35
+ }
36
+ mapBundleTreeToNftItem(node, topmostOwner, level = 0, parentId) {
37
+ const item = {
38
+ id: node.tokenId.toString(),
39
+ chain: this.chain,
40
+ collectionId: node.collectionId.toString(),
41
+ name: node.name || `#${node.tokenId}`,
42
+ image: node.image || undefined,
43
+ description: node.description || undefined,
44
+ owner: topmostOwner,
45
+ isBundle: node.nested && node.nested.length > 0 && level === 0,
46
+ properties: null,
47
+ nestingLevel: level,
48
+ parentId: level > 0 ? parentId : undefined
49
+ };
50
+ if (node.nested && node.nested.length > 0) {
51
+ item.nestingTokens = node.nested.map(child => this.mapBundleTreeToNftItem(child, topmostOwner, level + 1, item.id));
52
+ }
53
+ return item;
54
+ }
55
+ async fetchNftBundle(collectionId, tokenId, topmostOwner) {
56
+ const api = subwalletApiSdk.uniqueNftDetectionApi;
57
+ if (!api) {
58
+ return null;
59
+ }
60
+ try {
61
+ const treeData = await api.getNftBundleTree(collectionId, tokenId);
62
+ if (!treeData) {
63
+ return null;
64
+ }
65
+ return this.mapBundleTreeToNftItem(treeData, topmostOwner, 0, tokenId);
66
+ } catch (e) {
67
+ console.error('[UniqueNftHandler] Failed to fetch bundle tree', e);
68
+ return null;
69
+ }
70
+ }
71
+
72
+ // ==================== MAIN HANDLER ====================
73
+
74
+ async fetchPreview(addresses) {
75
+ const items = [];
76
+ const collectionsMap = new Map();
77
+ const api = subwalletApiSdk.uniqueNftDetectionApi;
78
+ if (!api) {
79
+ return {
80
+ items: [],
81
+ collections: []
82
+ };
83
+ }
84
+ try {
85
+ await Promise.all(addresses.map(async address => {
86
+ // 1. Collections
87
+ const sdkCollections = await api.getUniqueCollectionsByTokenOwner(address);
88
+ for (const col of sdkCollections) {
89
+ const collection = this.mapUniqueCollections(col);
90
+ if (!collectionsMap.has(collection.collectionId)) {
91
+ collectionsMap.set(collection.collectionId, collection);
92
+ }
93
+ }
94
+
95
+ // 2. Root NFTs
96
+ const sdkNfts = await api.getAllUniqueRootNfts({
97
+ owner: address
98
+ });
99
+ for (const rootNft of sdkNfts) {
100
+ items.push(this.mapUniqueRootNftToItem(rootNft, address));
101
+ }
102
+ }));
103
+ } catch (e) {
104
+ console.error(`[UniqueNftHandler] Failed to fetch for ${this.chain}`, e);
105
+ }
106
+ return {
107
+ items,
108
+ collections: Array.from(collectionsMap.values())
109
+ };
110
+ }
111
+ async fetchFullListNftOfACollection(request) {
112
+ const items = [];
113
+ const collections = [];
114
+ const {
115
+ collectionId,
116
+ owners,
117
+ tokenIds
118
+ } = request;
119
+ if (!collectionId || !owners || !tokenIds) {
120
+ console.warn('[NftService] missing params for getFullNftInstancesByCollection');
121
+ return {
122
+ items,
123
+ collections
124
+ };
125
+ }
126
+ for (const id of tokenIds) {
127
+ const fullTree = await this.fetchNftBundle(collectionId, id, owners[0]);
128
+ if (fullTree) {
129
+ items.push(fullTree);
130
+ }
131
+ }
132
+ return {
133
+ items: items,
134
+ collections: collections
135
+ };
136
+ }
137
+ async fetchNftDetail(request) {
138
+ const items = [];
139
+ const collections = [];
140
+ const api = subwalletApiSdk.uniqueNftDetectionApi;
141
+ if (!api) {
142
+ return {
143
+ items: [],
144
+ collections: []
145
+ };
146
+ }
147
+ const {
148
+ collectionId,
149
+ tokenId
150
+ } = request;
151
+ if (!collectionId || !tokenId) {
152
+ return {
153
+ items,
154
+ collections
155
+ };
156
+ }
157
+ try {
158
+ const rawNft = await api.getNftDetail(collectionId, tokenId);
159
+ if (!rawNft) {
160
+ return {
161
+ items: [],
162
+ collections: []
163
+ };
164
+ }
165
+ const nftItem = this.mapUniqueRootNftToItem(rawNft, rawNft.owner);
166
+ return {
167
+ items: [nftItem],
168
+ collections: []
169
+ };
170
+ } catch (e) {
171
+ return {
172
+ items: [],
173
+ collections: []
174
+ };
175
+ }
176
+ }
177
+ }
@@ -83,7 +83,7 @@ export default class DatabaseService {
83
83
  addNft(address: string, nft: NftItem): Promise<unknown>;
84
84
  handleNftTransfer(chain: string, addresses: string[], nftItem: NftItem): import("dexie").PromiseExtended<number>;
85
85
  removeNfts(chain: string, address: string, collectionId: string, nftIds: string[]): import("dexie").PromiseExtended<number>;
86
- removeNftsByAddress(address: string): import("dexie").PromiseExtended<number>;
86
+ removeNftsByAddress(address: string[]): import("dexie").PromiseExtended<number>;
87
87
  updateChainStore(item: IChain): Promise<unknown>;
88
88
  bulkUpdateChainStore(data: IChain[]): Promise<unknown>;
89
89
  removeFromChainStore(chains: string[]): Promise<number>;
@@ -393,7 +393,7 @@ export default class DatabaseService {
393
393
  return this.stores.nft.removeNfts(chain, address, collectionId, nftIds);
394
394
  }
395
395
  removeNftsByAddress(address) {
396
- return this.stores.nft.removeNftsByAddress([address]);
396
+ return this.stores.nft.removeNftsByAddress(address);
397
397
  }
398
398
 
399
399
  // Chain