Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions playground/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@ POSTGRES_PASSWORD=123
TOML_TRACE_ERROR=1
CHAIN=1
ETHFLOW_CONTRACTS=0x04501b9b1d52e67f6862d157e00d13419d2d6e95

# Otterscan Sourcify source: "cloud" (default) or "local"
# - cloud: Shows publicly verified contracts from sourcify.dev
# - local: Shows contracts verified on the local Sourcify instance
SOURCIFY_MODE=cloud
2 changes: 1 addition & 1 deletion playground/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM debian:bookworm AS chef
WORKDIR /src/
RUN apt-get update && apt-get install -y curl git clang mold libssl-dev pkg-config git && apt-get clean
RUN apt-get update && apt-get install -y curl git clang mold libssl-dev pkg-config git make && apt-get clean
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
ENV PATH="$PATH:/root/.cargo/bin"
RUN rustup component add clippy rustfmt
Expand Down
6 changes: 6 additions & 0 deletions playground/Dockerfile.otterscan
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FROM otterscan/otterscan:latest

COPY otterscan-entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]
31 changes: 31 additions & 0 deletions playground/Dockerfile.sourcify
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
FROM node:24-bookworm-slim

# Install dependencies
RUN apt-get update && apt-get install -y git curl postgresql-client && \
curl -fsSL -o /usr/local/bin/dbmate https://github.com/amacneil/dbmate/releases/download/v2.21.0/dbmate-linux-amd64 && \
chmod +x /usr/local/bin/dbmate && \
apt-get clean && rm -rf /var/lib/apt/lists/*

# Clone Sourcify with submodules
RUN git clone --depth 1 --branch master --recurse-submodules https://github.com/argotorg/sourcify.git /sourcify

WORKDIR /sourcify

# Install dependencies and build
RUN npm install && npm run build:lerna

# Prepare migrations
WORKDIR /sourcify/services/database
RUN mkdir -p /migrations && \
cp -r database-specs/migrations/* /migrations/ 2>/dev/null || true && \
cp -r migrations/* /migrations/ 2>/dev/null || true

WORKDIR /sourcify/services/server

# Copy custom entrypoint
COPY sourcify-entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

EXPOSE 5555

ENTRYPOINT ["/entrypoint.sh"]
50 changes: 49 additions & 1 deletion playground/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ await window.ethereum.request({
| Postgres | postgres | 5432 | 5432 | N/A | Local/Fork |
| Adminer | adminer | 8082 | 8080 | N/A | Local/Fork |
| Grafana | grafana | 3000 | 3000 | N/A | Local/Fork |
| Otterscan | otterscan | 8003 | 80 | N/A | Local/Fork |
| Sourcify | sourcify | 5555 | 5555 | N/A | Local/Fork |
| Sourcify DB | sourcify-db | N/A | 5432 | N/A | Local/Fork |

**NOTE**: Currently only **FORK** mode is supported.

Expand All @@ -137,7 +140,8 @@ In this mode, the stack will spin up:
- Postgres (with migrations)
- Adminer
- RPC (forked from `reth` or `erigon` node)
- Otterscan (*not yet implemented*)
- Otterscan
- Sourcify (contract verification)
- Orderbook
- Autopilot
- Driver
Expand All @@ -150,3 +154,47 @@ In this mode, the stack will spin up:
**NOT YET IMPLEMENTED**

- As per fork, but with a local node (not forked from Erigon)

## Contract Verification with Sourcify

The playground includes a local [Sourcify](https://sourcify.dev/) instance for contract verification. Sourcify is a decentralized contract verification service that matches deployed bytecode with source code. Verified contracts display their source code in Otterscan.

**How it works:**

- **Cloud mode** (`SOURCIFY_MODE=cloud`): Otterscan fetches verified source code from the public Sourcify repository. This shows source code for well-known contracts (CoW Protocol, USDC, etc.) that have been publicly verified.
- **Local mode** (`SOURCIFY_MODE=local`): Otterscan fetches from your local Sourcify instance. Use this when testing contracts you deploy and verify locally.

### Sourcify Sources Configuration

Configure which Sourcify source Otterscan uses in your `.env` file:

```bash
# Use public Sourcify (default) - shows publicly verified contracts
SOURCIFY_MODE=cloud

# Use local Sourcify - shows contracts verified on your local instance
SOURCIFY_MODE=local
```

After changing this value, recreate the Otterscan container:

```bash
docker compose -f docker-compose.fork.yml up -d otterscan
```

or

```bash
docker compose -f docker-compose.non-interactive.yml up -d otterscan
```

> **Note**: A simple `docker compose restart` won't work because it doesn't re-read `.env` - you need to recreate the container.

### Verifying Contracts

You can verify contracts on the local Sourcify instance using:

1. **Sourcify API**: POST to `http://localhost:5555/verify` with your contract address, chain ID, and source files
2. **Foundry**: Use `forge verify-contract` with `--verifier sourcify --verifier-url http://localhost:5555`

After verification, view the contract source in Otterscan at `http://localhost:8003/address/<contract_address>`.
60 changes: 60 additions & 0 deletions playground/docker-compose.fork.yml
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,65 @@ services:
ports:
- 8000:80

# Sourcify - Contract verification service
sourcify-db:
image: postgres:16
restart: always
environment:
- POSTGRES_USER=sourcify
- POSTGRES_PASSWORD=sourcify
- POSTGRES_DB=sourcify
volumes:
- sourcify-postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U sourcify"]
interval: 5s
timeout: 5s
retries: 5

sourcify:
build:
context: .
dockerfile: Dockerfile.sourcify
restart: always
depends_on:
sourcify-db:
condition: service_healthy
environment:
- SOURCIFY_POSTGRES_HOST=sourcify-db
- SOURCIFY_POSTGRES_PORT=5432
- SOURCIFY_POSTGRES_USER=sourcify
- SOURCIFY_POSTGRES_PASSWORD=sourcify
- SOURCIFY_POSTGRES_DB=sourcify
- NODE_ENV=development
volumes:
- ./sourcify-chains.json:/sourcify/services/server/dist/sourcify-chains.json
ports:
- 5555:5555
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5555/health"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s

otterscan:
build:
context: .
dockerfile: Dockerfile.otterscan
restart: always
environment:
- ERIGON_URL=http://127.0.0.1:8545
- SOURCIFY_MODE=${SOURCIFY_MODE:-cloud}
- LOCAL_SOURCIFY_URL=http://sourcify:5555
ports:
- 8003:80
depends_on:
chain:
condition: service_healthy
sourcify:
condition: service_healthy

explorer:
build:
context: .
Expand Down Expand Up @@ -253,3 +312,4 @@ services:

volumes:
postgres:
sourcify-postgres:
62 changes: 61 additions & 1 deletion playground/docker-compose.non-interactive.yml
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,66 @@ services:
ports:
- 8000:80

# Sourcify - Contract verification service
sourcify-db:
image: postgres:16
restart: always
environment:
- POSTGRES_USER=sourcify
- POSTGRES_PASSWORD=sourcify
- POSTGRES_DB=sourcify
volumes:
- sourcify-postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U sourcify"]
interval: 5s
timeout: 5s
retries: 5

sourcify:
build:
context: .
dockerfile: Dockerfile.sourcify
restart: always
depends_on:
sourcify-db:
condition: service_healthy
environment:
- SOURCIFY_POSTGRES_HOST=sourcify-db
- SOURCIFY_POSTGRES_PORT=5432
- SOURCIFY_POSTGRES_USER=sourcify
- SOURCIFY_POSTGRES_PASSWORD=sourcify
- SOURCIFY_POSTGRES_DB=sourcify
- NODE_ENV=development
volumes:
- ./sourcify-chains.json:/sourcify/services/server/dist/sourcify-chains.json
ports:
- 5555:5555
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5555/health"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s

# Otterscan - Local blockchain block explorer for Anvil
otterscan:
build:
context: .
dockerfile: Dockerfile.otterscan
restart: always
environment:
- ERIGON_URL=http://127.0.0.1:8545
- SOURCIFY_MODE=${SOURCIFY_MODE:-cloud}
- LOCAL_SOURCIFY_URL=http://sourcify:5555
ports:
- 8003:80
depends_on:
chain:
condition: service_healthy
sourcify:
condition: service_healthy

explorer:
build:
context: .
Expand Down Expand Up @@ -231,7 +291,6 @@ services:
volumes:
- ./grafana-prometheus.yml:/etc/grafana/provisioning/datasources/prometheus.yml


prometheus:
image: prom/prometheus:latest
container_name: prometheus
Expand All @@ -243,3 +302,4 @@ services:

volumes:
postgres:
sourcify-postgres:
51 changes: 51 additions & 0 deletions playground/otterscan-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/bin/sh
# Otterscan entrypoint that configures Sourcify based on SOURCIFY_MODE

CONFIG_FILE="/usr/share/nginx/html/config.json"
ERIGON_URL="${ERIGON_URL:-http://127.0.0.1:8545}"
LOCAL_SOURCIFY_URL="${LOCAL_SOURCIFY_URL:-http://localhost:5555}"

echo "=== Otterscan Entrypoint ==="
echo "SOURCIFY_MODE: ${SOURCIFY_MODE}"

case "${SOURCIFY_MODE:-cloud}" in
local)
echo "Using LOCAL Sourcify as primary source"
cat > "$CONFIG_FILE" << EOF
{
"erigonURL": "${ERIGON_URL}",
"sourcify": {
"sources": {
"Local Sourcify": {
"url": "${LOCAL_SOURCIFY_URL}/repository",
"backendFormat": "RepositoryV1"
}
}
}
}
EOF
;;
cloud|*)
echo "Using CLOUD Sourcify as primary source"
cat > "$CONFIG_FILE" << EOF
{
"erigonURL": "${ERIGON_URL}",
"sourcify": {
"sources": {
"Sourcify": {
"url": "https://repo.sourcify.dev",
"backendFormat": "RepositoryV1"
}
}
}
}
EOF
;;
esac

echo "Config written to $CONFIG_FILE:"
cat "$CONFIG_FILE"
echo ""
echo "=== Starting nginx ==="

exec nginx -g "daemon off;"
12 changes: 12 additions & 0 deletions playground/sourcify-chains.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"1": {
"sourcifyName": "Mainnet (Forked)",
"supported": true,
"rpc": ["http://chain:8545"]
},
"31337": {
"sourcifyName": "Anvil Local",
"supported": true,
"rpc": ["http://chain:8545"]
}
}
22 changes: 22 additions & 0 deletions playground/sourcify-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/bash
set -e

echo "=== Sourcify Server Starting ==="

# Wait for database to be ready
echo "Waiting for database..."
until pg_isready -h "$SOURCIFY_POSTGRES_HOST" -p "$SOURCIFY_POSTGRES_PORT" -U "$SOURCIFY_POSTGRES_USER" -d "$SOURCIFY_POSTGRES_DB" > /dev/null 2>&1; do
echo "Database not ready, waiting..."
sleep 2
done
echo "Database is ready!"

# Run migrations
echo "Running database migrations..."
DATABASE_URL="postgres://${SOURCIFY_POSTGRES_USER}:${SOURCIFY_POSTGRES_PASSWORD}@${SOURCIFY_POSTGRES_HOST}:${SOURCIFY_POSTGRES_PORT}/${SOURCIFY_POSTGRES_DB}?sslmode=disable"
dbmate --url "$DATABASE_URL" --migrations-dir /migrations --no-dump-schema up
echo "Migrations complete!"

# Start the server
echo "Starting Sourcify server..."
exec node dist/server/cli.js