Skip to content
This repository has been archived by the owner on Jan 21, 2022. It is now read-only.

[WIP] Implementation of plugins for ERC165, ERC721 and cryptokitties #116

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
53 changes: 53 additions & 0 deletions src/__tests__/erc165/erc165.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import core from '../../core';
import erc165 from '../../erc165';
import { testGraphql } from '../utils';

const { execQuery } = testGraphql({ optsOverride: { plugins: [core, erc165] } });

test('erc165: Cryptokitties supports ERC165 interface', async () => {
const query = `
{
account(address:"0x06012c8cf97BEaD5deAe237070F9587f8E7A266d") {
supportsInterface(interfaceID: "0x01ffc9a7")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We prefer strict camel casing.

Suggested change
supportsInterface(interfaceID: "0x01ffc9a7")
supportsInterface(interfaceId: "0x01ffc9a7")

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer too, but that's the language of the original EIP - https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md. Of course we can do interfaceId, your call.

}
}
`;

const result = await execQuery(query);
expect(result.errors).toBeUndefined();
expect(result.data).not.toBeUndefined();
expect(result.data.account.supportsInterface).toEqual(true);
});

test('erc165: Cryptokitties supports ERC721 interface', async () => {
const query = `
{
account(address:"0x06012c8cf97BEaD5deAe237070F9587f8E7A266d") {
supportsInterface(interfaceID: "0x9a20483d")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about we add a a field an an enum type for known interface IDs?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as a new grapql method (like supportsInterfaceByEnum) or just at the backend?

}
}
`;

const result = await execQuery(query);
expect(result.errors).toBeUndefined();
expect(result.data).not.toBeUndefined();

expect(result.data.account.supportsInterface).toEqual(true);
});

test('erc165: OmiseGO does not support ERC165', async () => {
const query = `
{
account(address:"0xd26114cd6EE289AccF82350c8d8487fedB8A0C07") {
address,
supportsInterface(interfaceID: "0x01ffc9a7")
}
}
`;

const result = await execQuery(query);
expect(result.errors).toBeUndefined();
expect(result.data).not.toBeUndefined();

expect(result.data.account.supportsInterface).toEqual(false);
});
209 changes: 209 additions & 0 deletions src/__tests__/erc721/erc721.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
import core from '../../core';
import erc165 from '../../erc165';
import erc20 from '../../erc20';
import erc721 from '../../erc721';
import { testGraphql } from '../utils';

const { execQuery } = testGraphql({ optsOverride: { plugins: [core, erc165, erc721] } });

test('erc721: nftToken balanceOf query #1', async () => {
const query = `
{
account(address: "0x6EbeAf8e8E946F0716E6533A6f2cefc83f60e8Ab") {
nftToken {
balanceOf(owner: "0xD418c5d0c4a3D87a6c555B7aA41f13EF87485Ec6")
}
}
}
`;
const result = await execQuery(query);
expect(result.errors).toBeUndefined();
expect(result.data).not.toBeUndefined();

expect(result.data).toEqual({
account: {
nftToken: {
balanceOf: 0,
},
},
});
});

test('erc721: nftToken balanceOf query #2', async () => {
const query = `
{
account(address: "0x6EbeAf8e8E946F0716E6533A6f2cefc83f60e8Ab") {
nftToken {
balanceOf(owner: "0x6f00cE7253bFD3A5A1c307b5E13814BF3433C72f")
}
}
}
`;
const result = await execQuery(query);
expect(result.errors).toBeUndefined();
expect(result.data).not.toBeUndefined();

expect(result.data).toEqual({
account: {
nftToken: {
balanceOf: 5,
},
},
});
});

test('erc721: nftToken ownerOf query', async () => {
const query = `
{
account(address: "0x6EbeAf8e8E946F0716E6533A6f2cefc83f60e8Ab") {
nftToken {
ownerOf(tokenId: 143880)
}
}
}
`;
const result = await execQuery(query);
expect(result.errors).toBeUndefined();
expect(result.data).not.toBeUndefined();

expect(result.data).toEqual({
account: {
nftToken: {
ownerOf: '0x6f00cE7253bFD3A5A1c307b5E13814BF3433C72f',
},
},
});
});

test('erc721: nftToken getApproved query', async () => {
const query = `
{
account(address:"0x6EbeAf8e8E946F0716E6533A6f2cefc83f60e8Ab") {
nftToken {
getApproved(tokenId: 33525)
}
}
}
`;
const result = await execQuery(query);
expect(result.errors).toBeUndefined();
expect(result.data).not.toBeUndefined();

expect(result.data).toEqual({
account: {
nftToken: {
getApproved: '0x0000000000000000000000000000000000000000',
},
},
});
});

test('erc721: nftToken isApprovedForAll query', async () => {
const query = `
{
account(address:"0x6EbeAf8e8E946F0716E6533A6f2cefc83f60e8Ab") {
nftToken {
isApprovedForAll(owner: "0xb85e9bdfCA73a536BE641bB5eacBA0772eA3E61E", operator: "0xD418c5d0c4a3D87a6c555B7aA41f13EF87485Ec6")
}
}
}
`;
const result = await execQuery(query);
expect(result.errors).toBeUndefined();
expect(result.data).not.toBeUndefined();

expect(result.data).toEqual({
account: {
nftToken: {
isApprovedForAll: false,
},
},
});
});

//44

test('erc721: not decodable', async () => {
const query = `
{
block(number: 5000000) {
hash
transactionAt(index: 66) {
value
decoded {
standard
operation
... on ERC721TransferFrom {
from {
account {
address
}
}
to {
account {
address
}
}
tokenId
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, nice test.

}
}
}
}
}
`;

const result = await execQuery(query);
expect(result.errors).toBeUndefined();
expect(result.data).not.toBeUndefined();

const tx = result.data.block.transactionAt;
expect(tx.value).toBeGreaterThan(0);
expect(tx.decoded).toEqual(null);
});

test('erc721: decode transfer log', async () => {
const query = `
{
transaction(hash: "0x5e9e7570cde63860a7cb71542729deb6d4dd796af70bb464050ca06ec7fc4bc9") {
hash
logs{
decoded {
... on ERC721TransferEvent{
from {
account {
address
}
}
to {
account {
address
}
},
tokenId
}
}
}
}
}`;

const result = await execQuery(query);
expect(result.errors).toBeUndefined();
expect(result.data).not.toBeUndefined();

const tranferLog = result.data.transaction.logs[0];
expect(tranferLog).toEqual({
decoded: {
from: {
account: {
address: '0x0000000000000000000000000000000000000000',
},
},
to: {
account: {
address: '0xc93227eee6e77db998a1ff5b01049fec8a5694cc',
},
},
tokenId: 43820,
},
});
});
12 changes: 8 additions & 4 deletions src/abi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ We classify supported ABIs in two types:

## Supported ABIs

| Standard | Type | Entity | Specification | Comments |
| -------- | --------- | ------ | ------------- | --------------------------------------------------------------- |
| ERC20 | Entity |  Token | [link][1] | |
| ERC223 | Extension |  Token | [link][2] | Private ERC20 implementation change. No action needed in ethql. |
| Standard | Type | Entity | Specification | Comments |
| -------- | --------- | --------- | ------------- | --------------------------------------------------------------- |
| ERC20 | Entity |  Token | [link][1] | |
| ERC223 | Extension |  Token | [link][2] | Private ERC20 implementation change. No action needed in ethql. |
| ERC165 | Entity | Interface | [link][3] | |
leonprou marked this conversation as resolved.
Show resolved Hide resolved
| ERC721 | Entity | Token | [link][4] | |

## ethql naming scheme

Expand All @@ -28,3 +30,5 @@ logs pertaining to several standards that relate to the same entity.

[1]: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
[2]: https://github.com/ethereum/EIPs/issues/223
[3]: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
[4]: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
21 changes: 21 additions & 0 deletions src/abi/erc165.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Watch the indentation here! Check out erc20.json.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what plugin did you use to indentation?

{
"constant": true,
"inputs": [
{
"name": "interfaceID",
"type": "bytes4"
}
],
"name": "supportsInterface",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
}
]
Loading