@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
@@ -4,175 +4,244 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.default = void 0;
8
- var _types = require("@subwallet/chain-list/types");
7
+ exports.NftService = void 0;
8
+ var _types = require("@subwallet/extension-base/services/base/types");
9
9
  var _utils = require("@subwallet/extension-base/services/chain-service/utils");
10
10
  var _utils2 = require("@subwallet/extension-base/utils");
11
- var _keyring = require("@subwallet/keyring");
12
- var _types2 = require("@subwallet/keyring/types");
13
- var _subwalletServicesSdk = _interopRequireDefault(require("@subwallet-monorepos/subwallet-services-sdk"));
11
+ var _uiKeyring = _interopRequireDefault(require("@subwallet/ui-keyring"));
12
+ var _rxjs = require("rxjs");
13
+ var _multiChainNftFetcher = require("./multi-chain-nft-fetcher");
14
14
  // Copyright 2019-2022 @subwallet/extension-base authors & contributors
15
15
  // SPDX-License-Identifier: Apache-2.0
16
16
 
17
- /**
18
- * NFT detection service
19
- * Responsible for managing NFT detection jobs per address
20
- */
17
+ const INITIAL_NFT_STATE = {
18
+ nftData: {
19
+ total: 0,
20
+ nftList: []
21
+ },
22
+ nftCollections: []
23
+ };
21
24
 
22
- function mapSdkToNftItem(rawInstance, chain, collectionId, owner) {
23
- var _rawInstance$token_ty, _rawInstance$token_ty2, _rawInstance$id;
24
- const metadata = rawInstance.metadata || {};
25
- const image = metadata.image || rawInstance.image_url || rawInstance.media_url || '';
26
- const attributes = Array.isArray(metadata.attributes) ? metadata.attributes : [];
27
- let rarity;
28
- const properties = {};
29
- for (const attr of attributes) {
30
- try {
31
- var _attr$trait_type;
32
- const key = (_attr$trait_type = attr.trait_type) === null || _attr$trait_type === void 0 ? void 0 : _attr$trait_type.trim();
33
- if (!key) {
34
- continue;
35
- }
36
- let value = attr.value;
37
- if (typeof value === 'string') {
38
- const lower = value.toLowerCase();
39
- if (lower === 'true') {
40
- value = true;
41
- } else if (lower === 'false') {
42
- value = false;
43
- }
44
- }
45
- properties[key] = value;
46
- if (key.toLowerCase() === 'rarity') {
47
- rarity = String(value);
48
- }
49
- } catch {}
50
- }
51
- const hasProperties = Object.keys(properties).length > 0;
52
- 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();
25
+ // HIGH PRIORITY no lazy
26
+ const IMMEDIATE_EVENTS = ['account.updateCurrent', 'account.add', 'account.remove'];
53
27
 
54
- // Only support ERC721
55
- if (normalizedType !== 'ERC721') {
56
- return null;
57
- }
58
- return {
59
- id: (_rawInstance$id = rawInstance.id) === null || _rawInstance$id === void 0 ? void 0 : _rawInstance$id.toString(),
60
- chain,
61
- collectionId,
62
- owner: rawInstance.owner || owner,
63
- originAsset: undefined,
64
- name: metadata.name || `#${rawInstance.id}`,
65
- image: (0, _utils2.baseParseIPFSUrl)(image),
66
- externalUrl: rawInstance.external_app_url || undefined,
67
- rarity,
68
- description: metadata.description || undefined,
69
- properties: hasProperties ? properties : null,
70
- type: normalizedType === 'ERC721' ? _types._AssetType.ERC721 : _types._AssetType.ERC721,
71
- // currently only support ERC721
72
- rmrk_ver: undefined,
73
- onChainOption: undefined,
74
- assetHubType: undefined
75
- };
76
- }
77
- function mapSdkToCollection(raw, chain) {
78
- var _raw$token_instances;
79
- const token = raw.token || {};
80
- return {
81
- // must-have
82
- collectionId: token.address_hash,
83
- chain,
84
- originAsset: undefined,
85
- // optional
86
- collectionName: token.name || token.symbol || 'Unknown Collection',
87
- image: token.icon_url || undefined,
88
- itemCount: Number(raw.amount) || ((_raw$token_instances = raw.token_instances) === null || _raw$token_instances === void 0 ? void 0 : _raw$token_instances.length) || 0,
89
- externalUrl: undefined
90
- };
91
- }
28
+ // LOW PRIORITY – lazy
29
+ const LAZY_EVENTS = ['asset.updateState', 'chain.add'];
92
30
  class NftService {
93
- inProgress = new Set();
31
+ NFT_INTERVAL_TIME = 2 * 60 * 60 * 1000; // 2 hours
32
+
33
+ nftStateSubject = new _rxjs.BehaviorSubject(INITIAL_NFT_STATE);
34
+ nftState$ = this.nftStateSubject.asObservable();
35
+ isReloading = false;
36
+ startPromiseHandler = (0, _utils2.createPromiseHandler)();
37
+ stopPromiseHandler = (0, _utils2.createPromiseHandler)();
38
+ status = _types.ServiceStatus.NOT_INITIALIZED;
39
+ get isStarted() {
40
+ return this.status === _types.ServiceStatus.STARTED;
41
+ }
94
42
  constructor(state) {
95
43
  this.state = state;
44
+ this.multiChainFetcher = new _multiChainNftFetcher.MultiChainNftFetcher(state);
45
+ }
46
+ async init() {
47
+ this.status = _types.ServiceStatus.INITIALIZING;
48
+ await this.state.eventService.waitKeyringReady;
49
+ await this.state.eventService.waitChainReady;
50
+ await this.loadCachedData();
51
+ this.status = _types.ServiceStatus.INITIALIZED;
52
+ this.state.eventService.onLazy(this.handleEvents.bind(this));
53
+ }
54
+ async loadCachedData() {
55
+ const [nftData, collections] = await Promise.all([this.state.getNft(), this.state.getNftCollection()]);
56
+ this.nftStateSubject.next({
57
+ nftData: nftData || {
58
+ total: 0,
59
+ nftList: []
60
+ },
61
+ nftCollections: collections || []
62
+ });
63
+ }
64
+ async start() {
65
+ if (this.status === _types.ServiceStatus.STOPPING) {
66
+ await this.waitForStopped();
67
+ }
68
+ if (this.isStarted || this.status === _types.ServiceStatus.STARTING) {
69
+ return this.waitForStarted();
70
+ }
71
+ this.status = _types.ServiceStatus.STARTING;
72
+ await this.refreshNftData();
73
+ this.status = _types.ServiceStatus.STARTED;
74
+ this.startPromiseHandler.resolve();
75
+ this.startScanNft();
76
+ }
77
+ async stop() {
78
+ if (this.status === _types.ServiceStatus.STARTING) {
79
+ await this.waitForStarted();
80
+ }
81
+ if (this.status === _types.ServiceStatus.STOPPED || this.status === _types.ServiceStatus.STOPPING) {
82
+ return this.waitForStopped();
83
+ }
84
+ this.status = _types.ServiceStatus.STOPPING;
85
+ this.stopScanNft();
86
+ this.stopPromiseHandler.resolve();
87
+ }
88
+ waitForStarted() {
89
+ return this.startPromiseHandler.promise;
90
+ }
91
+ waitForStopped() {
92
+ return this.stopPromiseHandler.promise;
93
+ }
94
+ checkIfNftUpdateNeeded(events, eventTypes) {
95
+ if (!eventTypes.includes('chain.updateState')) {
96
+ return false;
97
+ }
98
+ const updatedChains = this.extractUpdatedChains(events);
99
+ return this.hasNftSupportedChainUpdate(updatedChains);
100
+ }
101
+ extractUpdatedChains(events) {
102
+ return events.filter(event => event.type === 'chain.updateState').map(event => event.data[0]);
103
+ }
104
+ hasNftSupportedChainUpdate(updatedChains) {
105
+ if (updatedChains.length === 0) {
106
+ return false;
107
+ }
108
+ const chainInfoMap = this.state.getServiceInfo().chainInfoMap;
109
+ return updatedChains.some(chainSlug => {
110
+ const chainInfo = chainInfoMap[chainSlug];
111
+ return this.isChainNftSupported(chainInfo);
112
+ });
113
+ }
114
+ isChainNftSupported(chainInfo) {
115
+ return (0, _utils._isChainSupportNativeNft)(chainInfo) || (0, _utils._isChainSupportEvmNft)(chainInfo) || (0, _utils._isChainSupportWasmNft)(chainInfo);
116
+ }
117
+ handleImmediateRefresh(address) {
118
+ this.state.resetNft(address);
119
+ this.refreshNftData().catch(console.error);
96
120
  }
97
- async fetchEvmCollectionsWithPreview(addresses) {
98
- for (const address of addresses) {
99
- const type = (0, _keyring.getKeypairTypeByAddress)(address);
100
- const typeValid = [..._types2.EthereumKeypairTypes].includes(type);
101
- if (typeValid) {
102
- if (this.inProgress.has(address)) {
103
- console.log(`[NftService] ${address} already running`);
104
- continue;
105
- }
106
- this.inProgress.add(address);
107
- try {
108
- const nftDetectionApi = _subwalletServicesSdk.default.nftDetectionApi;
109
- if (!(nftDetectionApi !== null && nftDetectionApi !== void 0 && nftDetectionApi.getEvmNftCollectionsByAddress)) {
110
- console.warn('[NftService] NftDetectionApi not available');
111
- continue;
112
- }
113
- const rawData = await nftDetectionApi.getEvmNftCollectionsByAddress(address);
114
- const allItems = [];
115
- const allCollections = [];
116
- for (const [chain, collections] of Object.entries(rawData)) {
117
- if (!Array.isArray(collections)) {
118
- continue;
119
- }
120
- for (const col of collections) {
121
- const mappedCollection = mapSdkToCollection(col, chain);
122
- allCollections.push(mappedCollection);
123
- if (Array.isArray(col.token_instances)) {
124
- const items = col.token_instances.map(inst => mapSdkToNftItem(inst, chain, mappedCollection.collectionId, address)).filter(i => Boolean(i));
125
- allItems.push(...items);
126
- }
127
- }
128
- }
129
- await this.state.handleDetectedNftCollections(allCollections);
130
- await this.state.handleDetectedNfts(address, allItems);
131
- } catch (err) {
132
- console.warn(`[NftService] detect error for ${address}`, err);
133
- } finally {
134
- this.inProgress.delete(address);
135
- }
121
+ scheduleLazyRefresh(delay) {
122
+ (0, _utils2.addLazy)('nft.refresh', () => {
123
+ if (!this.isReloading && this.isStarted) {
124
+ this.refreshNftData().catch(console.error);
136
125
  }
126
+ }, delay, undefined, true);
127
+ }
128
+ handleEvents(events, eventTypes) {
129
+ const LAZY_REFRESH_DELAY = 1800;
130
+ const address = this.state.keyringService.context.currentAccount.proxyId;
131
+ const hasImmediateEvent = IMMEDIATE_EVENTS.some(event => eventTypes.includes(event));
132
+ const hasLazyEvent = LAZY_EVENTS.some(event => eventTypes.includes(event));
133
+ const needsNftUpdate = this.checkIfNftUpdateNeeded(events, eventTypes);
134
+ if (hasImmediateEvent || needsNftUpdate) {
135
+ this.handleImmediateRefresh(address);
136
+ return;
137
+ }
138
+ if (hasLazyEvent) {
139
+ this.scheduleLazyRefresh(LAZY_REFRESH_DELAY);
137
140
  }
138
141
  }
139
- async getFullNftInstancesByCollection(request) {
140
- const {
141
- chainInfo,
142
- contractAddress,
143
- owners
144
- } = request;
145
- const chainId = (0, _utils._getEvmChainId)(chainInfo);
146
- if (!contractAddress || !owners || !chainId) {
147
- console.warn('[NftService] missing params for getFullNftInstancesByCollection');
142
+ async fetchFullListNftOfACollection(request) {
143
+ if (this.isReloading) {
148
144
  return false;
149
145
  }
150
146
  try {
151
- const nftDetectionApi = _subwalletServicesSdk.default.nftDetectionApi;
152
- if (!(nftDetectionApi !== null && nftDetectionApi !== void 0 && nftDetectionApi.getAllNftInstances)) {
153
- console.warn('[NftService] getAllNftInstances not available');
154
- return false;
155
- }
156
- const ownerList = Array.isArray(owners) ? owners : [owners];
157
- for (const eachOwner of ownerList) {
158
- try {
159
- const instances = await nftDetectionApi.getAllNftInstances(contractAddress, eachOwner, chainId.toString());
160
- if (!Array.isArray(instances)) {
161
- continue;
162
- }
163
- console.log('FOR TESTER (before)', instances);
164
- const nftList = instances.map(inst => mapSdkToNftItem(inst, chainInfo.slug, contractAddress, eachOwner)).filter(i => Boolean(i));
165
- console.log('FOR TESTER (after)', nftList);
166
- await this.state.handleDetectedNfts(eachOwner, nftList);
167
- } catch (innerErr) {
168
- console.warn(`[NftService] getAllNftInstances failed for ${eachOwner}`, innerErr);
169
- }
170
- }
147
+ const result = await this.multiChainFetcher.fetchFullListNftOfACollection(request);
148
+
149
+ // Persist DB
150
+ this.persistNftData({
151
+ items: result.items,
152
+ collections: result.collections
153
+ });
171
154
  return true;
172
- } catch (err) {
173
- console.error(`[NftDetectionService] getFullNftInstancesByCollection error for ${contractAddress}`, err);
155
+ } catch (e) {
156
+ console.error('[NftServiceV2] fetchFullListNftOfaCollection failed', e);
174
157
  return false;
175
158
  }
176
159
  }
160
+ async fetchNftDetail(request) {
161
+ if (this.isReloading) {
162
+ return null;
163
+ }
164
+ try {
165
+ const result = await this.multiChainFetcher.fetchNftDetail(request);
166
+ return result.items[0];
167
+ } catch (e) {
168
+ console.error('[NftServiceV2] fetchNftDetail failed', e);
169
+ return null;
170
+ }
171
+ }
172
+ startScanNft() {
173
+ this.stopScanNft();
174
+ const scanNft = () => {
175
+ if (!this.isStarted || this.isReloading) {
176
+ return;
177
+ }
178
+ this.refreshNftData().catch(console.error);
179
+ };
180
+ this._intervalFetchNft = setInterval(scanNft, this.NFT_INTERVAL_TIME);
181
+ }
182
+ stopScanNft() {
183
+ this._intervalFetchNft && clearInterval(this._intervalFetchNft);
184
+ this._intervalFetchNft = undefined;
185
+ }
186
+ persistNftData(result) {
187
+ try {
188
+ for (const item of result.items) {
189
+ const sender = _uiKeyring.default.getPair(item.owner);
190
+ this.state.updateNftData(item.chain, item, sender.address || item.owner);
191
+ }
192
+ for (const col of result.collections) {
193
+ this.state.setNftCollection(col.chain, col);
194
+ }
195
+ } catch (error) {
196
+ console.error('[NftServiceV2] Persist failed:', error);
197
+ }
198
+ }
199
+ async refreshNftData() {
200
+ if (this.isReloading) {
201
+ return;
202
+ }
203
+ this.isReloading = true;
204
+ try {
205
+ const addresses = this.state.keyringService.context.getDecodedAddresses();
206
+ const activeChains = Object.keys(this.state.getActiveChainInfoMap());
207
+ if (addresses.length === 0 || activeChains.length === 0) {
208
+ this.nftStateSubject.next(INITIAL_NFT_STATE);
209
+ return;
210
+ }
211
+ const result = await this.multiChainFetcher.fetch(addresses, activeChains);
212
+ this.persistNftData(result);
213
+ this.nftStateSubject.next({
214
+ nftData: {
215
+ total: result.items.length,
216
+ nftList: result.items
217
+ },
218
+ nftCollections: result.collections
219
+ });
220
+ } catch (error) {
221
+ console.error('[NftService] Refresh failed:', error);
222
+ this.nftStateSubject.next({
223
+ ...this.nftStateSubject.getValue()
224
+ });
225
+ } finally {
226
+ this.isReloading = false;
227
+ }
228
+ }
229
+
230
+ /** Subscribe NFT state */
231
+ subscribeNftItem() {
232
+ return this.nftState$;
233
+ }
234
+ subscribeNftCollection() {
235
+ const getChains = () => this.state.activeChainSlugs;
236
+ return this.state.dbService.stores.nftCollection.subscribeNftCollection(getChains);
237
+ }
238
+
239
+ // TODO: Move NFT reset logic to this function after migration is complete
240
+ async forceReload() {
241
+ this.isReloading = true;
242
+ await (0, _utils2.waitTimeout)(1800);
243
+ this.isReloading = false;
244
+ await this.refreshNftData().catch(console.error);
245
+ }
177
246
  }
178
- exports.default = NftService;
247
+ exports.NftService = NftService;
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.MultiChainNftFetcher = void 0;
7
+ var _registry = require("@subwallet/extension-base/services/nft-service/nft-handlers/registry");
8
+ // Copyright 2019-2022 @subwallet/extension-koni authors & contributors
9
+ // SPDX-License-Identifier: Apache-2.0
10
+
11
+ class MultiChainNftFetcher {
12
+ constructor(state) {
13
+ this.state = state;
14
+ }
15
+ handlerCache = new Map();
16
+ getOrCreate(chain, desc) {
17
+ const key = `${chain}:${desc.id}`;
18
+ let handler = this.handlerCache.get(key);
19
+ if (!handler) {
20
+ handler = desc.create(chain, this.state);
21
+ this.handlerCache.set(key, handler);
22
+ }
23
+ return handler;
24
+ }
25
+ getHandlersForChain(chainSlug) {
26
+ const chainInfo = this.state.chainService.getChainInfoByKey(chainSlug);
27
+ if (!chainInfo) {
28
+ return [];
29
+ }
30
+ return _registry.NFT_HANDLER_REGISTRY.filter(d => d.supports(chainInfo)).map(d => this.getOrCreate(chainSlug, d));
31
+ }
32
+ async fetch(addresses, chainSlugs) {
33
+ const allItems = [];
34
+ const allCollections = [];
35
+ const tasks = [];
36
+ for (const chain of chainSlugs) {
37
+ const handlers = this.getHandlersForChain(chain);
38
+ if (handlers.length === 0) {
39
+ console.warn(`[NftFetcher] No handler for chain: ${chain}`);
40
+ continue;
41
+ }
42
+ for (const handler of handlers) {
43
+ const handlerAddresses = handler.filterAddresses(addresses);
44
+ const task = handler.fetchPreview(handlerAddresses).then(result => {
45
+ allItems.push(...result.items);
46
+ allCollections.push(...result.collections);
47
+ }).catch(err => {
48
+ console.error(`[NftFetcher] Handler failed on ${chain}: handler.id`, err);
49
+ });
50
+ tasks.push(task);
51
+ }
52
+ }
53
+ await Promise.all(tasks);
54
+
55
+ // DEDUPLICATE
56
+ // Todo: Move logic DEDUPLICATE to each handler
57
+ const seenItemIds = new Set();
58
+ const seenCollectionKeys = new Set();
59
+ const uniqueItems = [];
60
+ const uniqueCollections = [];
61
+ for (const item of allItems) {
62
+ if (!seenItemIds.has(item.id)) {
63
+ seenItemIds.add(item.id);
64
+ uniqueItems.push(item);
65
+ }
66
+ }
67
+ for (const col of allCollections) {
68
+ const key = `${col.chain}:${col.collectionId}`;
69
+ if (!seenCollectionKeys.has(key)) {
70
+ seenCollectionKeys.add(key);
71
+ uniqueCollections.push(col);
72
+ }
73
+ }
74
+ return {
75
+ items: uniqueItems,
76
+ collections: uniqueCollections
77
+ };
78
+ }
79
+ async fetchFullListNftOfACollection(request) {
80
+ const {
81
+ chainInfo,
82
+ collectionId,
83
+ owners,
84
+ tokenIds
85
+ } = request;
86
+ const items = [];
87
+ const collections = [];
88
+ const handlers = this.getHandlersForChain(chainInfo.slug);
89
+ for (const handler of handlers) {
90
+ // Todo: Improve the full-list fetch feature
91
+ // if (!handler.supportsFetchFullNftList) {
92
+ // continue;
93
+ // }
94
+
95
+ const handlerOwners = handler.filterAddresses(owners);
96
+ try {
97
+ const result = await handler.fetchFullListNftOfACollection({
98
+ collectionId: collectionId,
99
+ owners: handlerOwners,
100
+ tokenIds: tokenIds,
101
+ chainInfo
102
+ });
103
+ items.push(...result.items);
104
+ collections.push(...result.collections);
105
+ } catch (e) {
106
+ console.error('[NftFetcher] fetchCollection failed', e);
107
+ }
108
+ }
109
+ return {
110
+ items,
111
+ collections
112
+ };
113
+ }
114
+ async fetchNftDetail(request) {
115
+ const {
116
+ chainSlug,
117
+ collectionId,
118
+ tokenId
119
+ } = request;
120
+ const items = [];
121
+ const collections = [];
122
+ const handlers = this.getHandlersForChain(chainSlug);
123
+ for (const handler of handlers) {
124
+ // Todo: Improve the detail nft fetch feature
125
+ // if (!handler.supportsFetchFullNftList) {
126
+ // continue;
127
+ // }
128
+
129
+ try {
130
+ return await handler.fetchNftDetail({
131
+ collectionId: collectionId,
132
+ tokenId: tokenId,
133
+ chainSlug
134
+ });
135
+ } catch (e) {
136
+ console.error('[NftFetcher] fetchCollection failed', e);
137
+ }
138
+ }
139
+ return {
140
+ items,
141
+ collections
142
+ };
143
+ }
144
+ }
145
+ exports.MultiChainNftFetcher = MultiChainNftFetcher;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.BaseNftHandler = void 0;
7
+ // Copyright 2019-2022 @subwallet/extension-base authors & contributors
8
+ // SPDX-License-Identifier: Apache-2.0
9
+
10
+ const EMPTY_NFT_RESULT = {
11
+ items: [],
12
+ collections: []
13
+ };
14
+ class BaseNftHandler {
15
+ constructor(chain) {
16
+ this.chain = chain;
17
+ }
18
+ // Optional method - subclasses can choose to implement or not
19
+ fetchFullListNftOfACollection(_request) {
20
+ return Promise.resolve(EMPTY_NFT_RESULT);
21
+ }
22
+
23
+ // Optional method - subclasses can choose to implement or not
24
+ fetchNftDetail(_request) {
25
+ return Promise.resolve(EMPTY_NFT_RESULT);
26
+ }
27
+ }
28
+ exports.BaseNftHandler = BaseNftHandler;