@metamask/assets-controllers
Advanced tools
Comparing version 14.0.0 to 15.0.0
@@ -9,2 +9,42 @@ # Changelog | ||
## [15.0.0] | ||
### Changed | ||
- **BREAKING**: `NftController` now expects `getNetworkClientById` in constructor options ([#1698](https://github.com/MetaMask/core/pull/1698)) | ||
- **BREAKING**: `NftController.addNft` function signature has changed ([#1698](https://github.com/MetaMask/core/pull/1698)) | ||
- Previously | ||
``` | ||
address: string, | ||
tokenId: string, | ||
nftMetadata?: NftMetadata, | ||
accountParams?: { | ||
userAddress: string; | ||
chainId: Hex; | ||
}, | ||
source = Source.Custom, | ||
``` | ||
now: | ||
``` | ||
tokenAddress: string, | ||
tokenId: string, | ||
{ | ||
nftMetadata?: NftMetadata; | ||
chainId?: Hex; // extracts from AccountParams | ||
userAddress?: string // extracted from AccountParams | ||
source?: Source; | ||
networkClientId?: NetworkClientId; // new | ||
}, | ||
``` | ||
- `NftController.addNftVerifyOwnership`: Now accepts optional 3rd argument `networkClientId` which is used to fetch NFT metadata and determine by which chainId the added NFT should be stored in state. Also accepts optional 4th argument `source` used for metrics to identify the flow in which the NFT was added to the wallet. ([#1698](https://github.com/MetaMask/core/pull/1698)) | ||
- `NftController.isNftOwner`: Now accepts optional `networkClientId` which is used to instantiate the provider for the correct chain and call the NFT contract to verify ownership ([#1698](https://github.com/MetaMask/core/pull/1698)) | ||
- `NftController.addNft` will use the chainId value derived from `networkClientId` if provided ([#1698](https://github.com/MetaMask/core/pull/1698)) | ||
- `NftController.watchNft` options now accepts optional `networkClientId` which is used to fetch NFT metadata and determine by which chainId the added NFT should be stored in state ([#1698](https://github.com/MetaMask/core/pull/1698)) | ||
- Bump dependency on `@metamask/utils` to ^8.1.0 ([#1639](https://github.com/MetaMask/core/pull/1639)) | ||
- Bump dependency and peer dependency on `@metamask/approval-controller` to ^4.0.0 | ||
- Bump dependency on `@metamask/base-controller` to ^3.2.3 | ||
- Bump dependency on `@metamask/controller-utils` to ^5.0.2 | ||
- Bump dependency and peer dependency on `@metamask/network-controller` to ^14.0.0 | ||
### Fixed | ||
- Fix bug in TokensController where batched `addToken` overwrote each other because mutex was acquired after reading state ([#1768](https://github.com/MetaMask/core/pull/1768)) | ||
## [14.0.0] | ||
@@ -284,3 +324,4 @@ ### Changed | ||
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@14.0.0...HEAD | ||
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@15.0.0...HEAD | ||
[15.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@14.0.0...@metamask/assets-controllers@15.0.0 | ||
[14.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@13.0.0...@metamask/assets-controllers@14.0.0 | ||
@@ -287,0 +328,0 @@ [13.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@12.0.0...@metamask/assets-controllers@13.0.0 |
@@ -5,3 +5,3 @@ /// <reference types="node" /> | ||
import { BaseController } from '@metamask/base-controller'; | ||
import type { NetworkState } from '@metamask/network-controller'; | ||
import type { NetworkClientId, NetworkController, NetworkState } from '@metamask/network-controller'; | ||
import type { PreferencesState } from '@metamask/preferences-controller'; | ||
@@ -115,6 +115,2 @@ import type { Hex } from '@metamask/utils'; | ||
} | ||
interface AccountParams { | ||
userAddress: string; | ||
chainId: Hex; | ||
} | ||
/** | ||
@@ -202,2 +198,3 @@ * @type NftConfig | ||
* @param tokenId - The NFT identifier. | ||
* @param networkClientId - The networkClientId that can be used to identify the network client to use for this request. | ||
* @returns Promise resolving to the current NFT name and image. | ||
@@ -211,2 +208,3 @@ */ | ||
* @param tokenId - NFT token id. | ||
* @param networkClientId - The networkClientId that can be used to identify the network client to use for this request. | ||
* @returns Promise resolving NFT uri and token standard. | ||
@@ -220,2 +218,3 @@ */ | ||
* @param tokenId - The NFT identifier. | ||
* @param networkClientId - The networkClientId that can be used to identify the network client to use for this request. | ||
* @returns Promise resolving to the current NFT name and image. | ||
@@ -235,2 +234,3 @@ */ | ||
* @param contractAddress - Hex address of the NFT contract. | ||
* @param networkClientId - The networkClientId that can be used to identify the network client to use for this request. | ||
* @returns Promise resolving to the current NFT name and image. | ||
@@ -243,2 +243,3 @@ */ | ||
* @param contractAddress - Hex address of the NFT contract. | ||
* @param networkClientId - The networkClientId that can be used to identify the network client to use for this request. | ||
* @returns Promise resolving to the NFT contract name, image and description. | ||
@@ -250,7 +251,8 @@ */ | ||
* | ||
* @param address - Hex address of the NFT contract. | ||
* @param tokenAddress - Hex address of the NFT contract. | ||
* @param tokenId - The NFT identifier. | ||
* @param nftMetadata - NFT optional information (name, image and description). | ||
* @param nftContract - An object containing contract data of the NFT being added. | ||
* @param accountParams - The chain ID and address of network and account to which the nftContract should be added. | ||
* @param chainId - The chainId of the network where the NFT is being added. | ||
* @param userAddress - The address of the account where the NFT is being added. | ||
* @param source - Whether the NFT was detected, added manually or suggested by a dapp. | ||
@@ -263,5 +265,8 @@ * @returns Promise resolving to the current NFT list. | ||
* | ||
* @param address - Hex address of the NFT contract. | ||
* @param accountParams - The chain ID and address of network and account to which the nftContract should be added. | ||
* @param source - Whether the NFT was detected, added manually or suggested by a dapp. | ||
* @param options - options. | ||
* @param options.tokenAddress - Hex address of the NFT contract. | ||
* @param options.chainId - The chainId of the network where the NFT is being added. | ||
* @param options.userAddress - The address of the account where the NFT is being added. | ||
* @param options.networkClientId - The networkClientId that can be used to identify the network client to use for this request. | ||
* @param options.source - Whether the NFT was detected, added manually or suggested by a dapp. | ||
* @returns Promise resolving to the current NFT contracts list. | ||
@@ -309,2 +314,3 @@ */ | ||
private readonly getERC1155TokenURI; | ||
private readonly getNetworkClientById; | ||
private readonly onNftAdded?; | ||
@@ -324,2 +330,3 @@ /** | ||
* @param options.getERC1155TokenURI - Gets the URI of the ERC1155 token at the given address, with the given ID. | ||
* @param options.getNetworkClientById - Gets the network client for the given networkClientId. | ||
* @param options.onNftAdded - Callback that is called when an NFT is added. Currently used pass data | ||
@@ -331,3 +338,3 @@ * for tracking the NFT added event. | ||
*/ | ||
constructor({ chainId: initialChainId, onPreferencesStateChange, onNetworkStateChange, getERC721AssetName, getERC721AssetSymbol, getERC721TokenURI, getERC721OwnerOf, getERC1155BalanceOf, getERC1155TokenURI, onNftAdded, messenger, }: { | ||
constructor({ chainId: initialChainId, onPreferencesStateChange, onNetworkStateChange, getERC721AssetName, getERC721AssetSymbol, getERC721TokenURI, getERC721OwnerOf, getERC1155BalanceOf, getERC1155TokenURI, getNetworkClientById, onNftAdded, messenger, }: { | ||
chainId: Hex; | ||
@@ -342,2 +349,3 @@ onPreferencesStateChange: (listener: (preferencesState: PreferencesState) => void) => void; | ||
getERC1155TokenURI: AssetsContractController['getERC1155TokenURI']; | ||
getNetworkClientById: NetworkController['getNetworkClientById']; | ||
onNftAdded?: (data: { | ||
@@ -352,3 +360,4 @@ address: string; | ||
}, config?: Partial<BaseConfig>, state?: Partial<NftState>); | ||
validateWatchNft(asset: NftAsset, type: NFTStandardType, accountAddress: string): Promise<void>; | ||
validateWatchNft(asset: NftAsset, type: NFTStandardType, userAddress: string): Promise<void>; | ||
private getCorrectChainId; | ||
/** | ||
@@ -363,5 +372,6 @@ * Adds a new suggestedAsset to state. Parameters will be validated according to | ||
* @param origin - Domain origin to register the asset from. | ||
* @param networkClientId - The networkClientId that can be used to identify the network client to use for this request. | ||
* @returns Object containing a Promise resolving to the suggestedAsset address if accepted. | ||
*/ | ||
watchNft(asset: NftAsset, type: NFTStandardType, origin: string): Promise<void>; | ||
watchNft(asset: NftAsset, type: NFTStandardType, origin: string, networkClientId?: NetworkClientId): Promise<void>; | ||
/** | ||
@@ -378,6 +388,7 @@ * Sets an OpenSea API key to retrieve NFT information. | ||
* @param nftAddress - NFT contract address. | ||
* @param nftId - NFT token ID. | ||
* @param tokenId - NFT token ID. | ||
* @param networkClientId - The networkClientId that can be used to identify the network client to use for this request. | ||
* @returns Promise resolving the NFT ownership. | ||
*/ | ||
isNftOwner(ownerAddress: string, nftAddress: string, nftId: string): Promise<boolean>; | ||
isNftOwner(ownerAddress: string, nftAddress: string, tokenId: string, networkClientId?: NetworkClientId): Promise<boolean>; | ||
/** | ||
@@ -389,15 +400,27 @@ * Verifies currently selected address owns entered NFT address/tokenId combo and | ||
* @param tokenId - The NFT identifier. | ||
* @param networkClientId - The networkClientId that can be used to identify the network client to use for this request. | ||
* @param source - Whether the NFT was detected, added manually or suggested by a dapp. | ||
*/ | ||
addNftVerifyOwnership(address: string, tokenId: string): Promise<void>; | ||
addNftVerifyOwnership(address: string, tokenId: string, networkClientId?: NetworkClientId, source?: Source): Promise<void>; | ||
/** | ||
* Adds an NFT and respective NFT contract to the stored NFT and NFT contracts lists. | ||
* | ||
* @param address - Hex address of the NFT contract. | ||
* @param tokenAddress - Hex address of the NFT contract. | ||
* @param tokenId - The NFT identifier. | ||
* @param nftMetadata - NFT optional metadata. | ||
* @param accountParams - The chain ID and address of network and account to which the nftContract should be added. | ||
* @param source - Whether the NFT was detected, added manually or suggested by a dapp. | ||
* @param options - an object of arguments | ||
* @param options.nftMetadata - NFT optional metadata. | ||
* @param options.chainId - The chain ID of the current network. | ||
* @param options.userAddress - The address of the current user. | ||
* @param options.source - Whether the NFT was detected, added manually or suggested by a dapp. | ||
* @param options.networkClientId - The networkClientId that can be used to identify the network client to use for this request. | ||
* @returns Promise resolving to the current NFT list. | ||
*/ | ||
addNft(address: string, tokenId: string, nftMetadata?: NftMetadata, accountParams?: AccountParams, source?: Source): Promise<void>; | ||
addNft(tokenAddress: string, tokenId: string, { nftMetadata, chainId, // TODO remove and replace chainId arg with fetch chainId using getNetworkClientById(networkClientId).configuration.chainId once polling refactor is complete | ||
userAddress, source, networkClientId, }?: { | ||
nftMetadata?: NftMetadata; | ||
chainId?: Hex; | ||
userAddress?: string; | ||
source?: Source; | ||
networkClientId?: NetworkClientId; | ||
}): Promise<void>; | ||
/** | ||
@@ -404,0 +427,0 @@ * Removes an NFT from the stored token list. |
@@ -46,2 +46,3 @@ "use strict"; | ||
* @param options.getERC1155TokenURI - Gets the URI of the ERC1155 token at the given address, with the given ID. | ||
* @param options.getNetworkClientById - Gets the network client for the given networkClientId. | ||
* @param options.onNftAdded - Callback that is called when an NFT is added. Currently used pass data | ||
@@ -53,3 +54,3 @@ * for tracking the NFT added event. | ||
*/ | ||
constructor({ chainId: initialChainId, onPreferencesStateChange, onNetworkStateChange, getERC721AssetName, getERC721AssetSymbol, getERC721TokenURI, getERC721OwnerOf, getERC1155BalanceOf, getERC1155TokenURI, onNftAdded, messenger, }, config, state) { | ||
constructor({ chainId: initialChainId, onPreferencesStateChange, onNetworkStateChange, getERC721AssetName, getERC721AssetSymbol, getERC721TokenURI, getERC721OwnerOf, getERC1155BalanceOf, getERC1155TokenURI, getNetworkClientById, onNftAdded, messenger, }, config, state) { | ||
super(config, state); | ||
@@ -85,2 +86,3 @@ this.mutex = new async_mutex_1.Mutex(); | ||
this.getERC1155TokenURI = getERC1155TokenURI; | ||
this.getNetworkClientById = getNetworkClientById; | ||
this.onNftAdded = onNftAdded; | ||
@@ -137,2 +139,3 @@ this.messagingSystem = messenger; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
// TODO Parameterize this by chainId for non-mainnet token detection | ||
// Attempt to fetch the data with the proxy | ||
@@ -169,8 +172,9 @@ const nftInformation = yield (0, controller_utils_1.fetchWithErrorHandling)({ | ||
* @param tokenId - The NFT identifier. | ||
* @param networkClientId - The networkClientId that can be used to identify the network client to use for this request. | ||
* @returns Promise resolving to the current NFT name and image. | ||
*/ | ||
getNftInformationFromTokenURI(contractAddress, tokenId) { | ||
getNftInformationFromTokenURI(contractAddress, tokenId, networkClientId) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { ipfsGateway, useIPFSSubdomains, isIpfsGatewayEnabled } = this.config; | ||
const result = yield this.getNftURIAndStandard(contractAddress, tokenId); | ||
const result = yield this.getNftURIAndStandard(contractAddress, tokenId, networkClientId); | ||
let tokenURI = result[0]; | ||
@@ -224,9 +228,10 @@ const standard = result[1]; | ||
* @param tokenId - NFT token id. | ||
* @param networkClientId - The networkClientId that can be used to identify the network client to use for this request. | ||
* @returns Promise resolving NFT uri and token standard. | ||
*/ | ||
getNftURIAndStandard(contractAddress, tokenId) { | ||
getNftURIAndStandard(contractAddress, tokenId, networkClientId) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
// try ERC721 uri | ||
try { | ||
const uri = yield this.getERC721TokenURI(contractAddress, tokenId); | ||
const uri = yield this.getERC721TokenURI(contractAddress, tokenId, networkClientId); | ||
return [uri, controller_utils_1.ERC721]; | ||
@@ -239,3 +244,3 @@ } | ||
try { | ||
const tokenURI = yield this.getERC1155TokenURI(contractAddress, tokenId); | ||
const tokenURI = yield this.getERC1155TokenURI(contractAddress, tokenId, networkClientId); | ||
/** | ||
@@ -265,12 +270,19 @@ * According to EIP1155 the URI value allows for ID substitution | ||
* @param tokenId - The NFT identifier. | ||
* @param networkClientId - The networkClientId that can be used to identify the network client to use for this request. | ||
* @returns Promise resolving to the current NFT name and image. | ||
*/ | ||
getNftInformation(contractAddress, tokenId) { | ||
getNftInformation(contractAddress, tokenId, networkClientId) { | ||
var _a, _b, _c, _d, _e, _f, _g, _h, _j; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
let { chainId } = this.config; | ||
if (networkClientId) { | ||
chainId = | ||
this.getNetworkClientById(networkClientId).configuration.chainId; | ||
} | ||
const blockchainMetadata = yield (0, controller_utils_1.safelyExecute)(() => __awaiter(this, void 0, void 0, function* () { | ||
return yield this.getNftInformationFromTokenURI(contractAddress, tokenId); | ||
return yield this.getNftInformationFromTokenURI(contractAddress, tokenId, networkClientId); | ||
})); | ||
let openSeaMetadata; | ||
if (this.config.openSeaEnabled) { | ||
// currently we only need to enter this block if we are on mainnet | ||
if (this.config.openSeaEnabled && chainId === '0x1') { | ||
openSeaMetadata = yield (0, controller_utils_1.safelyExecute)(() => __awaiter(this, void 0, void 0, function* () { | ||
@@ -323,8 +335,9 @@ return yield this.getNftInformationFromApi(contractAddress, tokenId); | ||
* @param contractAddress - Hex address of the NFT contract. | ||
* @param networkClientId - The networkClientId that can be used to identify the network client to use for this request. | ||
* @returns Promise resolving to the current NFT name and image. | ||
*/ | ||
getNftContractInformationFromContract(contractAddress) { | ||
getNftContractInformationFromContract(contractAddress, networkClientId) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const name = yield this.getERC721AssetName(contractAddress); | ||
const symbol = yield this.getERC721AssetSymbol(contractAddress); | ||
const name = yield this.getERC721AssetName(contractAddress, networkClientId); | ||
const symbol = yield this.getERC721AssetSymbol(contractAddress, networkClientId); | ||
return { | ||
@@ -341,11 +354,17 @@ collection: { name }, | ||
* @param contractAddress - Hex address of the NFT contract. | ||
* @param networkClientId - The networkClientId that can be used to identify the network client to use for this request. | ||
* @returns Promise resolving to the NFT contract name, image and description. | ||
*/ | ||
getNftContractInformation(contractAddress) { | ||
getNftContractInformation(contractAddress, networkClientId) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const blockchainContractData = yield (0, controller_utils_1.safelyExecute)(() => __awaiter(this, void 0, void 0, function* () { | ||
return yield this.getNftContractInformationFromContract(contractAddress); | ||
return yield this.getNftContractInformationFromContract(contractAddress, networkClientId); | ||
})); | ||
const { chainId } = this.config; | ||
const getCurrentChainId = this.getCorrectChainId({ | ||
chainId, | ||
networkClientId, | ||
}); | ||
let openSeaContractData; | ||
if (this.config.openSeaEnabled) { | ||
if (this.config.openSeaEnabled && getCurrentChainId === '0x1') { | ||
openSeaContractData = yield (0, controller_utils_1.safelyExecute)(() => __awaiter(this, void 0, void 0, function* () { | ||
@@ -375,11 +394,12 @@ return yield this.getNftContractInformationFromApi(contractAddress); | ||
* | ||
* @param address - Hex address of the NFT contract. | ||
* @param tokenAddress - Hex address of the NFT contract. | ||
* @param tokenId - The NFT identifier. | ||
* @param nftMetadata - NFT optional information (name, image and description). | ||
* @param nftContract - An object containing contract data of the NFT being added. | ||
* @param accountParams - The chain ID and address of network and account to which the nftContract should be added. | ||
* @param chainId - The chainId of the network where the NFT is being added. | ||
* @param userAddress - The address of the account where the NFT is being added. | ||
* @param source - Whether the NFT was detected, added manually or suggested by a dapp. | ||
* @returns Promise resolving to the current NFT list. | ||
*/ | ||
addIndividualNft(address, tokenId, nftMetadata, nftContract, accountParams, source = constants_1.Source.Custom) { | ||
addIndividualNft(tokenAddress, tokenId, nftMetadata, nftContract, chainId, userAddress, source) { | ||
var _a; | ||
@@ -390,15 +410,6 @@ return __awaiter(this, void 0, void 0, function* () { | ||
try { | ||
address = (0, controller_utils_1.toChecksumHexAddress)(address); | ||
tokenAddress = (0, controller_utils_1.toChecksumHexAddress)(tokenAddress); | ||
const { allNfts } = this.state; | ||
let chainId, selectedAddress; | ||
if (accountParams) { | ||
chainId = accountParams.chainId; | ||
selectedAddress = accountParams.userAddress; | ||
} | ||
else { | ||
chainId = this.config.chainId; | ||
selectedAddress = this.config.selectedAddress; | ||
} | ||
const nfts = ((_a = allNfts[selectedAddress]) === null || _a === void 0 ? void 0 : _a[chainId]) || []; | ||
const existingEntry = nfts.find((nft) => nft.address.toLowerCase() === address.toLowerCase() && | ||
const nfts = ((_a = allNfts[userAddress]) === null || _a === void 0 ? void 0 : _a[chainId]) || []; | ||
const existingEntry = nfts.find((nft) => nft.address.toLowerCase() === tokenAddress.toLowerCase() && | ||
nft.tokenId === tokenId); | ||
@@ -409,3 +420,3 @@ if (existingEntry) { | ||
// TODO: Switch to indexToUpdate | ||
const indexToRemove = nfts.findIndex((nft) => nft.address.toLowerCase() === address.toLowerCase() && | ||
const indexToRemove = nfts.findIndex((nft) => nft.address.toLowerCase() === tokenAddress.toLowerCase() && | ||
nft.tokenId === tokenId); | ||
@@ -421,12 +432,11 @@ /* istanbul ignore next */ | ||
} | ||
const newEntry = Object.assign({ address, | ||
tokenId, favorite: (existingEntry === null || existingEntry === void 0 ? void 0 : existingEntry.favorite) || false, isCurrentlyOwned: true }, nftMetadata); | ||
const newEntry = Object.assign({ address: tokenAddress, tokenId, favorite: (existingEntry === null || existingEntry === void 0 ? void 0 : existingEntry.favorite) || false, isCurrentlyOwned: true }, nftMetadata); | ||
const newNfts = [...nfts, newEntry]; | ||
this.updateNestedNftState(newNfts, ALL_NFTS_STATE_KEY, { | ||
chainId, | ||
userAddress: selectedAddress, | ||
userAddress, | ||
}); | ||
if (this.onNftAdded) { | ||
this.onNftAdded({ | ||
address, | ||
address: tokenAddress, | ||
symbol: nftContract.symbol, | ||
@@ -448,8 +458,11 @@ tokenId: tokenId.toString(), | ||
* | ||
* @param address - Hex address of the NFT contract. | ||
* @param accountParams - The chain ID and address of network and account to which the nftContract should be added. | ||
* @param source - Whether the NFT was detected, added manually or suggested by a dapp. | ||
* @param options - options. | ||
* @param options.tokenAddress - Hex address of the NFT contract. | ||
* @param options.chainId - The chainId of the network where the NFT is being added. | ||
* @param options.userAddress - The address of the account where the NFT is being added. | ||
* @param options.networkClientId - The networkClientId that can be used to identify the network client to use for this request. | ||
* @param options.source - Whether the NFT was detected, added manually or suggested by a dapp. | ||
* @returns Promise resolving to the current NFT contracts list. | ||
*/ | ||
addNftContract(address, accountParams, source) { | ||
addNftContract({ tokenAddress, chainId, userAddress, networkClientId, source, }) { | ||
var _a; | ||
@@ -459,19 +472,17 @@ return __awaiter(this, void 0, void 0, function* () { | ||
try { | ||
address = (0, controller_utils_1.toChecksumHexAddress)(address); | ||
tokenAddress = (0, controller_utils_1.toChecksumHexAddress)(tokenAddress); | ||
const { allNftContracts } = this.state; | ||
let chainId, selectedAddress; | ||
if (accountParams) { | ||
chainId = accountParams.chainId; | ||
selectedAddress = accountParams.userAddress; | ||
} | ||
else { | ||
chainId = this.config.chainId; | ||
selectedAddress = this.config.selectedAddress; | ||
} | ||
const nftContracts = ((_a = allNftContracts[selectedAddress]) === null || _a === void 0 ? void 0 : _a[chainId]) || []; | ||
const existingEntry = nftContracts.find((nftContract) => nftContract.address.toLowerCase() === address.toLowerCase()); | ||
const currentChainId = this.getCorrectChainId({ | ||
chainId, | ||
networkClientId, | ||
}); | ||
const selectedAddress = userAddress !== null && userAddress !== void 0 ? userAddress : this.config.selectedAddress; | ||
const nftContracts = ((_a = allNftContracts[selectedAddress]) === null || _a === void 0 ? void 0 : _a[currentChainId]) || []; | ||
const existingEntry = nftContracts.find((nftContract) => nftContract.address.toLowerCase() === tokenAddress.toLowerCase()); | ||
if (existingEntry) { | ||
return nftContracts; | ||
} | ||
const contractInformation = yield this.getNftContractInformation(address); | ||
// this doesn't work currently for detection if the user switches networks while the detection is processing | ||
// will be fixed once detection uses networkClientIds | ||
const contractInformation = yield this.getNftContractInformation(tokenAddress, networkClientId); | ||
const { asset_contract_type, created_date, schema_name, symbol, total_supply, description, external_link, collection: { name, image_url }, } = contractInformation; | ||
@@ -493,7 +504,7 @@ // If the nft is auto-detected we want some valid metadata to be present | ||
/* istanbul ignore next */ | ||
const newEntry = Object.assign({}, { address }, description && { description }, name && { name }, image_url && { logo: image_url }, symbol && { symbol }, total_supply !== null && | ||
const newEntry = Object.assign({}, { address: tokenAddress }, description && { description }, name && { name }, image_url && { logo: image_url }, symbol && { symbol }, total_supply !== null && | ||
typeof total_supply !== 'undefined' && { totalSupply: total_supply }, asset_contract_type && { assetContractType: asset_contract_type }, created_date && { createdDate: created_date }, schema_name && { schemaName: schema_name }, external_link && { externalLink: external_link }); | ||
const newNftContracts = [...nftContracts, newEntry]; | ||
this.updateNestedNftState(newNftContracts, ALL_NFTS_CONTRACTS_STATE_KEY, { | ||
chainId, | ||
chainId: currentChainId, | ||
userAddress: selectedAddress, | ||
@@ -567,3 +578,3 @@ }); | ||
} | ||
validateWatchNft(asset, type, accountAddress) { | ||
validateWatchNft(asset, type, userAddress) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
@@ -589,3 +600,3 @@ const { address: contractAddress, tokenId } = asset; | ||
try { | ||
const isOwner = yield this.isNftOwner(accountAddress, contractAddress, tokenId); | ||
const isOwner = yield this.isNftOwner(userAddress, contractAddress, tokenId); | ||
if (!isOwner) { | ||
@@ -601,2 +612,13 @@ throw rpc_errors_1.rpcErrors.invalidInput('Suggested NFT is not owned by the selected account'); | ||
} | ||
// temporary method to get the correct chainId until we remove chainId from the config & the chainId arg from the detection logic | ||
// Just a helper method to prefer the networkClient chainId first then the chainId argument and then finally the config chainId | ||
getCorrectChainId({ chainId, networkClientId, }) { | ||
if (networkClientId) { | ||
return this.getNetworkClientById(networkClientId).configuration.chainId; | ||
} | ||
else if (chainId) { | ||
return chainId; | ||
} | ||
return this.config.chainId; | ||
} | ||
/** | ||
@@ -611,9 +633,10 @@ * Adds a new suggestedAsset to state. Parameters will be validated according to | ||
* @param origin - Domain origin to register the asset from. | ||
* @param networkClientId - The networkClientId that can be used to identify the network client to use for this request. | ||
* @returns Object containing a Promise resolving to the suggestedAsset address if accepted. | ||
*/ | ||
watchNft(asset, type, origin) { | ||
watchNft(asset, type, origin, networkClientId) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { selectedAddress, chainId } = this.config; | ||
yield this.validateWatchNft(asset, type, selectedAddress); | ||
const nftMetadata = yield this.getNftInformation(asset.address, asset.tokenId); | ||
const nftMetadata = yield this.getNftInformation(asset.address, asset.tokenId, networkClientId); | ||
if (nftMetadata.standard && nftMetadata.standard !== type) { | ||
@@ -634,10 +657,13 @@ throw rpc_errors_1.rpcErrors.invalidInput(`Suggested NFT of type ${nftMetadata.standard} does not match received type ${type}`); | ||
yield this.addNft(address, tokenId, { | ||
name: name !== null && name !== void 0 ? name : null, | ||
description: description !== null && description !== void 0 ? description : null, | ||
image: image !== null && image !== void 0 ? image : null, | ||
standard: standard !== null && standard !== void 0 ? standard : null, | ||
}, { | ||
nftMetadata: { | ||
name: name !== null && name !== void 0 ? name : null, | ||
description: description !== null && description !== void 0 ? description : null, | ||
image: image !== null && image !== void 0 ? image : null, | ||
standard: standard !== null && standard !== void 0 ? standard : null, | ||
}, | ||
chainId, | ||
userAddress: selectedAddress, | ||
}, constants_1.Source.Dapp); | ||
source: constants_1.Source.Dapp, | ||
networkClientId, | ||
}); | ||
}); | ||
@@ -658,10 +684,11 @@ } | ||
* @param nftAddress - NFT contract address. | ||
* @param nftId - NFT token ID. | ||
* @param tokenId - NFT token ID. | ||
* @param networkClientId - The networkClientId that can be used to identify the network client to use for this request. | ||
* @returns Promise resolving the NFT ownership. | ||
*/ | ||
isNftOwner(ownerAddress, nftAddress, nftId) { | ||
isNftOwner(ownerAddress, nftAddress, tokenId, networkClientId) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
// Checks the ownership for ERC-721. | ||
try { | ||
const owner = yield this.getERC721OwnerOf(nftAddress, nftId); | ||
const owner = yield this.getERC721OwnerOf(nftAddress, tokenId, networkClientId); | ||
return ownerAddress.toLowerCase() === owner.toLowerCase(); | ||
@@ -675,3 +702,3 @@ // eslint-disable-next-line no-empty | ||
try { | ||
const balance = yield this.getERC1155BalanceOf(ownerAddress, nftAddress, nftId); | ||
const balance = yield this.getERC1155BalanceOf(ownerAddress, nftAddress, tokenId, networkClientId); | ||
return !balance.isZero(); | ||
@@ -692,10 +719,12 @@ // eslint-disable-next-line no-empty | ||
* @param tokenId - The NFT identifier. | ||
* @param networkClientId - The networkClientId that can be used to identify the network client to use for this request. | ||
* @param source - Whether the NFT was detected, added manually or suggested by a dapp. | ||
*/ | ||
addNftVerifyOwnership(address, tokenId) { | ||
addNftVerifyOwnership(address, tokenId, networkClientId, source) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { selectedAddress } = this.config; | ||
if (!(yield this.isNftOwner(selectedAddress, address, tokenId))) { | ||
if (!(yield this.isNftOwner(selectedAddress, address, tokenId, networkClientId))) { | ||
throw new Error('This NFT is not owned by the user'); | ||
} | ||
yield this.addNft(address, tokenId); | ||
yield this.addNft(address, tokenId, { networkClientId, source }); | ||
}); | ||
@@ -706,20 +735,33 @@ } | ||
* | ||
* @param address - Hex address of the NFT contract. | ||
* @param tokenAddress - Hex address of the NFT contract. | ||
* @param tokenId - The NFT identifier. | ||
* @param nftMetadata - NFT optional metadata. | ||
* @param accountParams - The chain ID and address of network and account to which the nftContract should be added. | ||
* @param source - Whether the NFT was detected, added manually or suggested by a dapp. | ||
* @param options - an object of arguments | ||
* @param options.nftMetadata - NFT optional metadata. | ||
* @param options.chainId - The chain ID of the current network. | ||
* @param options.userAddress - The address of the current user. | ||
* @param options.source - Whether the NFT was detected, added manually or suggested by a dapp. | ||
* @param options.networkClientId - The networkClientId that can be used to identify the network client to use for this request. | ||
* @returns Promise resolving to the current NFT list. | ||
*/ | ||
addNft(address, tokenId, nftMetadata, accountParams, source = constants_1.Source.Custom) { | ||
addNft(tokenAddress, tokenId, { nftMetadata, chainId, // TODO remove and replace chainId arg with fetch chainId using getNetworkClientById(networkClientId).configuration.chainId once polling refactor is complete | ||
userAddress, source = constants_1.Source.Custom, networkClientId, } = {}) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
address = (0, controller_utils_1.toChecksumHexAddress)(address); | ||
const newNftContracts = yield this.addNftContract(address, accountParams, source); | ||
tokenAddress = (0, controller_utils_1.toChecksumHexAddress)(tokenAddress); | ||
const currentChainId = this.getCorrectChainId({ chainId, networkClientId }); | ||
const selectedAddress = userAddress !== null && userAddress !== void 0 ? userAddress : this.config.selectedAddress; | ||
const newNftContracts = yield this.addNftContract({ | ||
tokenAddress, | ||
chainId: currentChainId, | ||
userAddress: selectedAddress, | ||
networkClientId, | ||
source, | ||
}); | ||
nftMetadata = | ||
nftMetadata || (yield this.getNftInformation(address, tokenId)); | ||
nftMetadata || | ||
(yield this.getNftInformation(tokenAddress, tokenId, networkClientId)); | ||
// If NFT contract was not added, do not add individual NFT | ||
const nftContract = newNftContracts.find((contract) => contract.address.toLowerCase() === address.toLowerCase()); | ||
const nftContract = newNftContracts.find((contract) => contract.address.toLowerCase() === tokenAddress.toLowerCase()); | ||
// If NFT contract information, add individual NFT | ||
if (nftContract) { | ||
yield this.addIndividualNft(address, tokenId, nftMetadata, nftContract, accountParams, source); | ||
yield this.addIndividualNft(tokenAddress, tokenId, nftMetadata, nftContract, currentChainId, selectedAddress, source); | ||
} | ||
@@ -726,0 +768,0 @@ }); |
@@ -176,6 +176,8 @@ "use strict"; | ||
}, schema_name && { standard: schema_name }, external_link && { externalLink: external_link }, last_sale && { lastSale: last_sale }); | ||
yield this.addNft(address, token_id, nftMetadata, { | ||
yield this.addNft(address, token_id, { | ||
nftMetadata, | ||
userAddress: selectedAddress, | ||
chainId, | ||
}, constants_1.Source.Detected); | ||
source: constants_1.Source.Detected, | ||
}); | ||
} | ||
@@ -182,0 +184,0 @@ })); |
@@ -136,4 +136,5 @@ "use strict"; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { chainId, selectedAddress } = this.config; | ||
const releaseLock = yield this.mutex.acquire(); | ||
const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state; | ||
const { chainId, selectedAddress } = this.config; | ||
let currentChainId = chainId; | ||
@@ -146,3 +147,2 @@ if (networkClientId) { | ||
const isInteractingWithWalletAccount = accountAddress === selectedAddress; | ||
const releaseLock = yield this.mutex.acquire(); | ||
try { | ||
@@ -156,4 +156,6 @@ address = (0, controller_utils_1.toChecksumHexAddress)(address); | ||
this._detectIsERC721(address, networkClientId), | ||
// TODO parameterize the token metadata fetch by networkClientId | ||
this.fetchTokenMetadata(address), | ||
]); | ||
// TODO remove this once this method is fully parameterized by networkClientId | ||
if (!networkClientId && currentChainId !== this.config.chainId) { | ||
@@ -160,0 +162,0 @@ throw new Error('TokensController Error: Switched networks while adding token'); |
{ | ||
"name": "@metamask/assets-controllers", | ||
"version": "14.0.0", | ||
"version": "15.0.0", | ||
"description": "Controllers which manage interactions involving ERC-20, ERC-721, and ERC-1155 tokens (including NFTs)", | ||
@@ -28,2 +28,3 @@ "keywords": [ | ||
"test": "jest", | ||
"test:clean": "jest --clearCache", | ||
"test:watch": "jest --watch" | ||
@@ -37,12 +38,12 @@ }, | ||
"@metamask/abi-utils": "^2.0.2", | ||
"@metamask/approval-controller": "^3.5.2", | ||
"@metamask/base-controller": "^3.2.2", | ||
"@metamask/approval-controller": "^4.0.0", | ||
"@metamask/base-controller": "^3.2.3", | ||
"@metamask/contract-metadata": "^2.3.1", | ||
"@metamask/controller-utils": "^5.0.1", | ||
"@metamask/controller-utils": "^5.0.2", | ||
"@metamask/eth-query": "^3.0.1", | ||
"@metamask/metamask-eth-abis": "3.0.0", | ||
"@metamask/network-controller": "^13.0.1", | ||
"@metamask/network-controller": "^14.0.0", | ||
"@metamask/preferences-controller": "^4.4.2", | ||
"@metamask/rpc-errors": "^6.0.0", | ||
"@metamask/utils": "^6.2.0", | ||
"@metamask/utils": "^8.1.0", | ||
"@types/uuid": "^8.3.0", | ||
@@ -59,3 +60,3 @@ "async-mutex": "^0.2.6", | ||
"@types/jest": "^27.4.1", | ||
"@types/node": "^16.18.24", | ||
"@types/node": "^16.18.54", | ||
"deepmerge": "^4.2.2", | ||
@@ -68,9 +69,9 @@ "ethjs-provider-http": "^0.1.6", | ||
"ts-jest": "^27.1.4", | ||
"typedoc": "^0.23.15", | ||
"typedoc-plugin-missing-exports": "^0.23.0", | ||
"typedoc": "^0.24.8", | ||
"typedoc-plugin-missing-exports": "^2.0.0", | ||
"typescript": "~4.8.4" | ||
}, | ||
"peerDependencies": { | ||
"@metamask/approval-controller": "^3.5.2", | ||
"@metamask/network-controller": "^13.0.1", | ||
"@metamask/approval-controller": "^4.0.0", | ||
"@metamask/network-controller": "^14.0.0", | ||
"@metamask/preferences-controller": "^4.4.2" | ||
@@ -77,0 +78,0 @@ }, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
668452
6496
+ Added@metamask/approval-controller@4.1.0(transitive)
+ Added@metamask/network-controller@14.0.0(transitive)
+ Added@noble/hashes@1.6.0(transitive)
+ Added@types/node@22.9.3(transitive)
+ Addedcipher-base@1.0.5(transitive)
+ Addednanoid@3.3.7(transitive)
+ Addedundici-types@6.19.8(transitive)
- Removed@metamask/approval-controller@3.5.2(transitive)
- Removed@metamask/network-controller@13.0.1(transitive)
- Removed@metamask/utils@6.2.0(transitive)
- Removed@noble/hashes@1.6.1(transitive)
- Removed@types/node@22.10.0(transitive)
- Removedcipher-base@1.0.6(transitive)
- Removednanoid@3.3.8(transitive)
- Removedundici-types@6.20.0(transitive)
Updated@metamask/utils@^8.1.0