Add a local stack for ERC721 watcher (#81)
* Add a stack for erc721 watcher * Add a demo * Avoid watcher db service and volume name conflicts across watchers * Avoid host port conflicts across watchers * Avoid watcher-db port conflicts
This commit is contained in:
parent
a7221ddc24
commit
27c3efabe2
@ -14,6 +14,7 @@ cerc/fixturenet-eth-geth
|
||||
cerc/fixturenet-eth-lighthouse
|
||||
cerc/watcher-mobymask
|
||||
cerc/watcher-erc20
|
||||
cerc/watcher-erc721
|
||||
cerc/test-container
|
||||
cerc/eth-probe
|
||||
cerc/builder-js
|
||||
|
@ -12,6 +12,7 @@ fixturenet-laconicd
|
||||
fixturenet-eth
|
||||
watcher-mobymask
|
||||
watcher-erc20
|
||||
watcher-erc721
|
||||
test
|
||||
eth-probe
|
||||
keycloak
|
||||
|
@ -2,7 +2,7 @@ version: '3.2'
|
||||
|
||||
services:
|
||||
|
||||
watcher-db:
|
||||
erc20-watcher-db:
|
||||
restart: unless-stopped
|
||||
image: postgres:14-alpine
|
||||
environment:
|
||||
@ -12,9 +12,9 @@ services:
|
||||
- POSTGRES_PASSWORD=password
|
||||
volumes:
|
||||
- ../config/postgresql/multiple-postgressql-databases.sh:/docker-entrypoint-initdb.d/multiple-postgressql-databases.sh
|
||||
- watcher_db_data:/var/lib/postgresql/data
|
||||
- erc20_watcher_db_data:/var/lib/postgresql/data
|
||||
ports:
|
||||
- "0.0.0.0:15432:5432"
|
||||
- "0.0.0.0:15433:5432"
|
||||
healthcheck:
|
||||
test: ["CMD", "nc", "-v", "localhost", "5432"]
|
||||
interval: 20s
|
||||
@ -27,7 +27,7 @@ services:
|
||||
depends_on:
|
||||
ipld-eth-server:
|
||||
condition: service_healthy
|
||||
watcher-db:
|
||||
erc20-watcher-db:
|
||||
condition: service_healthy
|
||||
image: cerc/watcher-erc20:local
|
||||
environment:
|
||||
@ -36,14 +36,14 @@ services:
|
||||
volumes:
|
||||
- ../config/watcher-erc20/erc20-watcher.toml:/app/packages/erc20-watcher/environments/local.toml
|
||||
ports:
|
||||
- "0.0.0.0:3001:3001"
|
||||
- "0.0.0.0:9001:9001"
|
||||
- "0.0.0.0:3002:3001"
|
||||
- "0.0.0.0:9002:9001"
|
||||
healthcheck:
|
||||
test: ["CMD", "nc", "-v", "localhost", "3001"]
|
||||
test: ["CMD", "nc", "-v", "localhost", "3002"]
|
||||
interval: 20s
|
||||
timeout: 5s
|
||||
retries: 15
|
||||
start_period: 5s
|
||||
|
||||
volumes:
|
||||
watcher_db_data:
|
||||
erc20_watcher_db_data:
|
||||
|
49
compose/docker-compose-watcher-erc721.yml
Normal file
49
compose/docker-compose-watcher-erc721.yml
Normal file
@ -0,0 +1,49 @@
|
||||
version: '3.2'
|
||||
|
||||
services:
|
||||
|
||||
erc721-watcher-db:
|
||||
restart: unless-stopped
|
||||
image: postgres:14-alpine
|
||||
environment:
|
||||
- POSTGRES_USER=vdbm
|
||||
- POSTGRES_MULTIPLE_DATABASES=erc721-watcher,erc721-watcher-job-queue
|
||||
- POSTGRES_EXTENSION=erc721-watcher-job-queue:pgcrypto
|
||||
- POSTGRES_PASSWORD=password
|
||||
volumes:
|
||||
- ../config/postgresql/multiple-postgressql-databases.sh:/docker-entrypoint-initdb.d/multiple-postgressql-databases.sh
|
||||
- erc721_watcher_db_data:/var/lib/postgresql/data
|
||||
ports:
|
||||
- "0.0.0.0:15434:5432"
|
||||
healthcheck:
|
||||
test: ["CMD", "nc", "-v", "localhost", "5432"]
|
||||
interval: 20s
|
||||
timeout: 5s
|
||||
retries: 15
|
||||
start_period: 10s
|
||||
|
||||
erc721-watcher:
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
ipld-eth-server:
|
||||
condition: service_healthy
|
||||
erc721-watcher-db:
|
||||
condition: service_healthy
|
||||
image: cerc/watcher-erc721:local
|
||||
environment:
|
||||
- ETH_RPC_URL=http://go-ethereum:8545
|
||||
command: ["sh", "-c", "yarn server"]
|
||||
volumes:
|
||||
- ../config/watcher-erc721/erc721-watcher.toml:/app/packages/erc721-watcher/environments/local.toml
|
||||
ports:
|
||||
- "0.0.0.0:3009:3009"
|
||||
- "0.0.0.0:9003:9001"
|
||||
healthcheck:
|
||||
test: ["CMD", "nc", "-v", "localhost", "3009"]
|
||||
interval: 20s
|
||||
timeout: 5s
|
||||
retries: 15
|
||||
start_period: 5s
|
||||
|
||||
volumes:
|
||||
erc721_watcher_db_data:
|
@ -12,7 +12,7 @@
|
||||
|
||||
[database]
|
||||
type = "postgres"
|
||||
host = "watcher-db"
|
||||
host = "erc20-watcher-db"
|
||||
port = 5432
|
||||
database = "erc20-watcher"
|
||||
username = "vdbm"
|
||||
@ -32,7 +32,7 @@
|
||||
deleteOnStart = false
|
||||
|
||||
[jobQueue]
|
||||
dbConnectionString = "postgres://vdbm:password@watcher-db:5432/erc20-watcher-job-queue"
|
||||
dbConnectionString = "postgres://vdbm:password@erc20-watcher-db:5432/erc20-watcher-job-queue"
|
||||
maxCompletionLagInSecs = 300
|
||||
jobDelayInMilliSecs = 100
|
||||
eventsInBatch = 50
|
||||
|
56
config/watcher-erc721/erc721-watcher.toml
Normal file
56
config/watcher-erc721/erc721-watcher.toml
Normal file
@ -0,0 +1,56 @@
|
||||
[server]
|
||||
host = "0.0.0.0"
|
||||
port = 3009
|
||||
kind = "lazy"
|
||||
|
||||
# Checkpointing state.
|
||||
checkpointing = true
|
||||
|
||||
# Checkpoint interval in number of blocks.
|
||||
checkpointInterval = 2000
|
||||
|
||||
# Enable state creation
|
||||
enableState = true
|
||||
|
||||
# Boolean to filter logs by contract.
|
||||
filterLogs = false
|
||||
|
||||
# Max block range for which to return events in eventsInRange GQL query.
|
||||
# Use -1 for skipping check on block range.
|
||||
maxEventsBlockRange = 1000
|
||||
|
||||
[metrics]
|
||||
host = "127.0.0.1"
|
||||
port = 9000
|
||||
[metrics.gql]
|
||||
port = 9001
|
||||
|
||||
[database]
|
||||
type = "postgres"
|
||||
host = "erc721-watcher-db"
|
||||
port = 5432
|
||||
database = "erc721-watcher"
|
||||
username = "vdbm"
|
||||
password = "password"
|
||||
synchronize = true
|
||||
logging = false
|
||||
maxQueryExecutionTime = 100
|
||||
|
||||
[upstream]
|
||||
[upstream.ethServer]
|
||||
gqlApiEndpoint = "http://ipld-eth-server:8082/graphql"
|
||||
rpcProviderEndpoint = "http://ipld-eth-server:8081"
|
||||
|
||||
[upstream.cache]
|
||||
name = "requests"
|
||||
enabled = false
|
||||
deleteOnStart = false
|
||||
|
||||
[jobQueue]
|
||||
dbConnectionString = "postgres://vdbm:password@erc721-watcher-db:5432/erc721-watcher-job-queue"
|
||||
maxCompletionLagInSecs = 300
|
||||
jobDelayInMilliSecs = 100
|
||||
eventsInBatch = 50
|
||||
blockDelayInMilliSecs = 2000
|
||||
prefetchBlocksInMem = true
|
||||
prefetchBlockCount = 10
|
13
container-build/cerc-watcher-erc721/Dockerfile
Normal file
13
container-build/cerc-watcher-erc721/Dockerfile
Normal file
@ -0,0 +1,13 @@
|
||||
FROM node:16.17.1-alpine3.16
|
||||
|
||||
RUN apk --update --no-cache add git python3 alpine-sdk
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN echo "Building watcher-ts" && \
|
||||
git checkout v0.2.19 && \
|
||||
yarn && yarn build
|
||||
|
||||
WORKDIR /app/packages/erc721-watcher
|
7
container-build/cerc-watcher-erc721/build.sh
Executable file
7
container-build/cerc-watcher-erc721/build.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build cerc/watcher-erc721
|
||||
|
||||
# See: https://stackoverflow.com/a/246128/1701505
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
|
||||
docker build -t cerc/watcher-erc721:local -f ${SCRIPT_DIR}/Dockerfile ${CERC_REPO_BASE_DIR}/watcher-ts
|
214
stacks/erc721/README.md
Normal file
214
stacks/erc721/README.md
Normal file
@ -0,0 +1,214 @@
|
||||
# ERC721 Watcher
|
||||
|
||||
Instructions to deploy a local ERC721 watcher stack (core + watcher) for demonstration and testing purposes using [laconic-stack-orchestrator](../../README.md#setup)
|
||||
|
||||
## Setup
|
||||
|
||||
* Clone / pull required repositories:
|
||||
|
||||
```bash
|
||||
$ laconic-so setup-repositories --include cerc-io/go-ethereum,cerc-io/ipld-eth-db,cerc-io/ipld-eth-server,cerc-io/watcher-ts --pull
|
||||
```
|
||||
|
||||
* Build the core and watcher container images:
|
||||
|
||||
```bash
|
||||
$ laconic-so build-containers --include cerc/go-ethereum,cerc/go-ethereum-foundry,cerc/ipld-eth-db,cerc/ipld-eth-server,cerc/watcher-erc721
|
||||
```
|
||||
|
||||
This should create the required docker images in the local image registry.
|
||||
|
||||
* Deploy the stack:
|
||||
|
||||
```bash
|
||||
$ laconic-so deploy-system --include db,go-ethereum-foundry,ipld-eth-server,watcher-erc721 up
|
||||
```
|
||||
|
||||
## Demo
|
||||
|
||||
* Find the watcher container's id using `docker ps` and export it for later use:
|
||||
|
||||
```bash
|
||||
$ export CONTAINER_ID=<CONTAINER_ID>
|
||||
```
|
||||
|
||||
* Deploy an ERC721 token:
|
||||
|
||||
```bash
|
||||
$ docker exec $CONTAINER_ID yarn nft:deploy:docker
|
||||
```
|
||||
|
||||
Export the address of the deployed token to a shell variable for later use:
|
||||
|
||||
```bash
|
||||
$ export NFT_ADDRESS=<NFT_ADDRESS>
|
||||
```
|
||||
|
||||
* Open `http://localhost:3009/graphql` (GraphQL Playground) in a browser window
|
||||
|
||||
* Connect MetaMask to `http://localhost:8545` (with chain ID `99`)
|
||||
|
||||
* Export your MetaMask account (second account) address to a shell variable for later use:
|
||||
|
||||
```bash
|
||||
$ export RECIPIENT_ADDRESS=<RECIPIENT_ADDRESS>
|
||||
```
|
||||
|
||||
* To get the primary account's address, run:
|
||||
|
||||
```bash
|
||||
$ docker exec $CONTAINER_ID yarn account:docker
|
||||
```
|
||||
|
||||
Export it to shell variable for later use:
|
||||
|
||||
```bash
|
||||
$ export PRIMARY_ADDRESS=<PRIMARY_ADDRESS>
|
||||
```
|
||||
|
||||
* To get the current block hash at any time, run:
|
||||
|
||||
```bash
|
||||
$ docker exec $CONTAINER_ID yarn block:latest:docker
|
||||
```
|
||||
|
||||
* Fire the following GQL query (uses `eth_call`) in the playground:
|
||||
|
||||
```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: "PRIMARY_ADDRESS"
|
||||
) {
|
||||
value
|
||||
proof {
|
||||
data
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Balance for the `PRIMARY_ADDRESS` should be `0` as the token is yet to be minted.
|
||||
|
||||
* Fire the following GQL query (uses `storage` calls) in the playground:
|
||||
|
||||
```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: "PRIMARY_ADDRESS"
|
||||
) {
|
||||
value
|
||||
proof {
|
||||
data
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
* Mint the token:
|
||||
|
||||
```bash
|
||||
$ docker exec $CONTAINER_ID yarn nft:mint:docker --nft $NFT_ADDRESS --to $PRIMARY_ADDRESS --token-id 1
|
||||
```
|
||||
|
||||
Fire the GQL query above again with latest block hash. The balance should increase to `1`.
|
||||
|
||||
* Get the latest block hash and run the following GQL query in the playground for `balanceOf` and `ownerOf` (`eth_call`):
|
||||
|
||||
```graphql
|
||||
query {
|
||||
fromBalanceOf: balanceOf(
|
||||
blockHash: "LATEST_BLOCK_HASH"
|
||||
contractAddress: "NFT_ADDRESS"
|
||||
owner: "PRIMARY_ADDRESS"
|
||||
) {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Balance should be `1` for the `PRIMARY_ADDRESS`, `0` for the `RECIPIENT_ADDRESS` and owner value of the token should be equal to the `PRIMARY_ADDRESS`.
|
||||
|
||||
* Transfer the token:
|
||||
|
||||
```bash
|
||||
$ docker exec $CONTAINER_ID yarn nft:transfer:docker --nft $NFT_ADDRESS --from $PRIMARY_ADDRESS --to $RECIPIENT_ADDRESS --token-id 1
|
||||
```
|
||||
|
||||
Fire the GQL query above again with the latest block hash. The token should be transferred to the recipient.
|
||||
|
||||
## Clean up
|
||||
|
||||
* To stop all the services running in background:
|
||||
|
||||
```bash
|
||||
$ laconic-so deploy-system --include db,go-ethereum-foundry,ipld-eth-server,watcher-erc721 down
|
||||
```
|
18
stacks/erc721/stack.yml
Normal file
18
stacks/erc721/stack.yml
Normal file
@ -0,0 +1,18 @@
|
||||
version: "1.0"
|
||||
name: erc721-watcher
|
||||
repos:
|
||||
- cerc-io/go-ethereum
|
||||
- cerc-io/ipld-eth-db
|
||||
- cerc-io/ipld-eth-server
|
||||
- cerc-io/watcher-ts
|
||||
containers:
|
||||
- cerc/go-ethereum
|
||||
- cerc/go-ethereum-foundry
|
||||
- cerc/ipld-eth-db
|
||||
- cerc/ipld-eth-server
|
||||
- cerc/watcher-erc721
|
||||
pods:
|
||||
- go-ethereum-foundry
|
||||
- db
|
||||
- ipld-eth-server
|
||||
- watcher-erc721
|
Loading…
Reference in New Issue
Block a user