@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.
- package/background/KoniTypes.d.ts +13 -3
- package/cjs/core/substrate/system-pallet.js +3 -0
- package/cjs/koni/api/nft/index.js +0 -14
- package/cjs/koni/background/cron.js +0 -17
- package/cjs/koni/background/handlers/Extension.js +6 -5
- package/cjs/koni/background/handlers/State.js +24 -6
- package/cjs/packageInfo.js +1 -1
- package/cjs/services/balance-service/helpers/process.js +49 -21
- package/cjs/services/balance-service/index.js +2 -2
- package/cjs/services/chain-service/constants.js +6 -2
- package/cjs/services/earning-service/handlers/special.js +3 -2
- package/cjs/services/nft-service/index.js +219 -150
- package/cjs/services/nft-service/multi-chain-nft-fetcher.js +145 -0
- package/cjs/services/nft-service/nft-handlers/base-nft-handler.js +28 -0
- package/cjs/services/nft-service/nft-handlers/evm/evm-nft-handler.js +179 -0
- package/cjs/services/nft-service/nft-handlers/registry.js +37 -0
- package/cjs/services/nft-service/nft-handlers/unique/unique-nft-handler.js +187 -0
- package/cjs/services/storage-service/DatabaseService.js +1 -1
- package/core/substrate/system-pallet.js +3 -0
- package/koni/api/nft/index.js +1 -15
- package/koni/background/cron.d.ts +0 -1
- package/koni/background/cron.js +1 -18
- package/koni/background/handlers/Extension.d.ts +1 -0
- package/koni/background/handlers/Extension.js +6 -5
- package/koni/background/handlers/State.d.ts +8 -2
- package/koni/background/handlers/State.js +24 -6
- package/package.json +31 -6
- package/packageInfo.js +1 -1
- package/services/balance-service/helpers/process.d.ts +1 -1
- package/services/balance-service/helpers/process.js +48 -21
- package/services/balance-service/index.js +2 -2
- package/services/chain-service/constants.d.ts +3 -0
- package/services/chain-service/constants.js +3 -0
- package/services/earning-service/handlers/special.js +4 -3
- package/services/nft-service/index.d.ts +42 -6
- package/services/nft-service/index.js +219 -151
- package/services/nft-service/multi-chain-nft-fetcher.d.ts +13 -0
- package/services/nft-service/multi-chain-nft-fetcher.js +138 -0
- package/services/nft-service/nft-handlers/base-nft-handler.d.ts +13 -0
- package/services/nft-service/nft-handlers/base-nft-handler.js +21 -0
- package/services/nft-service/nft-handlers/evm/evm-nft-handler.d.ts +9 -0
- package/services/nft-service/nft-handlers/evm/evm-nft-handler.js +171 -0
- package/services/nft-service/nft-handlers/registry.d.ts +11 -0
- package/services/nft-service/nft-handlers/registry.js +29 -0
- package/services/nft-service/nft-handlers/unique/unique-nft-handler.d.ts +12 -0
- package/services/nft-service/nft-handlers/unique/unique-nft-handler.js +177 -0
- package/services/storage-service/DatabaseService.d.ts +1 -1
- package/services/storage-service/DatabaseService.js +1 -1
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.EvmNftHandler = void 0;
|
|
8
|
+
var _types = require("@subwallet/chain-list/types");
|
|
9
|
+
var _KoniTypes = require("@subwallet/extension-base/background/KoniTypes");
|
|
10
|
+
var _utils = require("@subwallet/extension-base/services/chain-service/utils");
|
|
11
|
+
var _utils2 = require("@subwallet/extension-base/utils");
|
|
12
|
+
var _subwalletServicesSdk = _interopRequireDefault(require("@subwallet-monorepos/subwallet-services-sdk"));
|
|
13
|
+
var _baseNftHandler = require("../base-nft-handler");
|
|
14
|
+
// Copyright 2019-2022 @subwallet/extension-koni authors & contributors
|
|
15
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
16
|
+
|
|
17
|
+
class EvmNftHandler extends _baseNftHandler.BaseNftHandler {
|
|
18
|
+
filterAddresses(addresses) {
|
|
19
|
+
return (0, _utils2.getAddressesByChainType)(addresses, [_KoniTypes.ChainType.EVM]);
|
|
20
|
+
}
|
|
21
|
+
mapSdkToNftItem(rawInstance, collectionId, owner) {
|
|
22
|
+
var _rawInstance$token_ty, _rawInstance$id;
|
|
23
|
+
const metadata = rawInstance.metadata || {};
|
|
24
|
+
const image = metadata.image || rawInstance.image_url || rawInstance.media_url || '';
|
|
25
|
+
const attributes = Array.isArray(metadata.attributes) ? metadata.attributes : [];
|
|
26
|
+
let rarity;
|
|
27
|
+
const properties = {};
|
|
28
|
+
for (const attr of attributes) {
|
|
29
|
+
try {
|
|
30
|
+
var _attr$trait_type;
|
|
31
|
+
const key = (_attr$trait_type = attr.trait_type) === null || _attr$trait_type === void 0 ? void 0 : _attr$trait_type.trim();
|
|
32
|
+
if (!key) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
let value = attr.value;
|
|
36
|
+
if (typeof value === 'string') {
|
|
37
|
+
const lower = value.toLowerCase();
|
|
38
|
+
if (lower === 'true') {
|
|
39
|
+
value = true;
|
|
40
|
+
}
|
|
41
|
+
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
|
+
// ignore
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const normalizedType = (_rawInstance$token_ty = rawInstance.token_type) === null || _rawInstance$token_ty === void 0 ? void 0 : _rawInstance$token_ty.replace('-', '').toUpperCase();
|
|
54
|
+
if (!['ERC721'].includes(normalizedType)) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
id: ((_rawInstance$id = rawInstance.id) === null || _rawInstance$id === void 0 ? void 0 : _rawInstance$id.toString()) || '',
|
|
59
|
+
chain: this.chain,
|
|
60
|
+
collectionId,
|
|
61
|
+
owner: rawInstance.owner || owner,
|
|
62
|
+
name: metadata.name || `#${rawInstance.id}`,
|
|
63
|
+
image: (0, _utils2.baseParseIPFSUrl)(image),
|
|
64
|
+
externalUrl: rawInstance.external_app_url || undefined,
|
|
65
|
+
rarity,
|
|
66
|
+
description: metadata.description || undefined,
|
|
67
|
+
properties: Object.keys(properties).length > 0 ? properties : null,
|
|
68
|
+
type: normalizedType === 'ERC721' ? _types._AssetType.ERC721 : _types._AssetType.ERC721,
|
|
69
|
+
originAsset: undefined,
|
|
70
|
+
rmrk_ver: undefined,
|
|
71
|
+
onChainOption: undefined,
|
|
72
|
+
assetHubType: undefined
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
mapSdkToCollection(raw) {
|
|
76
|
+
var _raw$token_instances;
|
|
77
|
+
const token = raw.token || {};
|
|
78
|
+
return {
|
|
79
|
+
collectionId: token.address_hash,
|
|
80
|
+
chain: this.chain,
|
|
81
|
+
collectionName: token.name || token.symbol || 'Unknown Collection',
|
|
82
|
+
image: token.icon_url || undefined,
|
|
83
|
+
itemCount: Number(raw.amount) || ((_raw$token_instances = raw.token_instances) === null || _raw$token_instances === void 0 ? void 0 : _raw$token_instances.length) || 0,
|
|
84
|
+
externalUrl: undefined,
|
|
85
|
+
originAsset: undefined
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ==================== 1. PREVIEW – Used for cron / background ====================
|
|
90
|
+
async fetchPreview(addresses) {
|
|
91
|
+
const items = [];
|
|
92
|
+
const collections = [];
|
|
93
|
+
const api = _subwalletServicesSdk.default.nftDetectionApi;
|
|
94
|
+
if (!(api !== null && api !== void 0 && api.getEvmNftCollectionsByAddress)) {
|
|
95
|
+
console.warn('[EvmNftHandler] Preview API not available');
|
|
96
|
+
return {
|
|
97
|
+
items,
|
|
98
|
+
collections
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
for (const address of addresses) {
|
|
102
|
+
try {
|
|
103
|
+
const rawData = await api.getEvmNftCollectionsByAddress(address);
|
|
104
|
+
for (const [chain, sdkCollections] of Object.entries(rawData)) {
|
|
105
|
+
if (chain !== this.chain || !Array.isArray(sdkCollections)) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
for (const col of sdkCollections) {
|
|
109
|
+
const collection = this.mapSdkToCollection(col);
|
|
110
|
+
collections.push(collection);
|
|
111
|
+
if (Array.isArray(col.token_instances)) {
|
|
112
|
+
const mapped = col.token_instances.map(inst => this.mapSdkToNftItem(inst, collection.collectionId, address)).filter(i => i !== null);
|
|
113
|
+
items.push(...mapped);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
} catch (error) {
|
|
118
|
+
console.error(`[EvmNftHandler] Preview failed for ${address}`, error);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
items: items,
|
|
123
|
+
collections: collections
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ==================== 2. FULL – At collection details screen ====================
|
|
128
|
+
async fetchFullListNftOfACollection(request) {
|
|
129
|
+
const items = [];
|
|
130
|
+
const collections = [];
|
|
131
|
+
const {
|
|
132
|
+
chainInfo,
|
|
133
|
+
collectionId,
|
|
134
|
+
owners
|
|
135
|
+
} = request;
|
|
136
|
+
const chainId = (0, _utils._getEvmChainId)(chainInfo);
|
|
137
|
+
if (!collectionId || !owners || !chainId) {
|
|
138
|
+
console.warn('[NftService] missing params for getFullNftInstancesByCollection');
|
|
139
|
+
return {
|
|
140
|
+
items,
|
|
141
|
+
collections
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
const nftDetectionApi = _subwalletServicesSdk.default.nftDetectionApi;
|
|
146
|
+
if (!(nftDetectionApi !== null && nftDetectionApi !== void 0 && nftDetectionApi.getAllNftInstances)) {
|
|
147
|
+
console.warn('[NftService] getAllNftInstances not available');
|
|
148
|
+
return {
|
|
149
|
+
items,
|
|
150
|
+
collections
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
const ownerList = Array.isArray(owners) ? owners : [owners];
|
|
154
|
+
for (const eachOwner of ownerList) {
|
|
155
|
+
try {
|
|
156
|
+
const instances = await nftDetectionApi.getAllNftInstances(collectionId, eachOwner, chainId.toString());
|
|
157
|
+
if (!Array.isArray(instances)) {
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
const mappedItems = instances.map(inst => this.mapSdkToNftItem(inst, collectionId, eachOwner)).filter(i => Boolean(i));
|
|
161
|
+
items.push(...mappedItems);
|
|
162
|
+
} catch (innerErr) {
|
|
163
|
+
console.warn(`[NftService] getAllNftInstances failed for ${eachOwner}`, innerErr);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
} catch (err) {
|
|
167
|
+
console.error(`[NftDetectionService] getFullNftInstancesByCollection error for ${collectionId}`, err);
|
|
168
|
+
return {
|
|
169
|
+
items: [],
|
|
170
|
+
collections: []
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
items: items,
|
|
175
|
+
collections: collections
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
exports.EvmNftHandler = EvmNftHandler;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.NFT_HANDLER_REGISTRY = void 0;
|
|
7
|
+
exports.isNftV2Chain = isNftV2Chain;
|
|
8
|
+
var _constants = require("@subwallet/extension-base/services/chain-service/constants");
|
|
9
|
+
var _utils = require("@subwallet/extension-base/services/chain-service/utils");
|
|
10
|
+
var _evmNftHandler = require("@subwallet/extension-base/services/nft-service/nft-handlers/evm/evm-nft-handler");
|
|
11
|
+
var _uniqueNftHandler = require("@subwallet/extension-base/services/nft-service/nft-handlers/unique/unique-nft-handler");
|
|
12
|
+
// Copyright 2019-2022 @subwallet/extension-base authors & contributors
|
|
13
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
14
|
+
|
|
15
|
+
function isNftV2Chain(chainInfo, registry) {
|
|
16
|
+
return registry.some(desc => desc.supports(chainInfo));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// todo list: only update into when migration
|
|
20
|
+
const NFT_HANDLER_REGISTRY = [{
|
|
21
|
+
id: 'evm',
|
|
22
|
+
supports: chainInfo => (0, _utils._isChainSupportEvmNft)(chainInfo),
|
|
23
|
+
supportsFetchFullNftList: true,
|
|
24
|
+
create: chain => new _evmNftHandler.EvmNftHandler(chain)
|
|
25
|
+
}, {
|
|
26
|
+
id: 'unique_network',
|
|
27
|
+
supports: chainInfo => _constants.NFT_CHAIN_GROUPS_MIGRATED.unique_network.includes(chainInfo.slug),
|
|
28
|
+
supportsFetchFullNftList: false,
|
|
29
|
+
create: chain => new _uniqueNftHandler.UniqueNftHandler(chain)
|
|
30
|
+
}
|
|
31
|
+
// {
|
|
32
|
+
// id: 'ordinal',
|
|
33
|
+
// supports: (chainInfo) => _isSupportOrdinal(chainInfo.slug),
|
|
34
|
+
// create: (chain, state) => new OrdinalNftHandler(chain, state)
|
|
35
|
+
// }
|
|
36
|
+
];
|
|
37
|
+
exports.NFT_HANDLER_REGISTRY = NFT_HANDLER_REGISTRY;
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.UniqueNftHandler = void 0;
|
|
8
|
+
var _KoniTypes = require("@subwallet/extension-base/background/KoniTypes");
|
|
9
|
+
var _utils = require("@subwallet/extension-base/utils");
|
|
10
|
+
var _subwalletServicesSdk = _interopRequireDefault(require("@subwallet-monorepos/subwallet-services-sdk"));
|
|
11
|
+
var _baseNftHandler = require("../base-nft-handler");
|
|
12
|
+
// Copyright 2019-2022 @subwallet/extension-koni authors & contributors
|
|
13
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
14
|
+
|
|
15
|
+
class UniqueNftHandler extends _baseNftHandler.BaseNftHandler {
|
|
16
|
+
filterAddresses(addresses) {
|
|
17
|
+
return (0, _utils.getAddressesByChainType)(addresses, [_KoniTypes.ChainType.SUBSTRATE]);
|
|
18
|
+
}
|
|
19
|
+
mapUniqueCollections(raws) {
|
|
20
|
+
var _raws$collectionCover;
|
|
21
|
+
return {
|
|
22
|
+
collectionId: raws.collectionId.toString(),
|
|
23
|
+
chain: this.chain,
|
|
24
|
+
collectionName: raws.collectionName || 'Unknown Collection',
|
|
25
|
+
image: ((_raws$collectionCover = raws.collectionCover) === null || _raws$collectionCover === void 0 ? void 0 : _raws$collectionCover.url) || undefined,
|
|
26
|
+
externalUrl: undefined,
|
|
27
|
+
originAsset: undefined
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
mapUniqueRootNftToItem(raw, owner) {
|
|
31
|
+
return {
|
|
32
|
+
id: raw.tokenId.toString(),
|
|
33
|
+
chain: this.chain,
|
|
34
|
+
collectionId: raw.collectionId.toString(),
|
|
35
|
+
name: raw.name || `#${raw.tokenId}`,
|
|
36
|
+
image: raw.image || undefined,
|
|
37
|
+
description: raw.description || undefined,
|
|
38
|
+
owner: owner,
|
|
39
|
+
isBundle: false,
|
|
40
|
+
properties: null
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
mapBundleTreeToNftItem(node, topmostOwner) {
|
|
44
|
+
let level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
|
|
45
|
+
let parentId = arguments.length > 3 ? arguments[3] : undefined;
|
|
46
|
+
const item = {
|
|
47
|
+
id: node.tokenId.toString(),
|
|
48
|
+
chain: this.chain,
|
|
49
|
+
collectionId: node.collectionId.toString(),
|
|
50
|
+
name: node.name || `#${node.tokenId}`,
|
|
51
|
+
image: node.image || undefined,
|
|
52
|
+
description: node.description || undefined,
|
|
53
|
+
owner: topmostOwner,
|
|
54
|
+
isBundle: node.nested && node.nested.length > 0 && level === 0,
|
|
55
|
+
properties: null,
|
|
56
|
+
nestingLevel: level,
|
|
57
|
+
parentId: level > 0 ? parentId : undefined
|
|
58
|
+
};
|
|
59
|
+
if (node.nested && node.nested.length > 0) {
|
|
60
|
+
item.nestingTokens = node.nested.map(child => this.mapBundleTreeToNftItem(child, topmostOwner, level + 1, item.id));
|
|
61
|
+
}
|
|
62
|
+
return item;
|
|
63
|
+
}
|
|
64
|
+
async fetchNftBundle(collectionId, tokenId, topmostOwner) {
|
|
65
|
+
const api = _subwalletServicesSdk.default.uniqueNftDetectionApi;
|
|
66
|
+
if (!api) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
const treeData = await api.getNftBundleTree(collectionId, tokenId);
|
|
71
|
+
if (!treeData) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
return this.mapBundleTreeToNftItem(treeData, topmostOwner, 0, tokenId);
|
|
75
|
+
} catch (e) {
|
|
76
|
+
console.error('[UniqueNftHandler] Failed to fetch bundle tree', e);
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ==================== MAIN HANDLER ====================
|
|
82
|
+
|
|
83
|
+
async fetchPreview(addresses) {
|
|
84
|
+
const items = [];
|
|
85
|
+
const collectionsMap = new Map();
|
|
86
|
+
const api = _subwalletServicesSdk.default.uniqueNftDetectionApi;
|
|
87
|
+
if (!api) {
|
|
88
|
+
return {
|
|
89
|
+
items: [],
|
|
90
|
+
collections: []
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
await Promise.all(addresses.map(async address => {
|
|
95
|
+
// 1. Collections
|
|
96
|
+
const sdkCollections = await api.getUniqueCollectionsByTokenOwner(address);
|
|
97
|
+
for (const col of sdkCollections) {
|
|
98
|
+
const collection = this.mapUniqueCollections(col);
|
|
99
|
+
if (!collectionsMap.has(collection.collectionId)) {
|
|
100
|
+
collectionsMap.set(collection.collectionId, collection);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// 2. Root NFTs
|
|
105
|
+
const sdkNfts = await api.getAllUniqueRootNfts({
|
|
106
|
+
owner: address
|
|
107
|
+
});
|
|
108
|
+
for (const rootNft of sdkNfts) {
|
|
109
|
+
items.push(this.mapUniqueRootNftToItem(rootNft, address));
|
|
110
|
+
}
|
|
111
|
+
}));
|
|
112
|
+
} catch (e) {
|
|
113
|
+
console.error(`[UniqueNftHandler] Failed to fetch for ${this.chain}`, e);
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
items,
|
|
117
|
+
collections: Array.from(collectionsMap.values())
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
async fetchFullListNftOfACollection(request) {
|
|
121
|
+
const items = [];
|
|
122
|
+
const collections = [];
|
|
123
|
+
const {
|
|
124
|
+
collectionId,
|
|
125
|
+
owners,
|
|
126
|
+
tokenIds
|
|
127
|
+
} = request;
|
|
128
|
+
if (!collectionId || !owners || !tokenIds) {
|
|
129
|
+
console.warn('[NftService] missing params for getFullNftInstancesByCollection');
|
|
130
|
+
return {
|
|
131
|
+
items,
|
|
132
|
+
collections
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
for (const id of tokenIds) {
|
|
136
|
+
const fullTree = await this.fetchNftBundle(collectionId, id, owners[0]);
|
|
137
|
+
if (fullTree) {
|
|
138
|
+
items.push(fullTree);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
items: items,
|
|
143
|
+
collections: collections
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
async fetchNftDetail(request) {
|
|
147
|
+
const items = [];
|
|
148
|
+
const collections = [];
|
|
149
|
+
const api = _subwalletServicesSdk.default.uniqueNftDetectionApi;
|
|
150
|
+
if (!api) {
|
|
151
|
+
return {
|
|
152
|
+
items: [],
|
|
153
|
+
collections: []
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
const {
|
|
157
|
+
collectionId,
|
|
158
|
+
tokenId
|
|
159
|
+
} = request;
|
|
160
|
+
if (!collectionId || !tokenId) {
|
|
161
|
+
return {
|
|
162
|
+
items,
|
|
163
|
+
collections
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
try {
|
|
167
|
+
const rawNft = await api.getNftDetail(collectionId, tokenId);
|
|
168
|
+
if (!rawNft) {
|
|
169
|
+
return {
|
|
170
|
+
items: [],
|
|
171
|
+
collections: []
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const nftItem = this.mapUniqueRootNftToItem(rawNft, rawNft.owner);
|
|
175
|
+
return {
|
|
176
|
+
items: [nftItem],
|
|
177
|
+
collections: []
|
|
178
|
+
};
|
|
179
|
+
} catch (e) {
|
|
180
|
+
return {
|
|
181
|
+
items: [],
|
|
182
|
+
collections: []
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
exports.UniqueNftHandler = UniqueNftHandler;
|
|
@@ -404,7 +404,7 @@ class DatabaseService {
|
|
|
404
404
|
return this.stores.nft.removeNfts(chain, address, collectionId, nftIds);
|
|
405
405
|
}
|
|
406
406
|
removeNftsByAddress(address) {
|
|
407
|
-
return this.stores.nft.removeNftsByAddress(
|
|
407
|
+
return this.stores.nft.removeNftsByAddress(address);
|
|
408
408
|
}
|
|
409
409
|
|
|
410
410
|
// Chain
|
|
@@ -43,6 +43,9 @@ function _getAppliedExistentialDeposit(accountInfo, existentialDeposit, strictMo
|
|
|
43
43
|
if (strictMode) {
|
|
44
44
|
return bnExistentialDeposit;
|
|
45
45
|
}
|
|
46
|
+
if (accountInfo.data.free.toString() === existentialDeposit) {
|
|
47
|
+
return BigInt(0);
|
|
48
|
+
}
|
|
46
49
|
return _canAccountBeReaped(accountInfo) ? BigInt(0) : bnExistentialDeposit; // account for ED here will go better with max transfer logic
|
|
47
50
|
}
|
|
48
51
|
function _getSystemPalletTransferableV2(accountInfo, existentialDeposit, strictMode) {
|
package/koni/api/nft/index.js
CHANGED
|
@@ -14,7 +14,7 @@ import { UniqueNftApi } from '@subwallet/extension-base/koni/api/nft/unique_netw
|
|
|
14
14
|
import { VaraNftApi } from '@subwallet/extension-base/koni/api/nft/vara_nft';
|
|
15
15
|
import { WasmNftApi } from '@subwallet/extension-base/koni/api/nft/wasm_nft';
|
|
16
16
|
import { _NFT_CHAIN_GROUP } from '@subwallet/extension-base/services/chain-service/constants';
|
|
17
|
-
import {
|
|
17
|
+
import { _isChainSupportNativeNft, _isChainSupportWasmNft, _isSupportOrdinal } from '@subwallet/extension-base/services/chain-service/utils';
|
|
18
18
|
import { getAddressesByChainType, targetIsWeb } from '@subwallet/extension-base/utils';
|
|
19
19
|
import AssetHubNftsPalletApi from "./assethub_nft/index.js";
|
|
20
20
|
import { RariNftApi } from "./rari/index.js";
|
|
@@ -33,8 +33,6 @@ function createSubstrateNftApi(chain, substrateApi, addresses) {
|
|
|
33
33
|
return [new AssetHubUniquesPalletApi(substrateApi, substrateAddresses, chain), new AssetHubNftsPalletApi(substrateApi, substrateAddresses, chain)];
|
|
34
34
|
} else if (_NFT_CHAIN_GROUP.statemint.includes(chain)) {
|
|
35
35
|
return [new AssetHubUniquesPalletApi(substrateApi, substrateAddresses, chain), new AssetHubNftsPalletApi(substrateApi, substrateAddresses, chain)];
|
|
36
|
-
} else if (_NFT_CHAIN_GROUP.unique_network.includes(chain)) {
|
|
37
|
-
return [new UniqueNftApi(chain, substrateAddresses)];
|
|
38
36
|
} else if (_NFT_CHAIN_GROUP.unique_evm.includes(chain)) {
|
|
39
37
|
return [new UniqueNftApi(chain, evmAddresses)];
|
|
40
38
|
} else if (_NFT_CHAIN_GROUP.bitcountry.includes(chain)) {
|
|
@@ -56,10 +54,6 @@ function createWasmNftApi(chain, apiProps, addresses) {
|
|
|
56
54
|
const substrateAddresses = getAddressesByChainType(addresses, [ChainType.SUBSTRATE]);
|
|
57
55
|
return new WasmNftApi(apiProps, substrateAddresses, chain);
|
|
58
56
|
}
|
|
59
|
-
function createWeb3NftApi(chain, evmApi, addresses) {
|
|
60
|
-
const evmAddresses = getAddressesByChainType(addresses, [ChainType.EVM]);
|
|
61
|
-
return new EvmNftApi(evmApi, evmAddresses, chain);
|
|
62
|
-
}
|
|
63
57
|
const createOrdinalApi = (chain, subscanChain, addresses) => {
|
|
64
58
|
return new OrdinalNftApi(addresses, chain, subscanChain);
|
|
65
59
|
};
|
|
@@ -128,14 +122,6 @@ export class NftHandler {
|
|
|
128
122
|
}
|
|
129
123
|
}
|
|
130
124
|
}
|
|
131
|
-
if (_isChainSupportEvmNft(chainInfo)) {
|
|
132
|
-
if (this.evmApiMap[chain]) {
|
|
133
|
-
const handler = createWeb3NftApi(chain, this.evmApiMap[chain], evmAddresses);
|
|
134
|
-
if (handler) {
|
|
135
|
-
this.handlers.push(handler);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
125
|
if (chain === 'unique_evm') {
|
|
140
126
|
const handlers = createSubstrateNftApi(chain, null, evmAddresses);
|
|
141
127
|
if (handlers && !!handlers.length) {
|
|
@@ -29,7 +29,6 @@ export declare class KoniCron {
|
|
|
29
29
|
refreshNft: (address: string, apiMap: ApiMap, smartContractNfts: _ChainAsset[], chainInfoMap: Record<string, _ChainInfo>) => () => void;
|
|
30
30
|
resetNft: (newAddress: string) => void;
|
|
31
31
|
checkNetworkAvailable: (serviceInfo: ServiceInfo) => boolean;
|
|
32
|
-
detectEvmCollectionNft: (address: string) => () => void;
|
|
33
32
|
reloadNft(): Promise<boolean>;
|
|
34
33
|
reloadStaking(): Promise<boolean>;
|
|
35
34
|
private needUpdateNft;
|
package/koni/background/cron.js
CHANGED
|
@@ -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 {
|
|
4
|
+
import { CRON_REFRESH_CHAIN_STAKING_METADATA, CRON_REFRESH_MKT_CAMPAIGN_INTERVAL, CRON_REFRESH_NFT_INTERVAL, CRON_SYNC_MANTA_PAY } from '@subwallet/extension-base/constants';
|
|
5
5
|
import { _isChainSupportEvmNft, _isChainSupportNativeNft, _isChainSupportWasmNft } from '@subwallet/extension-base/services/chain-service/utils';
|
|
6
6
|
import { waitTimeout } from '@subwallet/extension-base/utils';
|
|
7
7
|
import { Subject } from 'rxjs';
|
|
@@ -87,7 +87,6 @@ export class KoniCron {
|
|
|
87
87
|
// NFT
|
|
88
88
|
(commonReload || needUpdateNft) && this.resetNft(address);
|
|
89
89
|
(commonReload || needUpdateNft) && this.removeCron('refreshNft');
|
|
90
|
-
(commonReload || needUpdateNft) && this.removeCron('detectNft');
|
|
91
90
|
commonReload && this.removeCron('refreshPoolingStakingReward');
|
|
92
91
|
if (mktCampaignNeedReload) {
|
|
93
92
|
this.removeCron('fetchMktCampaignData');
|
|
@@ -103,7 +102,6 @@ export class KoniCron {
|
|
|
103
102
|
if (this.checkNetworkAvailable(serviceInfo)) {
|
|
104
103
|
// only add cron jobs if there's at least 1 active network
|
|
105
104
|
(commonReload || needUpdateNft) && this.addCron('refreshNft', this.refreshNft(address, serviceInfo.chainApiMap, this.state.getSmartContractNfts(), this.state.getActiveChainInfoMap()), CRON_REFRESH_NFT_INTERVAL);
|
|
106
|
-
(commonReload || needUpdateNft) && this.addCron('detectNft', this.detectEvmCollectionNft(address), CRON_NFT_DETECT_INTERVAL);
|
|
107
105
|
reloadMantaPay && this.addCron('syncMantaPay', this.syncMantaPay, CRON_SYNC_MANTA_PAY);
|
|
108
106
|
}
|
|
109
107
|
};
|
|
@@ -116,8 +114,6 @@ export class KoniCron {
|
|
|
116
114
|
if (Object.keys(this.state.getSubstrateApiMap()).length !== 0 || Object.keys(this.state.getEvmApiMap()).length !== 0) {
|
|
117
115
|
this.resetNft(currentAccountInfo.proxyId);
|
|
118
116
|
this.addCron('refreshNft', this.refreshNft(currentAccountInfo.proxyId, this.state.getApiMap(), this.state.getSmartContractNfts(), this.state.getActiveChainInfoMap()), CRON_REFRESH_NFT_INTERVAL);
|
|
119
|
-
this.addCron('detectNft', this.detectEvmCollectionNft(currentAccountInfo.proxyId), CRON_NFT_DETECT_INTERVAL);
|
|
120
|
-
// this.addCron('refreshStakingReward', this.refreshStakingReward(currentAccountInfo.address), CRON_REFRESH_STAKING_REWARD_INTERVAL);
|
|
121
117
|
this.addCron('syncMantaPay', this.syncMantaPay, CRON_SYNC_MANTA_PAY);
|
|
122
118
|
}
|
|
123
119
|
this.status = 'running';
|
|
@@ -166,25 +162,12 @@ export class KoniCron {
|
|
|
166
162
|
checkNetworkAvailable = serviceInfo => {
|
|
167
163
|
return Object.keys(serviceInfo.chainApiMap.substrate).length > 0 || Object.keys(serviceInfo.chainApiMap.evm).length > 0;
|
|
168
164
|
};
|
|
169
|
-
detectEvmCollectionNft = address => {
|
|
170
|
-
return () => {
|
|
171
|
-
let addresses = [];
|
|
172
|
-
addresses = this.state.keyringService.context.getDecodedAddresses();
|
|
173
|
-
if (!addresses.length) {
|
|
174
|
-
console.warn('[Cron] No decoded addresses found for ALL_ACCOUNT_KEY');
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
this.state.nftDetectionService.fetchEvmCollectionsWithPreview(addresses).catch(err => console.warn(`[Cron] NFT detection failed for ${address}:`, err));
|
|
178
|
-
};
|
|
179
|
-
};
|
|
180
165
|
async reloadNft() {
|
|
181
166
|
const address = this.state.keyringService.context.currentAccount.proxyId;
|
|
182
167
|
const serviceInfo = this.state.getServiceInfo();
|
|
183
168
|
this.resetNft(address);
|
|
184
169
|
this.removeCron('refreshNft');
|
|
185
|
-
this.removeCron('detectNft');
|
|
186
170
|
this.addCron('refreshNft', this.refreshNft(address, serviceInfo.chainApiMap, this.state.getSmartContractNfts(), this.state.getActiveChainInfoMap()), CRON_REFRESH_NFT_INTERVAL);
|
|
187
|
-
this.addCron('detectNft', this.detectEvmCollectionNft(address), CRON_NFT_DETECT_INTERVAL);
|
|
188
171
|
await waitTimeout(1800);
|
|
189
172
|
return true;
|
|
190
173
|
}
|
|
@@ -1150,7 +1150,10 @@ export default class KoniExtension {
|
|
|
1150
1150
|
return this.getNft();
|
|
1151
1151
|
}
|
|
1152
1152
|
async handleGetNftFullList(request) {
|
|
1153
|
-
return this.#koniState.
|
|
1153
|
+
return this.#koniState.nftService.fetchFullListNftOfACollection(request);
|
|
1154
|
+
}
|
|
1155
|
+
async handleGetNftDetail(request) {
|
|
1156
|
+
return this.#koniState.nftService.fetchNftDetail(request);
|
|
1154
1157
|
}
|
|
1155
1158
|
getStakingReward() {
|
|
1156
1159
|
return new Promise((resolve, reject) => {
|
|
@@ -5657,16 +5660,14 @@ export default class KoniExtension {
|
|
|
5657
5660
|
return this.getCrowdloanContributions(request);
|
|
5658
5661
|
case 'pri(crowdloan.getSubscription)':
|
|
5659
5662
|
return this.subscribeCrowdloan(id, port);
|
|
5660
|
-
case 'pri(nft.getNft)':
|
|
5661
|
-
return await this.getNft();
|
|
5662
5663
|
case 'pri(nft.getSubscription)':
|
|
5663
5664
|
return await this.subscribeNft(id, port);
|
|
5664
|
-
case 'pri(nftCollection.getNftCollection)':
|
|
5665
|
-
return await this.getNftCollection();
|
|
5666
5665
|
case 'pri(nftCollection.getSubscription)':
|
|
5667
5666
|
return await this.subscribeNftCollection(id, port);
|
|
5668
5667
|
case 'pri(nft.getFullList)':
|
|
5669
5668
|
return await this.handleGetNftFullList(request);
|
|
5669
|
+
case 'pri(nft.getNftdetail)':
|
|
5670
|
+
return await this.handleGetNftDetail(request);
|
|
5670
5671
|
case 'pri(staking.getStaking)':
|
|
5671
5672
|
return this.getStaking();
|
|
5672
5673
|
case 'pri(staking.getSubscription)':
|
|
@@ -20,7 +20,7 @@ import MigrationService from '@subwallet/extension-base/services/migration-servi
|
|
|
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
22
|
import { MultisigService } from '@subwallet/extension-base/services/multisig-service';
|
|
23
|
-
import NftService from '@subwallet/extension-base/services/nft-service';
|
|
23
|
+
import { NftService } from '@subwallet/extension-base/services/nft-service';
|
|
24
24
|
import NotificationService from '@subwallet/extension-base/services/notification-service/NotificationService';
|
|
25
25
|
import OpenGovService from '@subwallet/extension-base/services/open-gov';
|
|
26
26
|
import { PriceService } from '@subwallet/extension-base/services/price-service';
|
|
@@ -48,6 +48,11 @@ export default class KoniState {
|
|
|
48
48
|
private externalRequest;
|
|
49
49
|
private crowdloanMap;
|
|
50
50
|
private crowdloanSubject;
|
|
51
|
+
/**
|
|
52
|
+
* TODO: Remove this subject once NFT migration to the service layer is completed.
|
|
53
|
+
* The state manager should not handle the internal state of the NFT service.
|
|
54
|
+
* The NFT service will manage its own state independently.
|
|
55
|
+
*/
|
|
51
56
|
private nftSubject;
|
|
52
57
|
private mantaPayConfigSubject;
|
|
53
58
|
isMantaPayEnabled: boolean;
|
|
@@ -77,7 +82,7 @@ export default class KoniState {
|
|
|
77
82
|
readonly mintCampaignService: MintCampaignService;
|
|
78
83
|
readonly campaignService: CampaignService;
|
|
79
84
|
readonly mktCampaignService: MktCampaignService;
|
|
80
|
-
readonly
|
|
85
|
+
readonly nftService: NftService;
|
|
81
86
|
readonly buyService: BuyService;
|
|
82
87
|
readonly earningService: EarningService;
|
|
83
88
|
readonly feeService: FeeService;
|
|
@@ -273,6 +278,7 @@ export default class KoniState {
|
|
|
273
278
|
onAccountAdd(): void;
|
|
274
279
|
onAccountRemove(): void;
|
|
275
280
|
reloadNft(): Promise<boolean>;
|
|
281
|
+
reloadNftV2(): Promise<void>;
|
|
276
282
|
reloadStaking(): Promise<boolean>;
|
|
277
283
|
reloadBalance(): Promise<boolean>;
|
|
278
284
|
approvePassPhishingPage(_url: string): Promise<boolean>;
|