From 872d4db49439408ee01bcba71a9c925261c87f95 Mon Sep 17 00:00:00 2001 From: Ignacio Date: Thu, 11 Dec 2025 19:39:16 -0300 Subject: [PATCH 01/10] Added Otterscan to docker-compose files --- playground/docker-compose.fork.yml | 11 +++++++++++ playground/docker-compose.non-interactive.yml | 12 ++++++++++++ 2 files changed, 23 insertions(+) diff --git a/playground/docker-compose.fork.yml b/playground/docker-compose.fork.yml index 17f401cfb2..fde12109a0 100644 --- a/playground/docker-compose.fork.yml +++ b/playground/docker-compose.fork.yml @@ -213,6 +213,17 @@ services: ports: - 8000:80 + otterscan: + image: otterscan/otterscan:latest + restart: always + environment: + - ERIGON_URL=http://localhost:8545 + ports: + - 8003:80 + depends_on: + chain: + condition: service_healthy + explorer: build: context: . diff --git a/playground/docker-compose.non-interactive.yml b/playground/docker-compose.non-interactive.yml index f41847875b..5e4d7f9dec 100644 --- a/playground/docker-compose.non-interactive.yml +++ b/playground/docker-compose.non-interactive.yml @@ -202,6 +202,18 @@ services: ports: - 8000:80 + # Otterscan - Local blockchain block explorer for Anvil + otterscan: + image: otterscan/otterscan:latest + restart: always + environment: + - ERIGON_URL=http://localhost:8545 + ports: + - 8003:80 + depends_on: + chain: + condition: service_healthy + explorer: build: context: . From 3c11ff248dce9d5d94ad8254bc72bc2b34d8ff0b Mon Sep 17 00:00:00 2001 From: Ignacio Date: Mon, 15 Dec 2025 19:04:48 -0300 Subject: [PATCH 02/10] Fix Dockerfile --- playground/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playground/Dockerfile b/playground/Dockerfile index a9439ec7db..08c4e97745 100644 --- a/playground/Dockerfile +++ b/playground/Dockerfile @@ -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 From 6e8acb65895d429eb14972cf40c69f869108f903 Mon Sep 17 00:00:00 2001 From: Augusto Collerone Date: Thu, 18 Dec 2025 16:33:44 -0300 Subject: [PATCH 03/10] Update Otterscan readme details --- playground/README.md | 3 ++- playground/docker-compose.fork.yml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/playground/README.md b/playground/README.md index 44af35a9ae..379d759398 100644 --- a/playground/README.md +++ b/playground/README.md @@ -115,6 +115,7 @@ 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 | **NOTE**: Currently only **FORK** mode is supported. @@ -137,7 +138,7 @@ In this mode, the stack will spin up: - Postgres (with migrations) - Adminer - RPC (forked from `reth` or `erigon` node) -- Otterscan (*not yet implemented*) +- Otterscan - Orderbook - Autopilot - Driver diff --git a/playground/docker-compose.fork.yml b/playground/docker-compose.fork.yml index fde12109a0..5137bc7e29 100644 --- a/playground/docker-compose.fork.yml +++ b/playground/docker-compose.fork.yml @@ -217,7 +217,7 @@ services: image: otterscan/otterscan:latest restart: always environment: - - ERIGON_URL=http://localhost:8545 + - ERIGON_URL=http://127.0.0.1:8545 ports: - 8003:80 depends_on: From 8519ffac13b8e0aed4d8191e5b7d15b6ddc0ce81 Mon Sep 17 00:00:00 2001 From: Augusto Collerone Date: Thu, 18 Dec 2025 18:54:06 -0300 Subject: [PATCH 04/10] Sourcify included in docker-compose --- playground/docker-compose.fork.yml | 49 +++++++++++++++++++ playground/docker-compose.non-interactive.yml | 49 +++++++++++++++++++ playground/sourcify-chains.json | 12 +++++ 3 files changed, 110 insertions(+) create mode 100644 playground/sourcify-chains.json diff --git a/playground/docker-compose.fork.yml b/playground/docker-compose.fork.yml index 5137bc7e29..841235d52f 100644 --- a/playground/docker-compose.fork.yml +++ b/playground/docker-compose.fork.yml @@ -213,11 +213,59 @@ services: ports: - 8000:80 + # Sourcify - Contract verification service + sourcify-db: + image: postgres:15-alpine + 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-migrations: + build: + context: . + dockerfile: Dockerfile.sourcify-migrations + restart: "no" + depends_on: + sourcify-db: + condition: service_healthy + environment: + - DATABASE_URL=postgres://sourcify:sourcify@sourcify-db:5432/sourcify?sslmode=disable + + sourcify: + image: ghcr.io/ethereum/sourcify/server:latest + restart: always + depends_on: + sourcify-db: + condition: service_healthy + sourcify-migrations: + condition: service_completed_successfully + 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:/home/app/services/server/dist/sourcify-chains.json + ports: + - 5555:5555 + otterscan: image: otterscan/otterscan:latest restart: always environment: - ERIGON_URL=http://127.0.0.1:8545 + - OTTERSCAN_CONFIG={"erigonURL":"http://127.0.0.1:8545","sourcify":{"sources":{"Sourcify":{"url":"https://repo.sourcify.dev","backendFormat":"RepositoryV1"},"Local Sourcify":{"url":"http://localhost:5555/repository","backendFormat":"RepositoryV2"}}}} ports: - 8003:80 depends_on: @@ -264,3 +312,4 @@ services: volumes: postgres: + sourcify-postgres: diff --git a/playground/docker-compose.non-interactive.yml b/playground/docker-compose.non-interactive.yml index 5e4d7f9dec..081e802f27 100644 --- a/playground/docker-compose.non-interactive.yml +++ b/playground/docker-compose.non-interactive.yml @@ -202,12 +202,60 @@ services: ports: - 8000:80 + # Sourcify - Contract verification service + sourcify-db: + image: postgres:15-alpine + 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-migrations: + build: + context: . + dockerfile: Dockerfile.sourcify-migrations + restart: "no" + depends_on: + sourcify-db: + condition: service_healthy + environment: + - DATABASE_URL=postgres://sourcify:sourcify@sourcify-db:5432/sourcify?sslmode=disable + + sourcify: + image: ghcr.io/ethereum/sourcify/server:latest + restart: always + depends_on: + sourcify-db: + condition: service_healthy + sourcify-migrations: + condition: service_completed_successfully + 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:/home/app/services/server/dist/sourcify-chains.json + ports: + - 5555:5555 + # Otterscan - Local blockchain block explorer for Anvil otterscan: image: otterscan/otterscan:latest restart: always environment: - ERIGON_URL=http://localhost:8545 + - OTTERSCAN_CONFIG={"erigonURL":"http://localhost:8545","sourcify":{"sources":{"Sourcify":{"url":"https://repo.sourcify.dev","backendFormat":"RepositoryV1"},"Local Sourcify":{"url":"http://localhost:5555/repository","backendFormat":"RepositoryV2"}}}} ports: - 8003:80 depends_on: @@ -255,3 +303,4 @@ services: volumes: postgres: + sourcify-postgres: diff --git a/playground/sourcify-chains.json b/playground/sourcify-chains.json new file mode 100644 index 0000000000..b820af7586 --- /dev/null +++ b/playground/sourcify-chains.json @@ -0,0 +1,12 @@ +{ + "1": { + "sourcifyName": "Mainnet (Forked)", + "supported": true, + "rpc": ["http://chain:8545"] + }, + "31337": { + "sourcifyName": "Anvil Local", + "supported": true, + "rpc": ["http://chain:8545"] + } +} From 98fa7ec63f0b024173c1d80f76db3c33eb499bd8 Mon Sep 17 00:00:00 2001 From: Augusto Collerone Date: Thu, 18 Dec 2025 20:10:48 -0300 Subject: [PATCH 05/10] Sourcify cleanup --- playground/Dockerfile.sourcify | 31 +++++++++++++++++++ playground/docker-compose.fork.yml | 19 +++--------- playground/docker-compose.non-interactive.yml | 19 +++--------- playground/sourcify-entrypoint.sh | 22 +++++++++++++ 4 files changed, 61 insertions(+), 30 deletions(-) create mode 100644 playground/Dockerfile.sourcify create mode 100644 playground/sourcify-entrypoint.sh diff --git a/playground/Dockerfile.sourcify b/playground/Dockerfile.sourcify new file mode 100644 index 0000000000..ce280796c1 --- /dev/null +++ b/playground/Dockerfile.sourcify @@ -0,0 +1,31 @@ +FROM node:22-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 --recurse-submodules https://github.com/ethereum/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"] diff --git a/playground/docker-compose.fork.yml b/playground/docker-compose.fork.yml index 841235d52f..24fffb2749 100644 --- a/playground/docker-compose.fork.yml +++ b/playground/docker-compose.fork.yml @@ -229,25 +229,14 @@ services: timeout: 5s retries: 5 - sourcify-migrations: + sourcify: build: context: . - dockerfile: Dockerfile.sourcify-migrations - restart: "no" - depends_on: - sourcify-db: - condition: service_healthy - environment: - - DATABASE_URL=postgres://sourcify:sourcify@sourcify-db:5432/sourcify?sslmode=disable - - sourcify: - image: ghcr.io/ethereum/sourcify/server:latest + dockerfile: Dockerfile.sourcify restart: always depends_on: sourcify-db: condition: service_healthy - sourcify-migrations: - condition: service_completed_successfully environment: - SOURCIFY_POSTGRES_HOST=sourcify-db - SOURCIFY_POSTGRES_PORT=5432 @@ -256,7 +245,7 @@ services: - SOURCIFY_POSTGRES_DB=sourcify - NODE_ENV=development volumes: - - ./sourcify-chains.json:/home/app/services/server/dist/sourcify-chains.json + - ./sourcify-chains.json:/sourcify/services/server/dist/sourcify-chains.json ports: - 5555:5555 @@ -265,7 +254,7 @@ services: restart: always environment: - ERIGON_URL=http://127.0.0.1:8545 - - OTTERSCAN_CONFIG={"erigonURL":"http://127.0.0.1:8545","sourcify":{"sources":{"Sourcify":{"url":"https://repo.sourcify.dev","backendFormat":"RepositoryV1"},"Local Sourcify":{"url":"http://localhost:5555/repository","backendFormat":"RepositoryV2"}}}} + - OTTERSCAN_CONFIG={"erigonURL":"http://127.0.0.1:8545","sourcify":{"sources":{"Local Sourcify":{"url":"http://localhost:5555/repository","backendFormat":"RepositoryV1"},"Sourcify":{"url":"https://repo.sourcify.dev","backendFormat":"RepositoryV1"}}}} ports: - 8003:80 depends_on: diff --git a/playground/docker-compose.non-interactive.yml b/playground/docker-compose.non-interactive.yml index 081e802f27..98a9c7e5d9 100644 --- a/playground/docker-compose.non-interactive.yml +++ b/playground/docker-compose.non-interactive.yml @@ -218,25 +218,14 @@ services: timeout: 5s retries: 5 - sourcify-migrations: + sourcify: build: context: . - dockerfile: Dockerfile.sourcify-migrations - restart: "no" - depends_on: - sourcify-db: - condition: service_healthy - environment: - - DATABASE_URL=postgres://sourcify:sourcify@sourcify-db:5432/sourcify?sslmode=disable - - sourcify: - image: ghcr.io/ethereum/sourcify/server:latest + dockerfile: Dockerfile.sourcify restart: always depends_on: sourcify-db: condition: service_healthy - sourcify-migrations: - condition: service_completed_successfully environment: - SOURCIFY_POSTGRES_HOST=sourcify-db - SOURCIFY_POSTGRES_PORT=5432 @@ -245,7 +234,7 @@ services: - SOURCIFY_POSTGRES_DB=sourcify - NODE_ENV=development volumes: - - ./sourcify-chains.json:/home/app/services/server/dist/sourcify-chains.json + - ./sourcify-chains.json:/sourcify/services/server/dist/sourcify-chains.json ports: - 5555:5555 @@ -255,7 +244,7 @@ services: restart: always environment: - ERIGON_URL=http://localhost:8545 - - OTTERSCAN_CONFIG={"erigonURL":"http://localhost:8545","sourcify":{"sources":{"Sourcify":{"url":"https://repo.sourcify.dev","backendFormat":"RepositoryV1"},"Local Sourcify":{"url":"http://localhost:5555/repository","backendFormat":"RepositoryV2"}}}} + - OTTERSCAN_CONFIG={"erigonURL":"http://localhost:8545","sourcify":{"sources":{"Sourcify":{"url":"https://repo.sourcify.dev","backendFormat":"RepositoryV1"},"Local Sourcify":{"url":"http://localhost:5555/repository","backendFormat":"RepositoryV1"}}}} ports: - 8003:80 depends_on: diff --git a/playground/sourcify-entrypoint.sh b/playground/sourcify-entrypoint.sh new file mode 100644 index 0000000000..6ccada206c --- /dev/null +++ b/playground/sourcify-entrypoint.sh @@ -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 From ff75c1ff1df28718ec5a059feed6b0d8985e3969 Mon Sep 17 00:00:00 2001 From: Augusto Collerone Date: Thu, 18 Dec 2025 20:17:46 -0300 Subject: [PATCH 06/10] Update docker-compose.fork.yml --- playground/docker-compose.fork.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playground/docker-compose.fork.yml b/playground/docker-compose.fork.yml index 24fffb2749..e0069208ad 100644 --- a/playground/docker-compose.fork.yml +++ b/playground/docker-compose.fork.yml @@ -254,7 +254,7 @@ services: restart: always environment: - ERIGON_URL=http://127.0.0.1:8545 - - OTTERSCAN_CONFIG={"erigonURL":"http://127.0.0.1:8545","sourcify":{"sources":{"Local Sourcify":{"url":"http://localhost:5555/repository","backendFormat":"RepositoryV1"},"Sourcify":{"url":"https://repo.sourcify.dev","backendFormat":"RepositoryV1"}}}} + - OTTERSCAN_CONFIG={"erigonURL":"http://127.0.0.1:8545","sourcify":{"sources":{"Sourcify":{"url":"https://repo.sourcify.dev","backendFormat":"RepositoryV1"},"Local Sourcify":{"url":"http://localhost:5555/repository","backendFormat":"RepositoryV1"}}}} ports: - 8003:80 depends_on: From f7e8ff5131944c83dc200d83123fd666c25eacd9 Mon Sep 17 00:00:00 2001 From: Augusto Collerone Date: Fri, 19 Dec 2025 18:47:31 -0300 Subject: [PATCH 07/10] Sourcify env variable config --- playground/.env.example | 5 ++ playground/Dockerfile.otterscan | 6 +++ playground/docker-compose.fork.yml | 6 ++- playground/docker-compose.non-interactive.yml | 8 +-- playground/otterscan-entrypoint.sh | 50 +++++++++++++++++++ 5 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 playground/Dockerfile.otterscan create mode 100755 playground/otterscan-entrypoint.sh diff --git a/playground/.env.example b/playground/.env.example index deb4362cd1..bb1dae5c47 100644 --- a/playground/.env.example +++ b/playground/.env.example @@ -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 diff --git a/playground/Dockerfile.otterscan b/playground/Dockerfile.otterscan new file mode 100644 index 0000000000..e850887ee8 --- /dev/null +++ b/playground/Dockerfile.otterscan @@ -0,0 +1,6 @@ +FROM otterscan/otterscan:latest + +COPY otterscan-entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/playground/docker-compose.fork.yml b/playground/docker-compose.fork.yml index e0069208ad..a4a3423840 100644 --- a/playground/docker-compose.fork.yml +++ b/playground/docker-compose.fork.yml @@ -250,11 +250,13 @@ services: - 5555:5555 otterscan: - image: otterscan/otterscan:latest + build: + context: . + dockerfile: Dockerfile.otterscan restart: always environment: - ERIGON_URL=http://127.0.0.1:8545 - - OTTERSCAN_CONFIG={"erigonURL":"http://127.0.0.1:8545","sourcify":{"sources":{"Sourcify":{"url":"https://repo.sourcify.dev","backendFormat":"RepositoryV1"},"Local Sourcify":{"url":"http://localhost:5555/repository","backendFormat":"RepositoryV1"}}}} + - SOURCIFY_MODE=${SOURCIFY_MODE:-cloud} ports: - 8003:80 depends_on: diff --git a/playground/docker-compose.non-interactive.yml b/playground/docker-compose.non-interactive.yml index 98a9c7e5d9..7598e577b1 100644 --- a/playground/docker-compose.non-interactive.yml +++ b/playground/docker-compose.non-interactive.yml @@ -240,11 +240,13 @@ services: # Otterscan - Local blockchain block explorer for Anvil otterscan: - image: otterscan/otterscan:latest + build: + context: . + dockerfile: Dockerfile.otterscan restart: always environment: - - ERIGON_URL=http://localhost:8545 - - OTTERSCAN_CONFIG={"erigonURL":"http://localhost:8545","sourcify":{"sources":{"Sourcify":{"url":"https://repo.sourcify.dev","backendFormat":"RepositoryV1"},"Local Sourcify":{"url":"http://localhost:5555/repository","backendFormat":"RepositoryV1"}}}} + - ERIGON_URL=http://127.0.0.1:8545 + - SOURCIFY_MODE=${SOURCIFY_MODE:-cloud} ports: - 8003:80 depends_on: diff --git a/playground/otterscan-entrypoint.sh b/playground/otterscan-entrypoint.sh new file mode 100755 index 0000000000..81726c79ab --- /dev/null +++ b/playground/otterscan-entrypoint.sh @@ -0,0 +1,50 @@ +#!/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}" + +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": "http://localhost:5555/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;" From 0660cb86574f400d92c3f7927e66b5f5511c0f76 Mon Sep 17 00:00:00 2001 From: Augusto Collerone Date: Fri, 19 Dec 2025 18:54:09 -0300 Subject: [PATCH 08/10] Sourcify local url param --- playground/docker-compose.fork.yml | 11 ++++++++++- playground/docker-compose.non-interactive.yml | 10 +++++++++- playground/otterscan-entrypoint.sh | 3 ++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/playground/docker-compose.fork.yml b/playground/docker-compose.fork.yml index a4a3423840..5d5869df2f 100644 --- a/playground/docker-compose.fork.yml +++ b/playground/docker-compose.fork.yml @@ -248,6 +248,12 @@ services: - ./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: @@ -257,12 +263,15 @@ services: 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: . diff --git a/playground/docker-compose.non-interactive.yml b/playground/docker-compose.non-interactive.yml index 7598e577b1..fbd5b15d8b 100644 --- a/playground/docker-compose.non-interactive.yml +++ b/playground/docker-compose.non-interactive.yml @@ -237,6 +237,12 @@ services: - ./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: @@ -247,11 +253,14 @@ services: 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: @@ -282,7 +291,6 @@ services: volumes: - ./grafana-prometheus.yml:/etc/grafana/provisioning/datasources/prometheus.yml - prometheus: image: prom/prometheus:latest container_name: prometheus diff --git a/playground/otterscan-entrypoint.sh b/playground/otterscan-entrypoint.sh index 81726c79ab..6af791a8bd 100755 --- a/playground/otterscan-entrypoint.sh +++ b/playground/otterscan-entrypoint.sh @@ -3,6 +3,7 @@ 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}" @@ -16,7 +17,7 @@ case "${SOURCIFY_MODE:-cloud}" in "sourcify": { "sources": { "Local Sourcify": { - "url": "http://localhost:5555/repository", + "url": "${LOCAL_SOURCIFY_URL}/repository", "backendFormat": "RepositoryV1" } } From f92810ac9f72277a1a032e20641ef1abf4106611 Mon Sep 17 00:00:00 2001 From: Augusto Collerone Date: Fri, 19 Dec 2025 19:01:43 -0300 Subject: [PATCH 09/10] Update README.md --- playground/README.md | 47 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/playground/README.md b/playground/README.md index 379d759398..497d625cbd 100644 --- a/playground/README.md +++ b/playground/README.md @@ -116,6 +116,8 @@ await window.ethereum.request({ | 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. @@ -139,6 +141,7 @@ In this mode, the stack will spin up: - Adminer - RPC (forked from `reth` or `erigon` node) - Otterscan +- Sourcify (contract verification) - Orderbook - Autopilot - Driver @@ -151,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/`. From a62d78ecc8c86c037654d5eab6a9b94b2128c9b2 Mon Sep 17 00:00:00 2001 From: Augusto Collerone Date: Wed, 7 Jan 2026 10:29:00 -0300 Subject: [PATCH 10/10] Address PR review feedback - Fix heredoc EOF quoting to enable variable expansion in otterscan-entrypoint.sh - Update Node.js from v22 to v24 (current LTS) in Dockerfile.sourcify - Update Sourcify repo to argotorg/sourcify with explicit master branch - Align sourcify-db postgres version to 16 (matching main db service) --- playground/Dockerfile.sourcify | 4 ++-- playground/docker-compose.fork.yml | 2 +- playground/docker-compose.non-interactive.yml | 2 +- playground/otterscan-entrypoint.sh | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/playground/Dockerfile.sourcify b/playground/Dockerfile.sourcify index ce280796c1..b74107377f 100644 --- a/playground/Dockerfile.sourcify +++ b/playground/Dockerfile.sourcify @@ -1,4 +1,4 @@ -FROM node:22-bookworm-slim +FROM node:24-bookworm-slim # Install dependencies RUN apt-get update && apt-get install -y git curl postgresql-client && \ @@ -7,7 +7,7 @@ RUN apt-get update && apt-get install -y git curl postgresql-client && \ apt-get clean && rm -rf /var/lib/apt/lists/* # Clone Sourcify with submodules -RUN git clone --depth 1 --recurse-submodules https://github.com/ethereum/sourcify.git /sourcify +RUN git clone --depth 1 --branch master --recurse-submodules https://github.com/argotorg/sourcify.git /sourcify WORKDIR /sourcify diff --git a/playground/docker-compose.fork.yml b/playground/docker-compose.fork.yml index 5d5869df2f..d3c3274bf4 100644 --- a/playground/docker-compose.fork.yml +++ b/playground/docker-compose.fork.yml @@ -215,7 +215,7 @@ services: # Sourcify - Contract verification service sourcify-db: - image: postgres:15-alpine + image: postgres:16 restart: always environment: - POSTGRES_USER=sourcify diff --git a/playground/docker-compose.non-interactive.yml b/playground/docker-compose.non-interactive.yml index fbd5b15d8b..f56f605072 100644 --- a/playground/docker-compose.non-interactive.yml +++ b/playground/docker-compose.non-interactive.yml @@ -204,7 +204,7 @@ services: # Sourcify - Contract verification service sourcify-db: - image: postgres:15-alpine + image: postgres:16 restart: always environment: - POSTGRES_USER=sourcify diff --git a/playground/otterscan-entrypoint.sh b/playground/otterscan-entrypoint.sh index 6af791a8bd..b044c7aeb4 100755 --- a/playground/otterscan-entrypoint.sh +++ b/playground/otterscan-entrypoint.sh @@ -11,7 +11,7 @@ echo "SOURCIFY_MODE: ${SOURCIFY_MODE}" case "${SOURCIFY_MODE:-cloud}" in local) echo "Using LOCAL Sourcify as primary source" - cat > "$CONFIG_FILE" << 'EOF' + cat > "$CONFIG_FILE" << EOF { "erigonURL": "${ERIGON_URL}", "sourcify": { @@ -27,7 +27,7 @@ EOF ;; cloud|*) echo "Using CLOUD Sourcify as primary source" - cat > "$CONFIG_FILE" << 'EOF' + cat > "$CONFIG_FILE" << EOF { "erigonURL": "${ERIGON_URL}", "sourcify": {