Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding ERC721 detection to TokensController #524

Merged
merged 13 commits into from
Jul 20, 2021
216 changes: 151 additions & 65 deletions src/assets/TokensController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,90 +295,176 @@ describe('TokensController', () => {
});

describe('isERC721 flag', function () {
it('should add isERC721 = true to token object in state when token is collectible and in our contract-metadata repo', async function () {
const supportsInterfaceStub = sinon.stub().returns(Promise.resolve(true));
await sinon
.stub(tokensController, '_createEthersContract')
.callsFake(() =>
Promise.resolve({ supportsInterface: supportsInterfaceStub }),
describe('updateTokenType method', function () {
it('should add isERC721 = true to token object already in state when token is collectible and in our contract-metadata repo', async function () {
const contractAddresses = Object.keys(contractMaps);
const erc721ContractAddresses = contractAddresses.filter(
(contractAddress) => contractMaps[contractAddress].erc721 === true,
);
const contractAddresses = Object.keys(contractMaps);
const erc721ContractAddresses = contractAddresses.filter(
(contractAddress) => contractMaps[contractAddress].erc721 === true,
);
const address = erc721ContractAddresses[0];
const { symbol, decimals } = contractMaps[address];
tokensController.update({
tokens: [{ address, symbol, decimals }],
const address = erc721ContractAddresses[0];
const { symbol, decimals } = contractMaps[address];
tokensController.update({
tokens: [{ address, symbol, decimals }],
});
const result = await tokensController.updateTokenType(address);
expect(result.isERC721).toBe(true);
});

it('should add isERC721 = false to token object already in state when token is not a collectible and is in our contract-metadata repo', async function () {
const contractAddresses = Object.keys(contractMaps);
const erc20ContractAddresses = contractAddresses.filter(
(contractAddress) => contractMaps[contractAddress].erc20 === true,
);
const address = erc20ContractAddresses[0];
const { symbol, decimals } = contractMaps[address];
tokensController.update({
tokens: [{ address, symbol, decimals }],
});
const result = await tokensController.updateTokenType(address);
expect(result.isERC721).toBe(false);
});

it('should add isERC721 = true to token object already in state when token is collectible and is not in our contract-metadata repo', async function () {
const supportsInterfaceStub = sinon
.stub()
.returns(Promise.resolve(true));
await sinon
.stub(tokensController, '_createEthersContract')
.callsFake(() =>
Promise.resolve({ supportsInterface: supportsInterfaceStub }),
);
const tokenAddress = '0xda5584cc586d07c7141aa427224a4bd58e64af7d';
tokensController.update({
tokens: [
{
address: tokenAddress,
symbol: 'TESTNFT',
decimals: 0,
},
],
});

const result = await tokensController.updateTokenType(tokenAddress);

expect(result.isERC721).toBe(true);
});

it('should add isERC721 = false to token object already in state when token is not a collectible and not in our contract-metadata repo', async function () {
const supportsInterfaceStub = sinon
.stub()
.returns(Promise.resolve(false));
await sinon
.stub(tokensController, '_createEthersContract')
.callsFake(() =>
Promise.resolve({ supportsInterface: supportsInterfaceStub }),
);
const tokenAddress = '0xda5584cc586d07c7141aa427224a4bd58e64af7d';
tokensController.update({
tokens: [
{
address: tokenAddress,
symbol: 'TESTNFT',
decimals: 0,
},
],
});

const result = await tokensController.updateTokenType(tokenAddress);

expect(result.isERC721).toBe(false);
});
const result = await tokensController.updateTokenType(address);
expect(result.isERC721).toBe(true);
});

it('should add isERC721 = true to token object in state when token is collectible and not in our contract-metadata repo', async function () {
const supportsInterfaceStub = sinon.stub().returns(Promise.resolve(true));
await sinon
.stub(tokensController, '_createEthersContract')
.callsFake(() =>
Promise.resolve({ supportsInterface: supportsInterfaceStub }),
describe('addToken method', function () {
it('should add isERC721 = true when token is a collectible and is in our contract-metadata repo', async function () {
const contractAddresses = Object.keys(contractMaps);
const erc721ContractAddresses = contractAddresses.filter(
(contractAddress) => contractMaps[contractAddress].erc721 === true,
);
const tokenAddress = '0xda5584cc586d07c7141aa427224a4bd58e64af7d';
tokensController.update({
tokens: [
const address = erc721ContractAddresses[0];
const { symbol, decimals } = contractMaps[address];
await tokensController.addToken(address, symbol, decimals);

expect(tokensController.state.tokens).toStrictEqual([
{
address: tokenAddress,
symbol: 'TESTNFT',
decimals: 0,
address,
symbol,
isERC721: true,
image: undefined,
decimals,
},
],
]);
});

const result = await tokensController.updateTokenType(tokenAddress);
it('should add isERC721 = true when the token is a collectible but not in our contract-metadata repo', async function () {
const supportsInterfaceStub = sinon
.stub()
.returns(Promise.resolve(true));
await sinon
.stub(tokensController, '_createEthersContract')
.callsFake(() =>
Promise.resolve({ supportsInterface: supportsInterfaceStub }),
);

expect(result.isERC721).toBe(true);
});
const tokenAddress = '0xDA5584Cc586d07c7141aA427224A4Bd58E64aF7D';

it('should return true when token is in our contract-metadata repo', async function () {
const supportsInterfaceStub = sinon.stub().returns(Promise.resolve(true));
await sinon
.stub(tokensController, '_createEthersContract')
.callsFake(() =>
Promise.resolve({ supportsInterface: supportsInterfaceStub }),
);
const tokenAddress = '0x06012c8cf97BEaD5deAe237070F9587f8E7A266d';
await tokensController.addToken(tokenAddress, 'REST', 4);

const result = await tokensController._detectIsERC721(tokenAddress);
expect(result).toBe(true);
});
expect(tokensController.state.tokens).toStrictEqual([
{
address: tokenAddress,
symbol: 'REST',
isERC721: true,
image: undefined,
decimals: 4,
},
]);
});

it('should return true when the token is not in our contract-metadata repo but tokenContract.supportsInterface returns true', async function () {
const supportsInterfaceStub = sinon.stub().returns(Promise.resolve(true));
await sinon
.stub(tokensController, '_createEthersContract')
.callsFake(() =>
Promise.resolve({ supportsInterface: supportsInterfaceStub }),
it('should add isERC721 = false to token object already in state when token is not a collectible and in our contract-metadata repo', async function () {
const contractAddresses = Object.keys(contractMaps);
const erc20ContractAddresses = contractAddresses.filter(
(contractAddress) => contractMaps[contractAddress].erc20 === true,
);
const address = erc20ContractAddresses[0];
const { symbol, decimals } = contractMaps[address];

const tokenAddress = '0xda5584cc586d07c7141aa427224a4bd58e64af7d';
await tokensController.addToken(address, symbol, decimals);

const result = await tokensController._detectIsERC721(tokenAddress);
expect(tokensController.state.tokens).toStrictEqual([
{
address,
symbol,
isERC721: false,
image: undefined,
decimals,
},
]);
});

expect(result).toBe(true);
});
it('should add isERC721 = false when the token is not a collectible and not in our contract-metadata repo', async function () {
const supportsInterfaceStub = sinon
.stub()
.returns(Promise.resolve(false));
await sinon
.stub(tokensController, '_createEthersContract')
.callsFake(() =>
Promise.resolve({ supportsInterface: supportsInterfaceStub }),
);
const tokenAddress = '0xDA5584Cc586d07c7141aA427224A4Bd58E64aF7D';

it('should return false when the token is not in our contract-metadata repo and tokenContract.supportsInterface returns false', async function () {
const supportsInterfaceStub = sinon
.stub()
.returns(Promise.resolve(false));
await sinon
.stub(tokensController, '_createEthersContract')
.callsFake(() =>
Promise.resolve({ supportsInterface: supportsInterfaceStub }),
);
const tokenAddress = '0xda5584cc586d07c7141aa427224a4bd58e64af7d';
await tokensController.addToken(tokenAddress, 'LEST', 5);

const result = await tokensController._detectIsERC721(tokenAddress);
expect(result).toBe(false);
expect(tokensController.state.tokens).toStrictEqual([
{
address: tokenAddress,
symbol: 'LEST',
isERC721: false,
image: undefined,
decimals: 5,
},
]);
});
});
});

Expand Down
3 changes: 3 additions & 0 deletions src/assets/TokensController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,10 @@ export class TokensController extends BaseController<
// to check against the contract
if (contractsMap[checksumAddress]?.erc721 === true) {
return Promise.resolve(true);
} else if (contractsMap[checksumAddress]?.erc20 === true) {
return Promise.resolve(false);
}

const tokenContract = await this._createEthersContract(
tokenAddress,
abiERC721,
Expand Down