@metamask/assets-controllers 100.0.3 → 100.2.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/CHANGELOG.md +46 -1
- package/dist/AccountTrackerController.cjs +25 -4
- package/dist/AccountTrackerController.cjs.map +1 -1
- package/dist/AccountTrackerController.d.cts +5 -2
- package/dist/AccountTrackerController.d.cts.map +1 -1
- package/dist/AccountTrackerController.d.mts +5 -2
- package/dist/AccountTrackerController.d.mts.map +1 -1
- package/dist/AccountTrackerController.mjs +26 -5
- package/dist/AccountTrackerController.mjs.map +1 -1
- package/dist/MultichainAssetsRatesController/index.cjs +3 -1
- package/dist/MultichainAssetsRatesController/index.cjs.map +1 -1
- package/dist/MultichainAssetsRatesController/index.d.cts +1 -0
- package/dist/MultichainAssetsRatesController/index.d.cts.map +1 -1
- package/dist/MultichainAssetsRatesController/index.d.mts +1 -0
- package/dist/MultichainAssetsRatesController/index.d.mts.map +1 -1
- package/dist/MultichainAssetsRatesController/index.mjs +1 -0
- package/dist/MultichainAssetsRatesController/index.mjs.map +1 -1
- package/dist/NftController.cjs +198 -150
- package/dist/NftController.cjs.map +1 -1
- package/dist/NftController.d.cts.map +1 -1
- package/dist/NftController.d.mts.map +1 -1
- package/dist/NftController.mjs +198 -150
- package/dist/NftController.mjs.map +1 -1
- package/dist/TokenBalancesController.cjs +51 -12
- package/dist/TokenBalancesController.cjs.map +1 -1
- package/dist/TokenBalancesController.d.cts +1 -1
- package/dist/TokenBalancesController.d.cts.map +1 -1
- package/dist/TokenBalancesController.d.mts +1 -1
- package/dist/TokenBalancesController.d.mts.map +1 -1
- package/dist/TokenBalancesController.mjs +51 -12
- package/dist/TokenBalancesController.mjs.map +1 -1
- package/dist/TokenDetectionController.cjs +0 -2
- package/dist/TokenDetectionController.cjs.map +1 -1
- package/dist/TokenDetectionController.d.cts +1 -1
- package/dist/TokenDetectionController.d.cts.map +1 -1
- package/dist/TokenDetectionController.d.mts +1 -1
- package/dist/TokenDetectionController.d.mts.map +1 -1
- package/dist/TokenDetectionController.mjs +0 -2
- package/dist/TokenDetectionController.mjs.map +1 -1
- package/dist/TokenListController.cjs +38 -5
- package/dist/TokenListController.cjs.map +1 -1
- package/dist/TokenListController.d.cts.map +1 -1
- package/dist/TokenListController.d.mts.map +1 -1
- package/dist/TokenListController.mjs +38 -5
- package/dist/TokenListController.mjs.map +1 -1
- package/dist/balances.cjs +46 -12
- package/dist/balances.cjs.map +1 -1
- package/dist/balances.d.cts +14 -3
- package/dist/balances.d.cts.map +1 -1
- package/dist/balances.d.mts +14 -3
- package/dist/balances.d.mts.map +1 -1
- package/dist/balances.mjs +46 -12
- package/dist/balances.mjs.map +1 -1
- package/dist/index.cjs +4 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +4 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -1
- package/dist/index.mjs.map +1 -1
- package/dist/multi-chain-accounts-service/api-balance-fetcher.cjs +37 -11
- package/dist/multi-chain-accounts-service/api-balance-fetcher.cjs.map +1 -1
- package/dist/multi-chain-accounts-service/api-balance-fetcher.d.cts +10 -0
- package/dist/multi-chain-accounts-service/api-balance-fetcher.d.cts.map +1 -1
- package/dist/multi-chain-accounts-service/api-balance-fetcher.d.mts +10 -0
- package/dist/multi-chain-accounts-service/api-balance-fetcher.d.mts.map +1 -1
- package/dist/multi-chain-accounts-service/api-balance-fetcher.mjs +37 -11
- package/dist/multi-chain-accounts-service/api-balance-fetcher.mjs.map +1 -1
- package/dist/rpc-service/rpc-balance-fetcher.cjs +99 -58
- package/dist/rpc-service/rpc-balance-fetcher.cjs.map +1 -1
- package/dist/rpc-service/rpc-balance-fetcher.d.cts +4 -1
- package/dist/rpc-service/rpc-balance-fetcher.d.cts.map +1 -1
- package/dist/rpc-service/rpc-balance-fetcher.d.mts +4 -1
- package/dist/rpc-service/rpc-balance-fetcher.d.mts.map +1 -1
- package/dist/rpc-service/rpc-balance-fetcher.mjs +99 -58
- package/dist/rpc-service/rpc-balance-fetcher.mjs.map +1 -1
- package/dist/token-service.cjs +76 -3
- package/dist/token-service.cjs.map +1 -1
- package/dist/token-service.d.cts +102 -2
- package/dist/token-service.d.cts.map +1 -1
- package/dist/token-service.d.mts +102 -2
- package/dist/token-service.d.mts.map +1 -1
- package/dist/token-service.mjs +74 -2
- package/dist/token-service.mjs.map +1 -1
- package/package.json +8 -8
package/dist/NftController.mjs
CHANGED
|
@@ -9,7 +9,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
|
-
var _NftController_instances, _NftController_mutex, _NftController_selectedAccountId, _NftController_ipfsGateway, _NftController_displayNftMedia, _NftController_useIpfsSubdomains, _NftController_isIpfsGatewayEnabled, _NftController_onNftAdded, _NftController_onPreferencesControllerStateChange, _NftController_onSelectedAccountChange, _NftController_updateNestedNftState, _NftController_getNftInformationFromApi, _NftController_getNftInformationFromTokenURI, _NftController_getNftURIAndStandard, _NftController_getNftInformation,
|
|
12
|
+
var _NftController_instances, _NftController_mutex, _NftController_selectedAccountId, _NftController_ipfsGateway, _NftController_displayNftMedia, _NftController_useIpfsSubdomains, _NftController_isIpfsGatewayEnabled, _NftController_onNftAdded, _NftController_onPreferencesControllerStateChange, _NftController_onSelectedAccountChange, _NftController_updateNestedNftState, _NftController_getNftInformationFromApi, _NftController_getNftInformationFromTokenURI, _NftController_getNftURIAndStandard, _NftController_getNftInformation, _NftController_getNftContractInformation, _NftController_addMultipleNfts, _NftController_addNftContracts, _NftController_removeAndIgnoreIndividualNft, _NftController_removeIndividualNft, _NftController_removeNftContract, _NftController_validateWatchNft, _NftController_getAddressOrSelectedAddress, _NftController_updateNftUpdateForAccount, _NftController_bulkSanitizeNftMetadata, _NftController_sanitizeNftMetadata;
|
|
13
13
|
function $importDefault(module) {
|
|
14
14
|
if (module?.__esModule) {
|
|
15
15
|
return module.default;
|
|
@@ -234,23 +234,35 @@ export class NftController extends BaseController {
|
|
|
234
234
|
// Sanitize provided metadata
|
|
235
235
|
nftMetadata = await __classPrivateFieldGet(this, _NftController_instances, "m", _NftController_sanitizeNftMetadata).call(this, nftMetadata);
|
|
236
236
|
}
|
|
237
|
-
const newNftContracts = await __classPrivateFieldGet(this, _NftController_instances, "m",
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
237
|
+
const { contracts: newNftContracts } = await __classPrivateFieldGet(this, _NftController_instances, "m", _NftController_addNftContracts).call(this, addressToSearch, [
|
|
238
|
+
{
|
|
239
|
+
tokenAddress: checksumHexAddress,
|
|
240
|
+
networkClientId,
|
|
241
|
+
source,
|
|
242
|
+
nftMetadata,
|
|
243
|
+
},
|
|
244
|
+
]);
|
|
243
245
|
// If NFT contract was not added, do not add individual NFT
|
|
244
|
-
const nftContract =
|
|
246
|
+
const nftContract = Object.values(newNftContracts)
|
|
247
|
+
.flat()
|
|
248
|
+
.find((contract) => contract.address.toLowerCase() === checksumHexAddress.toLowerCase());
|
|
245
249
|
const { configuration: { chainId }, } = this.messenger.call('NetworkController:getNetworkClientById', networkClientId);
|
|
246
250
|
// This is the case when the NFT is added manually and not detected automatically
|
|
247
251
|
// TODO: An improvement would be to make the chainId a required field and return it when getting the NFT information
|
|
248
252
|
if (!nftMetadata.chainId) {
|
|
249
253
|
nftMetadata.chainId = convertHexToDecimal(chainId);
|
|
250
254
|
}
|
|
251
|
-
// If NFT contract information, add individual NFT
|
|
252
255
|
if (nftContract) {
|
|
253
|
-
await __classPrivateFieldGet(this, _NftController_instances, "m",
|
|
256
|
+
await __classPrivateFieldGet(this, _NftController_instances, "m", _NftController_addMultipleNfts).call(this, addressToSearch, [
|
|
257
|
+
{
|
|
258
|
+
tokenAddress: checksumHexAddress,
|
|
259
|
+
tokenId,
|
|
260
|
+
nftMetadata,
|
|
261
|
+
nftContract,
|
|
262
|
+
chainId,
|
|
263
|
+
source,
|
|
264
|
+
},
|
|
265
|
+
]);
|
|
254
266
|
}
|
|
255
267
|
}
|
|
256
268
|
/**
|
|
@@ -271,23 +283,51 @@ export class NftController extends BaseController {
|
|
|
271
283
|
}
|
|
272
284
|
// Remember max number of urls this allows is 250
|
|
273
285
|
const sanitizedNftMetadata = await __classPrivateFieldGet(this, _NftController_instances, "m", _NftController_bulkSanitizeNftMetadata).call(this, nfts.map((nft) => nft.nftMetadata));
|
|
286
|
+
// Resolve network client IDs per item up front. Items that fail (e.g.,
|
|
287
|
+
// the user removes a network during detection) are skipped individually
|
|
288
|
+
// so the rest of the batch is unaffected. Resolved data is bundled into
|
|
289
|
+
// one object per NFT to avoid index-alignment issues between the two loops.
|
|
290
|
+
const resolvedNfts = [];
|
|
274
291
|
for (const [index, nft] of nfts.entries()) {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
292
|
+
try {
|
|
293
|
+
const checksumHexAddress = toChecksumHexAddress(nft.tokenAddress);
|
|
294
|
+
const hexChainId = toHex(nft.nftMetadata.chainId);
|
|
295
|
+
const networkClientId = this.messenger.call('NetworkController:findNetworkClientIdByChainId', hexChainId);
|
|
296
|
+
resolvedNfts.push({
|
|
297
|
+
contractToAdd: {
|
|
298
|
+
networkClientId,
|
|
299
|
+
tokenAddress: checksumHexAddress,
|
|
300
|
+
source,
|
|
301
|
+
nftMetadata: sanitizedNftMetadata[index],
|
|
302
|
+
},
|
|
303
|
+
tokenId: nft.tokenId,
|
|
304
|
+
checksumHexAddress,
|
|
305
|
+
hexChainId,
|
|
306
|
+
sanitizedMetadata: sanitizedNftMetadata[index],
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
catch (error) {
|
|
310
|
+
console.error('Failed to resolve network for NFT', nft.tokenAddress, error);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
const { contracts: newNftContracts } = await __classPrivateFieldGet(this, _NftController_instances, "m", _NftController_addNftContracts).call(this, addressToSearch, resolvedNfts.map((item) => item.contractToAdd));
|
|
314
|
+
const nftsToAdd = [];
|
|
315
|
+
for (const { checksumHexAddress, tokenId, hexChainId, sanitizedMetadata, } of resolvedNfts) {
|
|
316
|
+
const nftContract = newNftContracts[hexChainId]?.find((contract) => contract.address.toLowerCase() === checksumHexAddress.toLowerCase());
|
|
287
317
|
if (nftContract) {
|
|
288
|
-
|
|
318
|
+
nftsToAdd.push({
|
|
319
|
+
tokenAddress: checksumHexAddress,
|
|
320
|
+
tokenId,
|
|
321
|
+
nftMetadata: sanitizedMetadata,
|
|
322
|
+
nftContract,
|
|
323
|
+
chainId: hexChainId,
|
|
324
|
+
source,
|
|
325
|
+
});
|
|
289
326
|
}
|
|
290
327
|
}
|
|
328
|
+
if (nftsToAdd.length > 0) {
|
|
329
|
+
await __classPrivateFieldGet(this, _NftController_instances, "m", _NftController_addMultipleNfts).call(this, addressToSearch, nftsToAdd);
|
|
330
|
+
}
|
|
291
331
|
}
|
|
292
332
|
/**
|
|
293
333
|
* Refetches NFT metadata and updates the state
|
|
@@ -869,43 +909,16 @@ async function _NftController_getNftInformation(contractAddress, tokenId, networ
|
|
|
869
909
|
};
|
|
870
910
|
// Sanitize the metadata by checking external links against phishing protection
|
|
871
911
|
return await __classPrivateFieldGet(this, _NftController_instances, "m", _NftController_sanitizeNftMetadata).call(this, metadata);
|
|
872
|
-
},
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
* @param networkClientId - The networkClientId that can be used to identify the network client to use for this request.
|
|
878
|
-
* @returns Promise resolving to the current NFT name and image.
|
|
879
|
-
*/
|
|
880
|
-
async function _NftController_getNftContractInformationFromContract(
|
|
881
|
-
// TODO for calls to blockchain we need to explicitly pass the currentNetworkClientId since its relying on the provider
|
|
882
|
-
contractAddress, networkClientId) {
|
|
883
|
-
const [name, symbol] = await Promise.all([
|
|
884
|
-
this.messenger.call('AssetsContractController:getERC721AssetName', contractAddress, networkClientId),
|
|
885
|
-
this.messenger.call('AssetsContractController:getERC721AssetSymbol', contractAddress, networkClientId),
|
|
886
|
-
]);
|
|
887
|
-
return {
|
|
888
|
-
collection: { name },
|
|
889
|
-
symbol,
|
|
890
|
-
address: contractAddress,
|
|
891
|
-
};
|
|
892
|
-
}, _NftController_getNftContractInformation =
|
|
893
|
-
/**
|
|
894
|
-
* Request NFT contract information from Blockchain and aggregate with received data from NFTMetadata.
|
|
895
|
-
*
|
|
896
|
-
* @param contractAddress - Hex address of the NFT contract.
|
|
897
|
-
* @param nftMetadataFromApi - Received NFT information to be aggregated with blockchain contract information.
|
|
898
|
-
* @param networkClientId - The networkClientId that can be used to identify the network client to use for this request.
|
|
899
|
-
* @returns Promise resolving to the NFT contract name, image and description.
|
|
900
|
-
*/
|
|
901
|
-
async function _NftController_getNftContractInformation(contractAddress, nftMetadataFromApi, networkClientId) {
|
|
902
|
-
const blockchainContractData = await safelyExecute(() => __classPrivateFieldGet(this, _NftController_instances, "m", _NftController_getNftContractInformationFromContract).call(this, contractAddress, networkClientId));
|
|
903
|
-
if (blockchainContractData ||
|
|
912
|
+
}, _NftController_getNftContractInformation = function _NftController_getNftContractInformation(contractAddress, nftMetadataFromApi) {
|
|
913
|
+
const name = nftMetadataFromApi.collection?.name;
|
|
914
|
+
const symbol = nftMetadataFromApi.collection?.symbol;
|
|
915
|
+
if (name !== undefined ||
|
|
916
|
+
symbol !== undefined ||
|
|
904
917
|
!Object.values(nftMetadataFromApi).every((value) => value === null)) {
|
|
905
918
|
return {
|
|
906
919
|
address: contractAddress,
|
|
907
|
-
...blockchainContractData,
|
|
908
920
|
schema_name: nftMetadataFromApi?.standard ?? null,
|
|
921
|
+
...(symbol !== undefined && { symbol }),
|
|
909
922
|
collection: {
|
|
910
923
|
name: null,
|
|
911
924
|
image_url: nftMetadataFromApi?.collection?.image ??
|
|
@@ -913,7 +926,7 @@ async function _NftController_getNftContractInformation(contractAddress, nftMeta
|
|
|
913
926
|
null,
|
|
914
927
|
tokenCount: nftMetadataFromApi?.collection?.tokenCount ?? null,
|
|
915
928
|
...nftMetadataFromApi?.collection,
|
|
916
|
-
...
|
|
929
|
+
...(name !== undefined && { name }),
|
|
917
930
|
},
|
|
918
931
|
};
|
|
919
932
|
}
|
|
@@ -929,122 +942,157 @@ async function _NftController_getNftContractInformation(contractAddress, nftMeta
|
|
|
929
942
|
external_link: null,
|
|
930
943
|
collection: { name: null, image_url: null },
|
|
931
944
|
};
|
|
932
|
-
},
|
|
945
|
+
}, _NftController_addMultipleNfts =
|
|
933
946
|
/**
|
|
934
|
-
* Adds
|
|
947
|
+
* Adds multiple NFTs to the stored NFT list for a given user.
|
|
935
948
|
*
|
|
936
|
-
* @param
|
|
937
|
-
* @param
|
|
938
|
-
* @param
|
|
939
|
-
* @param
|
|
940
|
-
* @param
|
|
941
|
-
* @param
|
|
942
|
-
* @param
|
|
943
|
-
* @
|
|
949
|
+
* @param userAddress - The address of the account where the NFTs are being added.
|
|
950
|
+
* @param nfts - Array of NFT objects to add.
|
|
951
|
+
* @param nfts[].tokenAddress - Hex address of the NFT contract.
|
|
952
|
+
* @param nfts[].tokenId - The NFT identifier.
|
|
953
|
+
* @param nfts[].nftMetadata - NFT optional information (name, image and description).
|
|
954
|
+
* @param nfts[].nftContract - An object containing contract data of the NFT being added.
|
|
955
|
+
* @param nfts[].chainId - The chainId of the network where the NFT is being added.
|
|
956
|
+
* @param nfts[].source - Whether the NFT was detected, added manually or suggested by a dapp.
|
|
944
957
|
*/
|
|
945
|
-
async function
|
|
958
|
+
async function _NftController_addMultipleNfts(userAddress, nfts) {
|
|
946
959
|
const releaseLock = await __classPrivateFieldGet(this, _NftController_mutex, "f").acquire();
|
|
947
960
|
try {
|
|
948
|
-
const checksumHexAddress = toChecksumHexAddress(tokenAddress);
|
|
949
961
|
const { allNfts } = this.state;
|
|
950
|
-
const
|
|
951
|
-
const
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
962
|
+
const allNftsForUser = allNfts[userAddress] || {};
|
|
963
|
+
const allNftsForUserPerChain = {};
|
|
964
|
+
const modifiedChainIds = new Set();
|
|
965
|
+
const pendingCallbacks = [];
|
|
966
|
+
for (const { tokenAddress, tokenId, nftMetadata, nftContract, chainId, source, } of nfts) {
|
|
967
|
+
try {
|
|
968
|
+
const checksumHexAddress = toChecksumHexAddress(tokenAddress);
|
|
969
|
+
if (!allNftsForUserPerChain[chainId]) {
|
|
970
|
+
allNftsForUserPerChain[chainId] = [
|
|
971
|
+
...(allNftsForUser?.[chainId] ?? []),
|
|
972
|
+
];
|
|
973
|
+
}
|
|
974
|
+
const existingEntry = allNftsForUserPerChain[chainId].find((nft) => nft.address.toLowerCase() === checksumHexAddress.toLowerCase() &&
|
|
975
|
+
nft.tokenId === tokenId);
|
|
976
|
+
if (existingEntry) {
|
|
977
|
+
const differentMetadata = compareNftMetadata(nftMetadata, existingEntry);
|
|
978
|
+
const hasNewFields = hasNewCollectionFields(nftMetadata, existingEntry);
|
|
979
|
+
if (!differentMetadata &&
|
|
980
|
+
existingEntry.isCurrentlyOwned &&
|
|
981
|
+
!hasNewFields) {
|
|
982
|
+
continue;
|
|
983
|
+
}
|
|
984
|
+
const indexToUpdate = allNftsForUserPerChain[chainId].findIndex((nft) => nft.address.toLowerCase() ===
|
|
985
|
+
checksumHexAddress.toLowerCase() && nft.tokenId === tokenId);
|
|
986
|
+
if (indexToUpdate !== -1) {
|
|
987
|
+
allNftsForUserPerChain[chainId][indexToUpdate] = {
|
|
988
|
+
...existingEntry,
|
|
989
|
+
...nftMetadata,
|
|
990
|
+
};
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
else {
|
|
994
|
+
const newEntry = {
|
|
995
|
+
address: checksumHexAddress,
|
|
996
|
+
tokenId,
|
|
997
|
+
favorite: false,
|
|
998
|
+
isCurrentlyOwned: true,
|
|
999
|
+
...nftMetadata,
|
|
1000
|
+
};
|
|
1001
|
+
allNftsForUserPerChain[chainId].push(newEntry);
|
|
1002
|
+
}
|
|
1003
|
+
modifiedChainIds.add(chainId);
|
|
1004
|
+
if (__classPrivateFieldGet(this, _NftController_onNftAdded, "f")) {
|
|
1005
|
+
pendingCallbacks.push({
|
|
1006
|
+
address: checksumHexAddress,
|
|
1007
|
+
symbol: nftContract.symbol,
|
|
1008
|
+
tokenId: tokenId.toString(),
|
|
1009
|
+
standard: nftMetadata.standard,
|
|
1010
|
+
source,
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
960
1013
|
}
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
if (indexToUpdate !== -1) {
|
|
964
|
-
nfts[indexToUpdate] = {
|
|
965
|
-
...existingEntry,
|
|
966
|
-
...nftMetadata,
|
|
967
|
-
};
|
|
1014
|
+
catch (error) {
|
|
1015
|
+
console.error('Failed to add NFT', tokenAddress, tokenId, error);
|
|
968
1016
|
}
|
|
969
1017
|
}
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
address: checksumHexAddress,
|
|
973
|
-
tokenId,
|
|
974
|
-
favorite: false,
|
|
975
|
-
isCurrentlyOwned: true,
|
|
976
|
-
...nftMetadata,
|
|
977
|
-
};
|
|
978
|
-
nfts.push(newEntry);
|
|
1018
|
+
for (const chainId of modifiedChainIds) {
|
|
1019
|
+
__classPrivateFieldGet(this, _NftController_instances, "m", _NftController_updateNestedNftState).call(this, allNftsForUserPerChain[chainId], ALL_NFTS_STATE_KEY, { chainId, userAddress });
|
|
979
1020
|
}
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
userAddress,
|
|
983
|
-
});
|
|
984
|
-
if (__classPrivateFieldGet(this, _NftController_onNftAdded, "f")) {
|
|
985
|
-
__classPrivateFieldGet(this, _NftController_onNftAdded, "f").call(this, {
|
|
986
|
-
address: checksumHexAddress,
|
|
987
|
-
symbol: nftContract.symbol,
|
|
988
|
-
tokenId: tokenId.toString(),
|
|
989
|
-
standard: nftMetadata.standard,
|
|
990
|
-
source,
|
|
991
|
-
});
|
|
1021
|
+
for (const callbackData of pendingCallbacks) {
|
|
1022
|
+
__classPrivateFieldGet(this, _NftController_onNftAdded, "f")?.call(this, callbackData);
|
|
992
1023
|
}
|
|
993
1024
|
}
|
|
994
1025
|
finally {
|
|
995
1026
|
releaseLock();
|
|
996
1027
|
}
|
|
997
|
-
},
|
|
1028
|
+
}, _NftController_addNftContracts =
|
|
998
1029
|
/**
|
|
999
|
-
* Adds
|
|
1030
|
+
* Adds multiple NFT contracts to the stored NFT contracts list for a given user.
|
|
1000
1031
|
*
|
|
1001
|
-
* @param
|
|
1002
|
-
* @param
|
|
1003
|
-
* @param
|
|
1004
|
-
* @param
|
|
1005
|
-
* @param
|
|
1006
|
-
* @param
|
|
1007
|
-
* @returns Promise resolving to
|
|
1032
|
+
* @param userAddress - The address of the account where the NFT contracts are being added.
|
|
1033
|
+
* @param contracts - Array of contract objects to add.
|
|
1034
|
+
* @param contracts[].networkClientId - The networkClientId used to identify the network client for the request.
|
|
1035
|
+
* @param contracts[].tokenAddress - Hex address of the NFT contract.
|
|
1036
|
+
* @param contracts[].nftMetadata - The retrieved NFT metadata from the API.
|
|
1037
|
+
* @param contracts[].source - Whether the NFT was detected, added manually or suggested by a dapp.
|
|
1038
|
+
* @returns Promise resolving to an object mapping chainIds to their updated NFT contract arrays.
|
|
1008
1039
|
*/
|
|
1009
|
-
async function
|
|
1040
|
+
async function _NftController_addNftContracts(userAddress, contracts) {
|
|
1010
1041
|
const releaseLock = await __classPrivateFieldGet(this, _NftController_mutex, "f").acquire();
|
|
1011
1042
|
try {
|
|
1012
|
-
const checksumHexAddress = toChecksumHexAddress(tokenAddress);
|
|
1013
1043
|
const { allNftContracts } = this.state;
|
|
1014
|
-
const
|
|
1015
|
-
const
|
|
1016
|
-
const
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1044
|
+
const allNftContractsForUser = allNftContracts[userAddress] || {};
|
|
1045
|
+
const nftContractsForUserPerChain = {};
|
|
1046
|
+
const modifiedChainIds = new Set();
|
|
1047
|
+
for (const { networkClientId, tokenAddress, source, nftMetadata, } of contracts) {
|
|
1048
|
+
try {
|
|
1049
|
+
const checksumHexAddress = toChecksumHexAddress(tokenAddress);
|
|
1050
|
+
const { configuration: { chainId }, } = this.messenger.call('NetworkController:getNetworkClientById', networkClientId);
|
|
1051
|
+
// Initialised before the existingEntry check so pre-existing contracts
|
|
1052
|
+
// are still present in the returned map for callers to look up.
|
|
1053
|
+
if (!nftContractsForUserPerChain[chainId]) {
|
|
1054
|
+
nftContractsForUserPerChain[chainId] = [
|
|
1055
|
+
...(allNftContractsForUser?.[chainId] ?? []),
|
|
1056
|
+
];
|
|
1057
|
+
}
|
|
1058
|
+
const existingEntry = nftContractsForUserPerChain[chainId].find((nftContract) => nftContract.address.toLowerCase() ===
|
|
1059
|
+
checksumHexAddress.toLowerCase());
|
|
1060
|
+
if (existingEntry) {
|
|
1061
|
+
continue;
|
|
1062
|
+
}
|
|
1063
|
+
// this doesn't work currently for detection if the user switches networks while the detection is processing
|
|
1064
|
+
// will be fixed once detection uses networkClientIds
|
|
1065
|
+
// get name and symbol if ERC721 then put together the metadata
|
|
1066
|
+
const contractInformation = __classPrivateFieldGet(this, _NftController_instances, "m", _NftController_getNftContractInformation).call(this, checksumHexAddress, nftMetadata);
|
|
1067
|
+
// If the nft is auto-detected we want some valid metadata to be present
|
|
1068
|
+
if (source === Source.Detected &&
|
|
1069
|
+
'address' in contractInformation &&
|
|
1070
|
+
typeof contractInformation.address === 'string' &&
|
|
1071
|
+
'collection' in contractInformation &&
|
|
1072
|
+
contractInformation.collection.name === null &&
|
|
1073
|
+
'image_url' in contractInformation.collection &&
|
|
1074
|
+
contractInformation.collection.image_url === null &&
|
|
1075
|
+
Object.entries(contractInformation).every(([key, value]) => {
|
|
1076
|
+
return key === 'address' || key === 'collection' || !value;
|
|
1077
|
+
})) {
|
|
1078
|
+
continue;
|
|
1079
|
+
}
|
|
1080
|
+
const { asset_contract_type, created_date, symbol, description, external_link, schema_name, collection: { name, image_url, tokenCount }, } = contractInformation;
|
|
1081
|
+
/* istanbul ignore next */
|
|
1082
|
+
const newEntry = Object.assign({}, { address: checksumHexAddress }, description && { description }, name && { name }, image_url && { logo: image_url }, symbol && { symbol }, tokenCount !== null &&
|
|
1083
|
+
typeof tokenCount !== 'undefined' && { totalSupply: tokenCount }, asset_contract_type && { assetContractType: asset_contract_type }, created_date && { createdDate: created_date }, schema_name && { schemaName: schema_name }, external_link && { externalLink: external_link });
|
|
1084
|
+
nftContractsForUserPerChain[chainId].push(newEntry);
|
|
1085
|
+
modifiedChainIds.add(chainId);
|
|
1086
|
+
}
|
|
1087
|
+
catch (error) {
|
|
1088
|
+
console.error('Failed to add NFT contract', tokenAddress, error);
|
|
1089
|
+
}
|
|
1020
1090
|
}
|
|
1021
|
-
//
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
const contractInformation = await __classPrivateFieldGet(this, _NftController_instances, "m", _NftController_getNftContractInformation).call(this, checksumHexAddress, nftMetadata, networkClientId);
|
|
1025
|
-
const { asset_contract_type, created_date, symbol, description, external_link, schema_name, collection: { name, image_url, tokenCount }, } = contractInformation;
|
|
1026
|
-
// If the nft is auto-detected we want some valid metadata to be present
|
|
1027
|
-
if (source === Source.Detected &&
|
|
1028
|
-
'address' in contractInformation &&
|
|
1029
|
-
typeof contractInformation.address === 'string' &&
|
|
1030
|
-
'collection' in contractInformation &&
|
|
1031
|
-
contractInformation.collection.name === null &&
|
|
1032
|
-
'image_url' in contractInformation.collection &&
|
|
1033
|
-
contractInformation.collection.image_url === null &&
|
|
1034
|
-
Object.entries(contractInformation).every(([key, value]) => {
|
|
1035
|
-
return key === 'address' || key === 'collection' || !value;
|
|
1036
|
-
})) {
|
|
1037
|
-
return nftContracts;
|
|
1091
|
+
// Loops once per chain (not once per NFT contract)
|
|
1092
|
+
for (const chainId of modifiedChainIds) {
|
|
1093
|
+
__classPrivateFieldGet(this, _NftController_instances, "m", _NftController_updateNestedNftState).call(this, nftContractsForUserPerChain[chainId], ALL_NFTS_CONTRACTS_STATE_KEY, { chainId, userAddress });
|
|
1038
1094
|
}
|
|
1039
|
-
|
|
1040
|
-
const newEntry = Object.assign({}, { address: checksumHexAddress }, description && { description }, name && { name }, image_url && { logo: image_url }, symbol && { symbol }, tokenCount !== null &&
|
|
1041
|
-
typeof tokenCount !== 'undefined' && { totalSupply: tokenCount }, asset_contract_type && { assetContractType: asset_contract_type }, created_date && { createdDate: created_date }, schema_name && { schemaName: schema_name }, external_link && { externalLink: external_link });
|
|
1042
|
-
const newNftContracts = [...nftContracts, newEntry];
|
|
1043
|
-
__classPrivateFieldGet(this, _NftController_instances, "m", _NftController_updateNestedNftState).call(this, newNftContracts, ALL_NFTS_CONTRACTS_STATE_KEY, {
|
|
1044
|
-
chainId,
|
|
1045
|
-
userAddress,
|
|
1046
|
-
});
|
|
1047
|
-
return newNftContracts;
|
|
1095
|
+
return { contracts: nftContractsForUserPerChain };
|
|
1048
1096
|
}
|
|
1049
1097
|
finally {
|
|
1050
1098
|
releaseLock();
|