mirror of
https://github.com/cerc-io/watcher-ts
synced 2025-01-22 19:19:05 +00:00
Add demo for erc721-watcher
This commit is contained in:
parent
99aaa9ae0a
commit
baa20de443
3
packages/erc721-watcher/.gitignore
vendored
Normal file
3
packages/erc721-watcher/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#Hardhat files
|
||||||
|
cache
|
||||||
|
artifacts
|
@ -8,12 +8,6 @@
|
|||||||
yarn
|
yarn
|
||||||
```
|
```
|
||||||
|
|
||||||
* Run the IPFS (go-ipfs version 0.12.2) daemon:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ipfs daemon
|
|
||||||
```
|
|
||||||
|
|
||||||
* Create a postgres12 database for the watcher:
|
* Create a postgres12 database for the watcher:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@ -41,13 +35,169 @@
|
|||||||
erc721-watcher-job-queue=# exit
|
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):
|
* In the [config file](./environments/local.toml):
|
||||||
|
|
||||||
* Update the database connection settings.
|
* Update the database connection settings.
|
||||||
|
|
||||||
* Update the `upstream` config and provide the `ipld-eth-server` GQL API endpoint.
|
* 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
|
## Customize
|
||||||
|
|
||||||
@ -99,7 +249,7 @@ GQL console: http://localhost:3006/graphql
|
|||||||
Watch a contract with its address and checkpointing on:
|
Watch a contract with its address and checkpointing on:
|
||||||
|
|
||||||
```bash
|
```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:
|
Watch a contract with its identifier and checkpointing on:
|
||||||
|
28
packages/erc721-watcher/hardhat.config.ts
Normal file
28
packages/erc721-watcher/hardhat.config.ts
Normal 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'
|
||||||
|
}
|
||||||
|
};
|
@ -15,7 +15,11 @@
|
|||||||
"checkpoint": "DEBUG=vulcanize:* ts-node src/cli/checkpoint.ts",
|
"checkpoint": "DEBUG=vulcanize:* ts-node src/cli/checkpoint.ts",
|
||||||
"export-state": "DEBUG=vulcanize:* ts-node src/cli/export-state.ts",
|
"export-state": "DEBUG=vulcanize:* ts-node src/cli/export-state.ts",
|
||||||
"import-state": "DEBUG=vulcanize:* ts-node src/cli/import-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": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -50,6 +54,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ethersproject/abi": "^5.3.0",
|
"@ethersproject/abi": "^5.3.0",
|
||||||
|
"@nomiclabs/hardhat-ethers": "^2.0.2",
|
||||||
|
"@nomiclabs/hardhat-waffle": "^2.0.1",
|
||||||
"@types/express": "^4.17.11",
|
"@types/express": "^4.17.11",
|
||||||
"@types/yargs": "^17.0.0",
|
"@types/yargs": "^17.0.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.25.0",
|
"@typescript-eslint/eslint-plugin": "^4.25.0",
|
||||||
@ -62,6 +68,7 @@
|
|||||||
"eslint-plugin-promise": "^5.1.0",
|
"eslint-plugin-promise": "^5.1.0",
|
||||||
"eslint-plugin-standard": "^5.0.0",
|
"eslint-plugin-standard": "^5.0.0",
|
||||||
"ts-node": "^10.0.0",
|
"ts-node": "^10.0.0",
|
||||||
"typescript": "^4.3.2"
|
"typescript": "^4.3.2",
|
||||||
|
"hardhat": "^2.3.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,10 +132,8 @@ export class Indexer implements IPLDIndexerInterface {
|
|||||||
this._contractMap.set(KIND_ERC721, new ethers.utils.Interface(ERC721ABI));
|
this._contractMap.set(KIND_ERC721, new ethers.utils.Interface(ERC721ABI));
|
||||||
|
|
||||||
this._entityTypesMap = new Map();
|
this._entityTypesMap = new Map();
|
||||||
this._populateEntityTypesMap();
|
|
||||||
|
|
||||||
this._relationsMap = new Map();
|
this._relationsMap = new Map();
|
||||||
this._populateRelationsMap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async init (): Promise<void> {
|
async init (): Promise<void> {
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2021 Vulcanize, Inc.
|
|
||||||
//
|
|
13
packages/erc721-watcher/test/contracts/TestNFT.sol
Normal file
13
packages/erc721-watcher/test/contracts/TestNFT.sol
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
18
packages/erc721-watcher/test/tasks/block-latest.ts
Normal file
18
packages/erc721-watcher/test/tasks/block-latest.ts
Normal 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);
|
||||||
|
}
|
||||||
|
);
|
15
packages/erc721-watcher/test/tasks/nft-deploy.ts
Normal file
15
packages/erc721-watcher/test/tasks/nft-deploy.ts
Normal 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);
|
||||||
|
});
|
33
packages/erc721-watcher/test/tasks/nft-mint.ts
Normal file
33
packages/erc721-watcher/test/tasks/nft-mint.ts
Normal 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
34
packages/erc721-watcher/test/tasks/nft-transfer.ts
Normal file
34
packages/erc721-watcher/test/tasks/nft-transfer.ts
Normal 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user