Add demo for erc721-watcher

This commit is contained in:
nabarun 2022-06-08 16:08:09 +05:30 committed by Ashwin Phatak
parent 99aaa9ae0a
commit baa20de443
11 changed files with 311 additions and 15 deletions

3
packages/erc721-watcher/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
#Hardhat files
cache
artifacts

View File

@ -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
@ -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
@ -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:

View File

@ -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'
}
};

View File

@ -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",
@ -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",
@ -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"
}
}

View File

@ -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> {

View File

@ -1,3 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//

View File

@ -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);
}
}

View File

@ -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);
}
);

View File

@ -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);
});

View File

@ -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());
}
}
});

View File

@ -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());
}
}
});