Skip to content

Commit

Permalink
Add demo for erc721-watcher
Browse files Browse the repository at this point in the history
  • Loading branch information
nikugogoi authored and ashwinphatak committed Jun 8, 2022
1 parent 99aaa9a commit baa20de
Show file tree
Hide file tree
Showing 11 changed files with 311 additions and 15 deletions.
3 changes: 3 additions & 0 deletions packages/erc721-watcher/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#Hardhat files
cache
artifacts
166 changes: 158 additions & 8 deletions packages/erc721-watcher/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,6 @@
yarn
```

* Run the IPFS (go-ipfs version 0.12.2) daemon:

```bash
ipfs daemon
```

* Create a postgres12 database for the watcher:

```bash
Expand Down Expand Up @@ -41,13 +35,169 @@
erc721-watcher-job-queue=# exit
```

* The following core services should be setup and running on localhost:

* `vulcanize/go-ethereum` [v1.10.18-statediff-3.2.2](https://github.com/vulcanize/go-ethereum/releases/tag/v1.10.18-statediff-3.2.2) on port 8545

* `vulcanize/ipld-eth-server` [v3.2.2](https://github.com/vulcanize/ipld-eth-server/releases/tag/v3.2.2) with native GQL API enabled, on port 8082

* In the [config file](./environments/local.toml):

* Update the database connection settings.

* Update the `upstream` config and provide the `ipld-eth-server` GQL API endpoint.

* Update the `server` config with state checkpoint settings and provide the IPFS API address.
## Demo

* Deploy an ERC721 token:

```bash
yarn nft:deploy
# NFT deployed to: NFT_ADDRESS
```

Export the address of the deployed token to a shell variable for later use:

```bash
export NFT_ADDRESS="<NFT_ADDRESS>"
```

* Open `http://localhost:3006/graphql` (GraphQL Playground) in a browser window

* Connect MetaMask to `http://localhost:8545` (with chain ID `41337`)

* Add a second account to Metamask and export the account address to a shell variable for later use:

```bash
export RECIPIENT_ADDRESS="<RECIPIENT_ADDRESS>"
```

* To get the current block hash at any time, run:

```bash
yarn block:latest
```

* Run the following GQL query (`eth_call`) in generated watcher graphql endpoint http://127.0.0.1:3006/graphql

```graphql
query {
name(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "NFT_ADDRESS"
) {
value
proof {
data
}
}
symbol(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "NFT_ADDRESS"
) {
value
proof {
data
}
}
balanceOf(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "NFT_ADDRESS"
owner: "0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc"
) {
value
proof {
data
}
}
}
```

* Run the following GQL query (`storage`) in generated watcher graphql endpoint http://127.0.0.1:3006/graphql

```graphql
query {
_name(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "NFT_ADDRESS"
) {
value
proof {
data
}
}
_symbol(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "NFT_ADDRESS"
) {
value
proof {
data
}
}
_balances(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "NFT_ADDRESS"
key0: "0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc"
) {
value
proof {
data
}
}
}
```

* Mint token

```bash
yarn nft:mint --nft $NFT_ADDRESS --to 0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc --token-id 1
```

* Get the latest blockHash and run the following query for `balanceOf` and `ownerOf` (`eth_call`):

```graphql
query {
fromBalanceOf: balanceOf(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "NFT_ADDRESS"
owner: "0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc"
) {
value
proof {
data
}
}
toBalanceOf: balanceOf(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "NFT_ADDRESS"
owner: "RECIPIENT_ADDRESS"
) {
value
proof {
data
}
}
ownerOf(
blockHash: "LATEST_BLOCK_HASH"
contractAddress: "NFT_ADDRESS"
tokenId: 1
) {
value
proof {
data
}
}
}
```

* Transfer token

```bash
yarn nft:transfer --nft $NFT_ADDRESS --from 0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc --to $RECIPIENT_ADDRESS --token-id 1
```

* Get the latest blockHash and replace the blockHash in the above query. The result should be different and the token should be transferred to the recipient.

## Customize

Expand Down Expand Up @@ -99,7 +249,7 @@ GQL console: http://localhost:3006/graphql
Watch a contract with its address and checkpointing on:

```bash
yarn watch:contract --address 0x1F78641644feB8b64642e833cE4AFE93DD6e7833 --kind ERC20 --checkpoint true
yarn watch:contract --address 0x1F78641644feB8b64642e833cE4AFE93DD6e7833 --kind ERC721 --checkpoint true
```

Watch a contract with its identifier and checkpointing on:
Expand Down
28 changes: 28 additions & 0 deletions packages/erc721-watcher/hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// Copyright 2022 Vulcanize, Inc.
//

import '@nomiclabs/hardhat-waffle';

import './test/tasks/nft-deploy';
import './test/tasks/nft-mint';
import './test/tasks/nft-transfer';
import './test/tasks/block-latest';

// You need to export an object to set up your config
// Go to https://hardhat.org/config/ to learn more

/**
* @type import('hardhat/config').HardhatUserConfig
*/
export default {
solidity: '0.8.0',
networks: {
docker: {
url: 'http://geth:8545'
}
},
paths: {
sources: './test/contracts'
}
};
11 changes: 9 additions & 2 deletions packages/erc721-watcher/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
"checkpoint": "DEBUG=vulcanize:* ts-node src/cli/checkpoint.ts",
"export-state": "DEBUG=vulcanize:* ts-node src/cli/export-state.ts",
"import-state": "DEBUG=vulcanize:* ts-node src/cli/import-state.ts",
"inspect-cid": "DEBUG=vulcanize:* ts-node src/cli/inspect-cid.ts"
"inspect-cid": "DEBUG=vulcanize:* ts-node src/cli/inspect-cid.ts",
"nft:deploy": "hardhat --network localhost nft-deploy",
"nft:mint": "hardhat --network localhost nft-mint",
"nft:transfer": "hardhat --network localhost nft-transfer",
"block:latest": "hardhat --network localhost block-latest"
},
"repository": {
"type": "git",
Expand Down Expand Up @@ -50,6 +54,8 @@
},
"devDependencies": {
"@ethersproject/abi": "^5.3.0",
"@nomiclabs/hardhat-ethers": "^2.0.2",
"@nomiclabs/hardhat-waffle": "^2.0.1",
"@types/express": "^4.17.11",
"@types/yargs": "^17.0.0",
"@typescript-eslint/eslint-plugin": "^4.25.0",
Expand All @@ -62,6 +68,7 @@
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-standard": "^5.0.0",
"ts-node": "^10.0.0",
"typescript": "^4.3.2"
"typescript": "^4.3.2",
"hardhat": "^2.3.0"
}
}
2 changes: 0 additions & 2 deletions packages/erc721-watcher/src/indexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,8 @@ export class Indexer implements IPLDIndexerInterface {
this._contractMap.set(KIND_ERC721, new ethers.utils.Interface(ERC721ABI));

this._entityTypesMap = new Map();
this._populateEntityTypesMap();

this._relationsMap = new Map();
this._populateRelationsMap();
}

async init (): Promise<void> {
Expand Down
3 changes: 0 additions & 3 deletions packages/erc721-watcher/src/types.ts

This file was deleted.

13 changes: 13 additions & 0 deletions packages/erc721-watcher/test/contracts/TestNFT.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract TestNFT is ERC721 {
constructor() ERC721("TestNFT", "TNFT") {
}

function mint(address to, uint256 tokenId) public {
_safeMint(to, tokenId);
}
}
18 changes: 18 additions & 0 deletions packages/erc721-watcher/test/tasks/block-latest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// Copyright 2022 Vulcanize, Inc.
//

import { task } from 'hardhat/config';
import '@nomiclabs/hardhat-ethers';

task(
'block-latest',
'Prints the current block info',
async (_, { ethers }) => {
const blockNumber = await ethers.provider.getBlockNumber();
const block = await ethers.provider.getBlock(blockNumber);

console.log('Block Number:', blockNumber);
console.log('Block Hash:', block.hash);
}
);
15 changes: 15 additions & 0 deletions packages/erc721-watcher/test/tasks/nft-deploy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// Copyright 2022 Vulcanize, Inc.
//

import { task } from 'hardhat/config';
import '@nomiclabs/hardhat-ethers';

task('nft-deploy', 'Deploys NFT')
.setAction(async (args, hre) => {
await hre.run('compile');
const NFT = await hre.ethers.getContractFactory('TestNFT');
const nft = await NFT.deploy();

console.log('NFT deployed to:', nft.address);
});
33 changes: 33 additions & 0 deletions packages/erc721-watcher/test/tasks/nft-mint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// Copyright 2022 Vulcanize, Inc.
//

import { task, types } from 'hardhat/config';
import '@nomiclabs/hardhat-ethers';
import { ContractTransaction } from 'ethers';

task('nft-mint', 'Mint NFT')
.addParam('nft', 'Contract address', undefined, types.string)
.addParam('tokenId', 'Token ID', undefined, types.string)
.addParam('to', 'Transfer recipient address', undefined, types.string)
.setAction(async (args, hre) => {
const { tokenId, to, nft: contractAddress } = args;
await hre.run('compile');
const NFT = await hre.ethers.getContractFactory('TestNFT');
const nft = NFT.attach(contractAddress);

const transaction: ContractTransaction = await nft.mint(to, tokenId);

const receipt = await transaction.wait();

if (receipt.events) {
const TransferEvent = receipt.events.find(el => el.event === 'Transfer');

if (TransferEvent && TransferEvent.args) {
console.log('Transfer Event');
console.log('from:', TransferEvent.args.from.toString());
console.log('to:', TransferEvent.args.to.toString());
console.log('tokenId:', TransferEvent.args.tokenId.toString());
}
}
});
34 changes: 34 additions & 0 deletions packages/erc721-watcher/test/tasks/nft-transfer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// Copyright 2022 Vulcanize, Inc.
//

import { task, types } from 'hardhat/config';
import '@nomiclabs/hardhat-ethers';
import { ContractTransaction } from 'ethers';

task('nft-transfer', 'Move tokens to recipient')
.addParam('nft', 'Contract address', undefined, types.string)
.addParam('from', 'Transfer from address', undefined, types.string)
.addParam('to', 'Transfer recipient address', undefined, types.string)
.addParam('tokenId', 'Token ID to transfer', undefined, types.string)
.setAction(async (args, hre) => {
const { nft: contractAddress, from, to, tokenId } = args;
await hre.run('compile');
const NFT = await hre.ethers.getContractFactory('TestNFT');
const nft = NFT.attach(contractAddress);

const transaction: ContractTransaction = await nft['safeTransferFrom(address,address,uint256)'](from, to, tokenId);

const receipt = await transaction.wait();

if (receipt.events) {
const TransferEvent = receipt.events.find(el => el.event === 'Transfer');

if (TransferEvent && TransferEvent.args) {
console.log('Transfer Event');
console.log('from:', TransferEvent.args.from.toString());
console.log('to:', TransferEvent.args.to.toString());
console.log('tokenId:', TransferEvent.args.tokenId.toString());
}
}
});

0 comments on commit baa20de

Please sign in to comment.