@metamask-previews/assets-controllers 103.1.1-preview-dff83af4c → 103.1.1-preview-aa31fa3
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 +7 -0
- package/dist/NftController.cjs +44 -74
- package/dist/NftController.cjs.map +1 -1
- package/dist/NftController.d.cts +9 -17
- package/dist/NftController.d.cts.map +1 -1
- package/dist/NftController.d.mts +9 -17
- package/dist/NftController.d.mts.map +1 -1
- package/dist/NftController.mjs +44 -74
- package/dist/NftController.mjs.map +1 -1
- package/dist/multicall.cjs +220 -1
- package/dist/multicall.cjs.map +1 -1
- package/dist/multicall.d.cts +22 -0
- package/dist/multicall.d.cts.map +1 -1
- package/dist/multicall.d.mts +22 -0
- package/dist/multicall.d.mts.map +1 -1
- package/dist/multicall.mjs +218 -0
- package/dist/multicall.mjs.map +1 -1
- package/dist/token-prices-service/codefi-v2.d.cts +1 -1
- package/dist/token-prices-service/codefi-v2.d.mts +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
### Changed
|
|
11
11
|
|
|
12
|
+
- **BREAKING:** `NftController` no longer uses the `AssetsContractController:getERC721OwnerOf` and `AssetsContractController:getERC1155BalanceOf` messenger actions for ownership checks; these have been removed from `AllowedActions` ([#8281](https://github.com/MetaMask/core/pull/8281))
|
|
13
|
+
- Consumers that construct the `NftController` messenger and register handlers for these two actions must remove them from their allowed actions list.
|
|
14
|
+
- **BREAKING:** Removed the `checkAndUpdateSingleNftOwnershipStatus` method from `NftController` ([#8281](https://github.com/MetaMask/core/pull/8281))
|
|
15
|
+
- Use `checkAndUpdateAllNftsOwnershipStatus` instead, which now batches all ownership checks via Multicall3 in a single RPC request.
|
|
16
|
+
- `checkAndUpdateAllNftsOwnershipStatus` now removes NFTs confirmed as unowned from state instead of setting `isCurrentlyOwned: false` ([#8281](https://github.com/MetaMask/core/pull/8281))
|
|
17
|
+
- The `isCurrentlyOwned: false` flag was originally used to power a "Previously Owned" NFTs section in MetaMask, which is no longer supported. NFTs that are confirmed as no longer owned are now removed from state immediately rather than being retained with a stale flag.
|
|
18
|
+
- `NftController` NFT ownership checks (`isNftOwner`, `checkAndUpdateAllNftsOwnershipStatus`) now use Multicall3 to batch ERC-721 `ownerOf` and ERC-1155 `balanceOf` calls into fewer RPC requests, falling back to individual calls on unsupported chains ([#8281](https://github.com/MetaMask/core/pull/8281))
|
|
12
19
|
- Bump `@metamask/accounts-controller` from `^37.1.1` to `^37.2.0` ([#8363](https://github.com/MetaMask/core/pull/8363))
|
|
13
20
|
- Bump `@metamask/keyring-controller` from `^25.1.1` to `^25.2.0` ([#8363](https://github.com/MetaMask/core/pull/8363))
|
|
14
21
|
- Bump `@metamask/messenger` from `^1.0.0` to `^1.1.1` ([#8364](https://github.com/MetaMask/core/pull/8364), [#8373](https://github.com/MetaMask/core/pull/8373))
|
package/dist/NftController.cjs
CHANGED
|
@@ -17,6 +17,7 @@ var _NftController_instances, _NftController_mutex, _NftController_selectedAccou
|
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
exports.NftController = exports.getDefaultNftControllerState = void 0;
|
|
19
19
|
const address_1 = require("@ethersproject/address");
|
|
20
|
+
const providers_1 = require("@ethersproject/providers");
|
|
20
21
|
const base_controller_1 = require("@metamask/base-controller");
|
|
21
22
|
const controller_utils_1 = require("@metamask/controller-utils");
|
|
22
23
|
const phishing_controller_1 = require("@metamask/phishing-controller");
|
|
@@ -27,6 +28,7 @@ const bn_js_1 = __importDefault(require("bn.js"));
|
|
|
27
28
|
const uuid_1 = require("uuid");
|
|
28
29
|
const assetsUtil_1 = require("./assetsUtil.cjs");
|
|
29
30
|
const constants_1 = require("./constants.cjs");
|
|
31
|
+
const multicall_1 = require("./multicall.cjs");
|
|
30
32
|
const nftControllerMetadata = {
|
|
31
33
|
allNftContracts: {
|
|
32
34
|
includeInStateLogs: false,
|
|
@@ -165,26 +167,27 @@ class NftController extends base_controller_1.BaseController {
|
|
|
165
167
|
* @param nftAddress - NFT contract address.
|
|
166
168
|
* @param tokenId - NFT token ID.
|
|
167
169
|
* @param networkClientId - The networkClientId that can be used to identify the network client to use for this request.
|
|
170
|
+
* @param options - Optional parameters.
|
|
171
|
+
* @param options.standard - The NFT standard ('ERC721' or 'ERC1155'). When provided, only the
|
|
172
|
+
* relevant ownership check is performed, halving the number of RPC subcalls.
|
|
168
173
|
* @returns Promise resolving the NFT ownership.
|
|
169
174
|
*/
|
|
170
|
-
async isNftOwner(ownerAddress, nftAddress, tokenId, networkClientId) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
catch {
|
|
185
|
-
// Ignore ERC-1155 contract error
|
|
175
|
+
async isNftOwner(ownerAddress, nftAddress, tokenId, networkClientId, { standard } = {}) {
|
|
176
|
+
const client = this.messenger.call('NetworkController:getNetworkClientById', networkClientId);
|
|
177
|
+
const provider = new providers_1.Web3Provider(client.provider);
|
|
178
|
+
const { chainId } = client.configuration;
|
|
179
|
+
const [result] = await (0, multicall_1.getNftOwnershipForMultipleNfts)([
|
|
180
|
+
{
|
|
181
|
+
nftAddress,
|
|
182
|
+
tokenId,
|
|
183
|
+
userAddress: ownerAddress,
|
|
184
|
+
standard: standard ?? null,
|
|
185
|
+
},
|
|
186
|
+
], chainId, provider);
|
|
187
|
+
if (result.isOwned === undefined) {
|
|
188
|
+
throw new Error(`Unable to verify ownership. Possibly because the standard is not supported or the user's currently selected network does not match the chain of the asset in question.`);
|
|
186
189
|
}
|
|
187
|
-
|
|
190
|
+
return result.isOwned;
|
|
188
191
|
}
|
|
189
192
|
/**
|
|
190
193
|
* Verifies currently selected address owns entered NFT address/tokenId combo and
|
|
@@ -459,59 +462,10 @@ class NftController extends base_controller_1.BaseController {
|
|
|
459
462
|
state.ignoredNfts = [];
|
|
460
463
|
});
|
|
461
464
|
}
|
|
462
|
-
/**
|
|
463
|
-
* Checks whether input NFT is still owned by the user
|
|
464
|
-
* And updates the isCurrentlyOwned value on the NFT object accordingly.
|
|
465
|
-
*
|
|
466
|
-
* @param nft - The NFT object to check and update.
|
|
467
|
-
* @param batch - A boolean indicating whether this method is being called as part of a batch or single update.
|
|
468
|
-
* @param networkClientId - The networkClientId that can be used to identify the network client to use for this request.
|
|
469
|
-
* @param accountParams - The userAddress and chainId to check ownership against
|
|
470
|
-
* @param accountParams.userAddress - the address passed through the confirmed transaction flow to ensure assets are stored to the correct account
|
|
471
|
-
* @returns the NFT with the updated isCurrentlyOwned value
|
|
472
|
-
*/
|
|
473
|
-
async checkAndUpdateSingleNftOwnershipStatus(nft, batch, networkClientId, { userAddress } = {}) {
|
|
474
|
-
const addressToSearch = __classPrivateFieldGet(this, _NftController_instances, "m", _NftController_getAddressOrSelectedAddress).call(this, userAddress);
|
|
475
|
-
const { configuration: { chainId }, } = this.messenger.call('NetworkController:getNetworkClientById', networkClientId);
|
|
476
|
-
const { address, tokenId } = nft;
|
|
477
|
-
let isOwned = nft.isCurrentlyOwned;
|
|
478
|
-
try {
|
|
479
|
-
isOwned = await this.isNftOwner(addressToSearch, address, tokenId, networkClientId);
|
|
480
|
-
}
|
|
481
|
-
catch {
|
|
482
|
-
// ignore error
|
|
483
|
-
// this will only throw an error 'Unable to verify ownership' in which case
|
|
484
|
-
// we want to keep the current value of isCurrentlyOwned for this flow.
|
|
485
|
-
}
|
|
486
|
-
const updatedNft = {
|
|
487
|
-
...nft,
|
|
488
|
-
isCurrentlyOwned: isOwned,
|
|
489
|
-
};
|
|
490
|
-
if (batch) {
|
|
491
|
-
return updatedNft;
|
|
492
|
-
}
|
|
493
|
-
// if this is not part of a batched update we update this one NFT in state
|
|
494
|
-
const { allNfts } = this.state;
|
|
495
|
-
const nfts = [...(allNfts[addressToSearch]?.[chainId] || [])];
|
|
496
|
-
const indexToUpdate = nfts.findIndex((item) => item.tokenId === tokenId &&
|
|
497
|
-
item.address.toLowerCase() === address.toLowerCase());
|
|
498
|
-
if (indexToUpdate !== -1) {
|
|
499
|
-
nfts[indexToUpdate] = updatedNft;
|
|
500
|
-
this.update((state) => {
|
|
501
|
-
state.allNfts[addressToSearch] = Object.assign({}, state.allNfts[addressToSearch], {
|
|
502
|
-
[chainId]: nfts,
|
|
503
|
-
});
|
|
504
|
-
});
|
|
505
|
-
__classPrivateFieldGet(this, _NftController_instances, "m", _NftController_updateNestedNftState).call(this, nfts, ALL_NFTS_STATE_KEY, {
|
|
506
|
-
userAddress: addressToSearch,
|
|
507
|
-
chainId,
|
|
508
|
-
});
|
|
509
|
-
}
|
|
510
|
-
return updatedNft;
|
|
511
|
-
}
|
|
512
465
|
/**
|
|
513
466
|
* Checks whether NFTs associated with current selectedAddress/chainId combination are still owned by the user
|
|
514
467
|
* And updates the isCurrentlyOwned value on each accordingly.
|
|
468
|
+
* Uses Multicall3 to batch all ownership checks into a single RPC request when available.
|
|
515
469
|
*
|
|
516
470
|
* @param networkClientId - The networkClientId that can be used to identify the network client to use for this request.
|
|
517
471
|
* @param options - an object of arguments
|
|
@@ -519,14 +473,30 @@ class NftController extends base_controller_1.BaseController {
|
|
|
519
473
|
*/
|
|
520
474
|
async checkAndUpdateAllNftsOwnershipStatus(networkClientId, { userAddress, } = {}) {
|
|
521
475
|
const addressToSearch = __classPrivateFieldGet(this, _NftController_instances, "m", _NftController_getAddressOrSelectedAddress).call(this, userAddress);
|
|
522
|
-
const
|
|
476
|
+
const client = this.messenger.call('NetworkController:getNetworkClientById', networkClientId);
|
|
477
|
+
const { chainId } = client.configuration;
|
|
523
478
|
const { allNfts } = this.state;
|
|
524
479
|
const nfts = allNfts[addressToSearch]?.[chainId] || [];
|
|
525
|
-
|
|
526
|
-
return
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
480
|
+
if (nfts.length === 0) {
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
const provider = new providers_1.Web3Provider(client.provider);
|
|
484
|
+
let ownershipResults;
|
|
485
|
+
try {
|
|
486
|
+
ownershipResults = await (0, multicall_1.getNftOwnershipForMultipleNfts)(nfts.map((nft) => ({
|
|
487
|
+
nftAddress: nft.address,
|
|
488
|
+
tokenId: nft.tokenId,
|
|
489
|
+
userAddress: addressToSearch,
|
|
490
|
+
standard: nft.standard,
|
|
491
|
+
})), chainId, provider);
|
|
492
|
+
}
|
|
493
|
+
catch {
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
const updatedNfts = nfts.filter((_nft, index) => {
|
|
497
|
+
const { isOwned } = ownershipResults[index];
|
|
498
|
+
return isOwned !== false;
|
|
499
|
+
});
|
|
530
500
|
__classPrivateFieldGet(this, _NftController_instances, "m", _NftController_updateNestedNftState).call(this, updatedNfts, ALL_NFTS_STATE_KEY, {
|
|
531
501
|
userAddress: addressToSearch,
|
|
532
502
|
chainId,
|
|
@@ -1161,7 +1131,7 @@ async function _NftController_addNftContracts(userAddress, contracts) {
|
|
|
1161
1131
|
}
|
|
1162
1132
|
// Check if the user owns the suggested NFT
|
|
1163
1133
|
try {
|
|
1164
|
-
const isOwner = await this.isNftOwner(userAddress, contractAddress, tokenId, networkClientId);
|
|
1134
|
+
const isOwner = await this.isNftOwner(userAddress, contractAddress, tokenId, networkClientId, { standard: type });
|
|
1165
1135
|
if (!isOwner) {
|
|
1166
1136
|
throw rpc_errors_1.rpcErrors.invalidInput('Suggested NFT is not owned by the selected account');
|
|
1167
1137
|
}
|