Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: MetaMask/core
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v23.0.0
Choose a base ref
...
head repository: MetaMask/core
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v23.1.0
Choose a head ref
  • 3 commits
  • 11 files changed
  • 4 contributors

Commits on Dec 22, 2021

  1. Update ABIs module (#633)

    Gustavo Antunes authored Dec 22, 2021
    Copy the full SHA
    bfd4484 View commit details

Commits on Dec 27, 2021

  1. Copy the full SHA
    28c8434 View commit details

Commits on Jan 3, 2022

  1. 23.1.0 (#670)

    * 23.1.0
    
    * update changelog
    
    Co-authored-by: github-actions <github-actions@github.com>
    Co-authored-by: Alex <adonesky@gmail.com>
    3 people authored Jan 3, 2022
    Copy the full SHA
    ccfd032 View commit details
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [23.1.0]
### Added
- add checkAndUpdateSingleCollectibleOwnershipStatus method ([#669](https://github.com/MetaMask/controllers/pull/669))

## [23.0.0]
### Added
- Add method to check and update collectible ownership state ([#664](https://github.com/MetaMask/controllers/pull/664))
@@ -468,7 +472,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Removed
- Remove shapeshift controller (#209)

[Unreleased]: https://github.com/MetaMask/controllers/compare/v23.0.0...HEAD
[Unreleased]: https://github.com/MetaMask/controllers/compare/v23.1.0...HEAD
[23.1.0]: https://github.com/MetaMask/controllers/compare/v23.0.0...v23.1.0
[23.0.0]: https://github.com/MetaMask/controllers/compare/v22.0.0...v23.0.0
[22.0.0]: https://github.com/MetaMask/controllers/compare/v21.0.1...v22.0.0
[21.0.1]: https://github.com/MetaMask/controllers/compare/v21.0.0...v21.0.1
Binary file added metamask-metamask-eth-abis-v1.0.3.tgz
Binary file not shown.
6 changes: 2 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@metamask/controllers",
"version": "23.0.0",
"version": "23.1.0",
"description": "Collection of platform-agnostic modules for creating secure data models for cryptocurrency wallets",
"keywords": [
"MetaMask",
@@ -38,6 +38,7 @@
"@ethereumjs/common": "^2.3.1",
"@ethereumjs/tx": "^3.2.1",
"@metamask/contract-metadata": "^1.31.0",
"@metamask/metamask-eth-abis": "^2.1.0",
"@types/uuid": "^8.3.0",
"abort-controller": "^3.0.0",
"async-mutex": "^0.2.6",
@@ -54,9 +55,6 @@
"ethereumjs-wallet": "^1.0.1",
"ethers": "^5.4.1",
"ethjs-unit": "^0.1.6",
"human-standard-collectible-abi": "^1.0.2",
"human-standard-multi-collectible-abi": "^1.0.4",
"human-standard-token-abi": "^2.0.0",
"immer": "^9.0.6",
"isomorphic-fetch": "^3.0.0",
"jsonschema": "^1.2.4",
4 changes: 1 addition & 3 deletions src/assets/AssetsContractController.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { BN } from 'ethereumjs-util';
import Web3 from 'web3';
import abiERC20 from 'human-standard-token-abi';
import abiERC721 from 'human-standard-collectible-abi';
import abiERC1155 from 'human-standard-multi-collectible-abi';
import { abiERC1155, abiERC721, abiERC20 } from '@metamask/metamask-eth-abis';
import abiSingleCallBalancesContract from 'single-call-balance-checker-abi';
import { BaseController, BaseConfig, BaseState } from '../BaseController';
import { ERC721Standard } from './CollectibleStandards/ERC721/ERC721Standard';
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Web3 from 'web3';
import HttpProvider from 'ethjs-provider-http';
import abiERC1155 from 'human-standard-multi-collectible-abi';
import { abiERC1155 } from '@metamask/metamask-eth-abis';

import { ERC1155Standard } from './ERC1155Standard';

const MAINNET_PROVIDER = new HttpProvider(
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Web3 from 'web3';
import HttpProvider from 'ethjs-provider-http';
import abiERC721 from 'human-standard-collectible-abi';
import { abiERC721 } from '@metamask/metamask-eth-abis';
import { ERC721Standard } from './ERC721Standard';

const MAINNET_PROVIDER = new HttpProvider(
188 changes: 138 additions & 50 deletions src/assets/CollectiblesController.test.ts
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ const ERC721_DEPRESSIONIST_ADDRESS =
'0x18E8E76aeB9E2d9FA2A2b88DD9CF3C8ED45c3660';
const ERC721_DEPRESSIONIST_ID = '36';
const MAINNET_PROVIDER = new HttpProvider(
'https://mainnet.infura.io/v3/341eacb578dd44a1a049cbc5f6fd4035',
'https://mainnet.infura.io/v3/ad3a368836ff4596becc3be8e2f137ac',
);
const OWNER_ADDRESS = '0x5a3CA5cD63807Ce5e4d7841AB32Ce6B6d9BbBa2D';

@@ -1132,11 +1132,66 @@ describe('CollectiblesController', () => {
});

describe('checkAndUpdateCollectiblesOwnershipStatus', () => {
it('should check whether collectibles for the current selectedAddress/chainId combination are still owned by the selectedAddress and update the isCurrentlyOwned value to false when collectible is not still owned', async () => {
describe('checkAndUpdateAllCollectiblesOwnershipStatus', () => {
it('should check whether collectibles for the current selectedAddress/chainId combination are still owned by the selectedAddress and update the isCurrentlyOwned value to false when collectible is not still owned', async () => {
sandbox.restore();
sandbox
.stub(collectiblesController, 'isCollectibleOwner' as any)
.returns(false);

const { selectedAddress, chainId } = collectiblesController.config;
await collectiblesController.addCollectible('0x02', '1', {
name: 'name',
image: 'image',
description: 'description',
standard: 'standard',
favorite: false,
});

expect(
collectiblesController.state.allCollectibles[selectedAddress][
chainId
][0].isCurrentlyOwned,
).toBe(true);

await collectiblesController.checkAndUpdateAllCollectiblesOwnershipStatus();
expect(
collectiblesController.state.allCollectibles[selectedAddress][
chainId
][0].isCurrentlyOwned,
).toBe(false);
});
});

it('should check whether collectibles for the current selectedAddress/chainId combination are still owned by the selectedAddress and leave/set the isCurrentlyOwned value to true when collectible is still owned', async () => {
const { selectedAddress, chainId } = collectiblesController.config;
await collectiblesController.addCollectible('0x02', '1', {
name: 'name',
image: 'image',
description: 'description',
standard: 'standard',
favorite: false,
});

expect(
collectiblesController.state.allCollectibles[selectedAddress][
chainId
][0].isCurrentlyOwned,
).toBe(true);

await collectiblesController.checkAndUpdateAllCollectiblesOwnershipStatus();
expect(
collectiblesController.state.allCollectibles[selectedAddress][
chainId
][0].isCurrentlyOwned,
).toBe(true);
});

it('should check whether collectibles for the current selectedAddress/chainId combination are still owned by the selectedAddress and leave the isCurrentlyOwned value as is when collectible ownership check fails', async () => {
sandbox.restore();
sandbox
.stub(collectiblesController, 'isCollectibleOwner' as any)
.returns(false);
.throws(new Error('Unable to verify ownership'));

const { selectedAddress, chainId } = collectiblesController.config;
await collectiblesController.addCollectible('0x02', '1', {
@@ -1153,66 +1208,99 @@ describe('CollectiblesController', () => {
][0].isCurrentlyOwned,
).toBe(true);

await collectiblesController.checkAndUpdateCollectiblesOwnershipStatus();
await collectiblesController.checkAndUpdateAllCollectiblesOwnershipStatus();
expect(
collectiblesController.state.allCollectibles[selectedAddress][
chainId
][0].isCurrentlyOwned,
).toBe(false);
).toBe(true);
});
});

it('should check whether collectibles for the current selectedAddress/chainId combination are still owned by the selectedAddress and leave/set the isCurrentlyOwned value to true when collectible is still owned', async () => {
const { selectedAddress, chainId } = collectiblesController.config;
await collectiblesController.addCollectible('0x02', '1', {
name: 'name',
image: 'image',
description: 'description',
standard: 'standard',
favorite: false,
describe('checkAndUpdateSingleCollectibleOwnershipStatus', () => {
it('should check whether the passed collectible is still owned by the the current selectedAddress/chainId combination and update its isCurrentlyOwned property in state if batch is false and isCollectibleOwner returns false', async () => {
const { selectedAddress, chainId } = collectiblesController.config;
const collectible = {
address: '0x02',
tokenId: '1',
name: 'name',
image: 'image',
description: 'description',
standard: 'standard',
favorite: false,
};

await collectiblesController.addCollectible(
collectible.address,
collectible.tokenId,
collectible,
);

expect(
collectiblesController.state.allCollectibles[selectedAddress][
chainId
][0].isCurrentlyOwned,
).toBe(true);

sandbox.restore();
sandbox
.stub(collectiblesController, 'isCollectibleOwner' as any)
.returns(false);

await collectiblesController.checkAndUpdateSingleCollectibleOwnershipStatus(
collectible,
false,
);

expect(
collectiblesController.state.allCollectibles[selectedAddress][
chainId
][0].isCurrentlyOwned,
).toBe(false);
});
});

expect(
collectiblesController.state.allCollectibles[selectedAddress][
chainId
][0].isCurrentlyOwned,
).toBe(true);
it('should check whether the passed collectible is still owned by the the current selectedAddress/chainId combination and return the updated collectible object without updating state if batch is true', async () => {
const { selectedAddress, chainId } = collectiblesController.config;
const collectible = {
address: '0x02',
tokenId: '1',
name: 'name',
image: 'image',
description: 'description',
standard: 'standard',
favorite: false,
};

await collectiblesController.checkAndUpdateCollectiblesOwnershipStatus();
expect(
collectiblesController.state.allCollectibles[selectedAddress][
chainId
][0].isCurrentlyOwned,
).toBe(true);
});
await collectiblesController.addCollectible(
collectible.address,
collectible.tokenId,
collectible,
);

it('should check whether collectibles for the current selectedAddress/chainId combination are still owned by the selectedAddress and leave the isCurrentlyOwned value as is when collectible ownership check fails', async () => {
sandbox.restore();
sandbox
.stub(collectiblesController, 'isCollectibleOwner' as any)
.throws(new Error('Unable to verify ownership'));
expect(
collectiblesController.state.allCollectibles[selectedAddress][
chainId
][0].isCurrentlyOwned,
).toBe(true);

const { selectedAddress, chainId } = collectiblesController.config;
await collectiblesController.addCollectible('0x02', '1', {
name: 'name',
image: 'image',
description: 'description',
standard: 'standard',
favorite: false,
});
sandbox.restore();
sandbox
.stub(collectiblesController, 'isCollectibleOwner' as any)
.returns(false);

expect(
collectiblesController.state.allCollectibles[selectedAddress][
chainId
][0].isCurrentlyOwned,
).toBe(true);
const updatedCollectible = await collectiblesController.checkAndUpdateSingleCollectibleOwnershipStatus(
collectible,
true,
);

await collectiblesController.checkAndUpdateCollectiblesOwnershipStatus();
expect(
collectiblesController.state.allCollectibles[selectedAddress][
chainId
][0].isCurrentlyOwned,
).toBe(true);
expect(
collectiblesController.state.allCollectibles[selectedAddress][
chainId
][0].isCurrentlyOwned,
).toBe(true);

expect(updatedCollectible.isCurrentlyOwned).toBe(false);
});
});
});
});
73 changes: 56 additions & 17 deletions src/assets/CollectiblesController.ts
Original file line number Diff line number Diff line change
@@ -1039,32 +1039,71 @@ export class CollectiblesController extends BaseController<
this.update({ ignoredCollectibles: [] });
}

/**
* Checks whether input collectible is still owned by the user
* And updates the isCurrentlyOwned value on the collectible object accordingly.
*
* @param collectible - The collectible object to check and update.
* @param batch - A boolean indicating whether this method is being called as part of a batch or single update.
* @returns the collectible with the updated isCurrentlyOwned value
*/
async checkAndUpdateSingleCollectibleOwnershipStatus(
collectible: Collectible,
batch: boolean,
) {
const { allCollectibles } = this.state;
const { selectedAddress, chainId } = this.config;
const { address, tokenId } = collectible;
let isOwned = collectible.isCurrentlyOwned;
try {
isOwned = await this.isCollectibleOwner(
selectedAddress,
address,
tokenId,
);
} catch (error) {
if (!error.message.includes('Unable to verify ownership')) {
throw error;
}
}

collectible.isCurrentlyOwned = isOwned;

if (batch === true) {
return collectible;
}

// if this is not part of a batched update we update this one collectible in state
const collectibles = allCollectibles[selectedAddress]?.[chainId] || [];
const collectibleToUpdate = collectibles.find(
(item) => item.tokenId === tokenId && item.address === address,
);
if (collectibleToUpdate) {
collectibleToUpdate.isCurrentlyOwned = isOwned;
this.updateNestedCollectibleState(
collectibles,
ALL_COLLECTIBLES_STATE_KEY,
);
}
return collectible;
}

/**
* Checks whether Collectibles associated with current selectedAddress/chainId combination are still owned by the user
* And updates the isCurrentlyOwned value on each accordingly.
*/
async checkAndUpdateCollectiblesOwnershipStatus() {
async checkAndUpdateAllCollectiblesOwnershipStatus() {
const { allCollectibles } = this.state;
const { chainId, selectedAddress } = this.config;
const collectibles = allCollectibles[selectedAddress]?.[chainId] || [];
const updatedCollectibles = await Promise.all(
collectibles.map(async (collectible) => {
const { address, tokenId } = collectible;
let isOwned = collectible.isCurrentlyOwned;
try {
isOwned = await this.isCollectibleOwner(
selectedAddress,
address,
tokenId,
);
} catch (error) {
if (!error.message.includes('Unable to verify ownership')) {
throw error;
}
}
collectible.isCurrentlyOwned = isOwned;

return collectible;
return (
(await this.checkAndUpdateSingleCollectibleOwnershipStatus(
collectible,
true,
)) ?? collectible
);
}),
);

2 changes: 1 addition & 1 deletion src/assets/TokensController.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { EventEmitter } from 'events';
import contractsMap from '@metamask/contract-metadata';
import abiERC721 from 'human-standard-collectible-abi';
import { abiERC721 } from '@metamask/metamask-eth-abis';
import { v1 as random } from 'uuid';
import { Mutex } from 'async-mutex';
import { ethers } from 'ethers';
Loading