Refresh explorer verification runbooks
This commit is contained in:
171
scripts/deployment/ensure-blockscout-smart-contract-verifier-5000.sh
Executable file
171
scripts/deployment/ensure-blockscout-smart-contract-verifier-5000.sh
Executable file
@@ -0,0 +1,171 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Enable the upstream Blockscout smart-contract verifier sidecar on CT 5000 and
|
||||
# wire Blockscout to use it.
|
||||
#
|
||||
# Usage:
|
||||
# bash scripts/deployment/ensure-blockscout-smart-contract-verifier-5000.sh --dry-run
|
||||
# bash scripts/deployment/ensure-blockscout-smart-contract-verifier-5000.sh --apply
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
|
||||
if [[ -f "${PROJECT_ROOT}/scripts/lib/load-project-env.sh" ]]; then
|
||||
# shellcheck source=/dev/null
|
||||
source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh"
|
||||
fi
|
||||
|
||||
HOST="${PROXMOX_HOST_R630_02:-192.168.11.12}"
|
||||
VMID="${BLOCKSCOUT_DB_CT_VMID:-5000}"
|
||||
APPLY=0
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--apply) APPLY=1; shift ;;
|
||||
--dry-run) APPLY=0; shift ;;
|
||||
*)
|
||||
echo "Unknown argument: $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
read -r -d '' REMOTE_SCRIPT <<'EOF_REMOTE' || true
|
||||
set -euo pipefail
|
||||
cd /opt/blockscout
|
||||
|
||||
stamp="$(date +%Y%m%d_%H%M%S)"
|
||||
cp docker-compose.yml "docker-compose.yml.bak.${stamp}.pre_verifier"
|
||||
|
||||
cat > smart-contract-verifier.env <<'EOF_VERIFIER'
|
||||
SMART_CONTRACT_VERIFIER__SERVER__HTTP__ENABLED=true
|
||||
SMART_CONTRACT_VERIFIER__SERVER__HTTP__ADDR=0.0.0.0:8050
|
||||
SMART_CONTRACT_VERIFIER__SERVER__HTTP__MAX_BODY_SIZE=8388608
|
||||
SMART_CONTRACT_VERIFIER__SERVER__GRPC__ENABLED=false
|
||||
SMART_CONTRACT_VERIFIER__SERVER__GRPC__ADDR=0.0.0.0:8051
|
||||
SMART_CONTRACT_VERIFIER__SOLIDITY__ENABLED=true
|
||||
SMART_CONTRACT_VERIFIER__SOLIDITY__COMPILERS_DIR=/tmp/solidity-compilers
|
||||
SMART_CONTRACT_VERIFIER__SOLIDITY__REFRESH_VERSIONS_SCHEDULE=0 0 * * * * *
|
||||
SMART_CONTRACT_VERIFIER__SOLIDITY__FETCHER__LIST__LIST_URL=https://binaries.soliditylang.org/linux-amd64/list.json
|
||||
SMART_CONTRACT_VERIFIER__VYPER__ENABLED=true
|
||||
SMART_CONTRACT_VERIFIER__VYPER__COMPILERS_DIR=/tmp/vyper-compilers
|
||||
SMART_CONTRACT_VERIFIER__VYPER__REFRESH_VERSIONS_SCHEDULE=0 0 * * * * *
|
||||
SMART_CONTRACT_VERIFIER__VYPER__FETCHER__LIST__LIST_URL=https://raw.githubusercontent.com/blockscout/solc-bin/main/vyper.list.json
|
||||
SMART_CONTRACT_VERIFIER__SOURCIFY__ENABLED=true
|
||||
SMART_CONTRACT_VERIFIER__SOURCIFY__API_URL=https://sourcify.dev/server/
|
||||
SMART_CONTRACT_VERIFIER__SOURCIFY__VERIFICATION_ATTEMPTS=3
|
||||
SMART_CONTRACT_VERIFIER__SOURCIFY__REQUEST_TIMEOUT=10
|
||||
SMART_CONTRACT_VERIFIER__METRICS__ENABLED=false
|
||||
SMART_CONTRACT_VERIFIER__JAEGER__ENABLED=false
|
||||
EOF_VERIFIER
|
||||
|
||||
cat > docker-compose.yml <<'EOF_COMPOSE'
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:15-alpine
|
||||
container_name: blockscout-postgres
|
||||
environment:
|
||||
POSTGRES_USER: blockscout
|
||||
POSTGRES_PASSWORD: blockscout
|
||||
POSTGRES_DB: blockscout
|
||||
volumes:
|
||||
- postgres-data:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- blockscout-network
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U blockscout"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
smart-contract-verifier:
|
||||
image: ghcr.io/blockscout/smart-contract-verifier:latest
|
||||
container_name: smart-contract-verifier
|
||||
env_file:
|
||||
- ./smart-contract-verifier.env
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- blockscout-network
|
||||
|
||||
blockscout:
|
||||
image: blockscout/blockscout:latest
|
||||
container_name: blockscout
|
||||
command: bin/blockscout start
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
smart-contract-verifier:
|
||||
condition: service_started
|
||||
environment:
|
||||
- DISABLE_WEBAPP=false
|
||||
- DISABLE_INDEXER=false
|
||||
- INDEXER_DISABLE_PENDING_TRANSACTIONS_FETCHER=true
|
||||
- DATABASE_URL=postgresql://blockscout:blockscout@postgres:5432/blockscout?sslmode=disable
|
||||
- ETHEREUM_JSONRPC_HTTP_URL=http://192.168.11.221:8545
|
||||
- ETHEREUM_JSONRPC_WS_URL=ws://192.168.11.221:8546
|
||||
- ETHEREUM_JSONRPC_TRACE_URL=http://192.168.11.221:8545
|
||||
- ETHEREUM_JSONRPC_VARIANT=besu
|
||||
- CHAIN_ID=138
|
||||
- COIN=ETH
|
||||
- BLOCKSCOUT_HOST=explorer.d-bis.org
|
||||
- BLOCKSCOUT_PROTOCOL=https
|
||||
- SECRET_KEY_BASE=73159c7d10b9a5a75ddf10710773078c078bf02124d35b72fa2a841b30b4f88c7c43e5caaf7f9f7f87d16dd66e7870931ae11039c428d1dedae187af762531fa
|
||||
- POOL_SIZE=50
|
||||
- POOL_SIZE_API=50
|
||||
- DATABASE_QUEUE_TARGET=5s
|
||||
- ECTO_USE_SSL=false
|
||||
- MICROSERVICE_SC_VERIFIER_ENABLED=true
|
||||
- MICROSERVICE_SC_VERIFIER_TYPE=sc_verifier
|
||||
- MICROSERVICE_SC_VERIFIER_URL=http://smart-contract-verifier:8050/
|
||||
ports:
|
||||
- "4000:4000"
|
||||
volumes:
|
||||
- blockscout-data:/app/apps/explorer/priv/static
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- blockscout-network
|
||||
|
||||
volumes:
|
||||
postgres-data:
|
||||
blockscout-data:
|
||||
|
||||
networks:
|
||||
blockscout-network:
|
||||
driver: bridge
|
||||
EOF_COMPOSE
|
||||
|
||||
docker pull ghcr.io/blockscout/smart-contract-verifier:latest
|
||||
docker rm -f blockscout 2>/dev/null || true
|
||||
docker rm -f smart-contract-verifier 2>/dev/null || true
|
||||
# Older docker-compose v1 can leave an orphaned auto-generated verifier container
|
||||
# that breaks recreation with a `ContainerConfig` KeyError. Clear it first.
|
||||
docker ps -a --format '{{.Names}}' | grep -E 'smart-contract-verifier$' | xargs -r docker rm -f
|
||||
|
||||
if command -v docker-compose >/dev/null 2>&1; then
|
||||
docker-compose -f docker-compose.yml up -d
|
||||
else
|
||||
docker compose -f docker-compose.yml up -d
|
||||
fi
|
||||
|
||||
sleep 10
|
||||
docker ps --format "table {{.Names}}\t{{.Status}}"
|
||||
curl -fsS http://127.0.0.1:4000/api/v2/smart-contracts/verification/config >/dev/null
|
||||
EOF_REMOTE
|
||||
|
||||
echo "Blockscout smart-contract verifier enablement"
|
||||
echo "Host: ${HOST}"
|
||||
echo "VMID: ${VMID}"
|
||||
echo
|
||||
|
||||
if (( APPLY == 0 )); then
|
||||
echo "[dry-run] Would patch /opt/blockscout/docker-compose.yml on CT ${VMID}, add smart-contract-verifier, and restart Blockscout."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ssh root@"${HOST}" "pct exec ${VMID} -- bash -lc $(printf '%q' "${REMOTE_SCRIPT}")"
|
||||
echo
|
||||
echo "[ok] Blockscout verifier sidecar enabled on CT ${VMID}."
|
||||
224
scripts/verify/verify-chain138-native-v2-blockscout.sh
Executable file
224
scripts/verify/verify-chain138-native-v2-blockscout.sh
Executable file
@@ -0,0 +1,224 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Verify the Chain 138 native Uniswap v2 and SushiSwap deployments on Blockscout.
|
||||
#
|
||||
# Usage:
|
||||
# bash scripts/verify/verify-chain138-native-v2-blockscout.sh
|
||||
# bash scripts/verify/verify-chain138-native-v2-blockscout.sh --status-only
|
||||
# bash scripts/verify/verify-chain138-native-v2-blockscout.sh --only UniswapV2Factory,SushiSwapRouter
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
SMOM_ROOT="${PROJECT_ROOT}/smom-dbis-138"
|
||||
|
||||
if [[ -f "${PROJECT_ROOT}/scripts/lib/load-project-env.sh" ]]; then
|
||||
# shellcheck source=/dev/null
|
||||
source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh"
|
||||
fi
|
||||
|
||||
command -v forge >/dev/null 2>&1 || { echo "ERROR: forge not found"; exit 1; }
|
||||
command -v node >/dev/null 2>&1 || { echo "ERROR: node not found"; exit 1; }
|
||||
command -v cast >/dev/null 2>&1 || { echo "ERROR: cast not found"; exit 1; }
|
||||
command -v jq >/dev/null 2>&1 || { echo "ERROR: jq not found"; exit 1; }
|
||||
command -v curl >/dev/null 2>&1 || { echo "ERROR: curl not found"; exit 1; }
|
||||
|
||||
RPC_URL="${RPC_URL_138:-${CHAIN138_RPC_URL:-http://192.168.11.211:8545}}"
|
||||
BLOCKSCOUT_URL="${CHAIN138_BLOCKSCOUT_INTERNAL_URL:-http://${IP_BLOCKSCOUT:-192.168.11.140}:4000}"
|
||||
BLOCKSCOUT_API_BASE="${CHAIN138_BLOCKSCOUT_API_BASE:-${BLOCKSCOUT_URL}/api/v2}"
|
||||
BLOCKSCOUT_PUBLIC_API_BASE="${CHAIN138_BLOCKSCOUT_PUBLIC_API_BASE:-https://explorer.d-bis.org/api/v2}"
|
||||
VERIFIER_PORT="${FORGE_VERIFIER_PROXY_PORT:-3080}"
|
||||
FORGE_VERIFIER_URL="${FORGE_VERIFIER_URL:-http://127.0.0.1:${VERIFIER_PORT}/api}"
|
||||
|
||||
UNISWAP_JSON="${SMOM_ROOT}/deployments/chain138/uniswap-v2-native.json"
|
||||
SUSHI_JSON="${SMOM_ROOT}/deployments/chain138/sushiswap-native.json"
|
||||
|
||||
ONLY_LIST=""
|
||||
STATUS_ONLY=0
|
||||
PROXY_PID=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--only) ONLY_LIST="${2:-}"; shift 2 ;;
|
||||
--status-only) STATUS_ONLY=1; shift ;;
|
||||
*)
|
||||
echo "Unknown argument: $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
cleanup_proxy() {
|
||||
[[ -n "${PROXY_PID:-}" ]] && kill "${PROXY_PID}" 2>/dev/null || true
|
||||
}
|
||||
trap cleanup_proxy EXIT
|
||||
|
||||
should_handle() {
|
||||
local name="$1"
|
||||
[[ -n "${ONLY_LIST}" ]] && [[ ",${ONLY_LIST}," != *",${name},"* ]] && return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
log() { printf '%s\n' "$*"; }
|
||||
ok() { printf '[ok] %s\n' "$*"; }
|
||||
warn() { printf '[warn] %s\n' "$*" >&2; }
|
||||
fail() { printf '[fail] %s\n' "$*" >&2; exit 1; }
|
||||
|
||||
proxy_listening() {
|
||||
if command -v nc >/dev/null 2>&1; then
|
||||
nc -z -w 2 127.0.0.1 "${VERIFIER_PORT}" 2>/dev/null
|
||||
else
|
||||
timeout 2 bash -c "echo >/dev/tcp/127.0.0.1/${VERIFIER_PORT}" 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
start_proxy_if_needed() {
|
||||
if proxy_listening; then
|
||||
ok "Forge verification proxy already listening on ${VERIFIER_PORT}."
|
||||
return 0
|
||||
fi
|
||||
|
||||
log "Starting forge verification proxy on ${VERIFIER_PORT} -> ${BLOCKSCOUT_URL}"
|
||||
PORT="${VERIFIER_PORT}" BLOCKSCOUT_URL="${BLOCKSCOUT_URL}" node "${PROJECT_ROOT}/forge-verification-proxy/server.js" >/tmp/chain138-native-v2-blockscout-proxy.log 2>&1 &
|
||||
PROXY_PID=$!
|
||||
sleep 2
|
||||
proxy_listening || fail "Forge verification proxy failed to start. See /tmp/chain138-native-v2-blockscout-proxy.log"
|
||||
}
|
||||
|
||||
has_contract_bytecode() {
|
||||
local addr="$1"
|
||||
local code
|
||||
code="$(cast code "${addr}" --rpc-url "${RPC_URL}" 2>/dev/null | tr -d '\n\r \t' | tr '[:upper:]' '[:lower:]')" || true
|
||||
[[ -n "${code}" && "${code}" != "0x" && "${code}" != "0x0" ]]
|
||||
}
|
||||
|
||||
verification_status_json() {
|
||||
local addr="$1"
|
||||
local raw
|
||||
local base
|
||||
for base in "${BLOCKSCOUT_API_BASE}" "${BLOCKSCOUT_PUBLIC_API_BASE}"; do
|
||||
raw="$(curl --max-time 20 -fsS "${base}/smart-contracts/${addr}" 2>/dev/null || true)"
|
||||
if [[ -n "${raw}" ]] && jq -e 'type == "object"' >/dev/null 2>&1 <<<"${raw}"; then
|
||||
printf '%s' "${raw}"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
is_verified() {
|
||||
local addr="$1"
|
||||
local expected_name="$2"
|
||||
local json name compiler
|
||||
json="$(verification_status_json "${addr}")" || return 1
|
||||
name="$(jq -r '.name // empty' <<<"${json}")"
|
||||
compiler="$(jq -r '.compiler_version // empty' <<<"${json}")"
|
||||
[[ -n "${name}" && -n "${compiler}" && "${name}" == "${expected_name}" ]]
|
||||
}
|
||||
|
||||
submit_verification() {
|
||||
local label="$1"
|
||||
local addr="$2"
|
||||
local path="$3"
|
||||
local expected_name="$4"
|
||||
local constructor_sig="$5"
|
||||
local compiler_version="$6"
|
||||
local force_flag="${7:-0}"
|
||||
shift 6
|
||||
local constructor_args=("$@")
|
||||
|
||||
start_proxy_if_needed
|
||||
has_contract_bytecode "${addr}" || fail "${label} has no bytecode at ${addr}"
|
||||
|
||||
if is_verified "${addr}" "${expected_name}"; then
|
||||
ok "${label} already verified on Blockscout."
|
||||
return 0
|
||||
fi
|
||||
|
||||
local cmd=(forge verify-contract "${addr}" "${path}" --chain-id 138 --verifier blockscout --verifier-url "${FORGE_VERIFIER_URL}" --rpc-url "${RPC_URL}" --flatten)
|
||||
[[ -n "${compiler_version}" ]] && cmd+=(--compiler-version "${compiler_version}")
|
||||
if [[ "${force_flag}" == "1" ]]; then
|
||||
cmd+=(--force)
|
||||
fi
|
||||
if [[ -n "${constructor_sig}" ]]; then
|
||||
local encoded
|
||||
encoded="$(cast abi-encode "${constructor_sig}" "${constructor_args[@]:1}")"
|
||||
cmd+=(--constructor-args "${encoded}")
|
||||
fi
|
||||
|
||||
log "Submitting Blockscout verification for ${label} (${addr})"
|
||||
if (cd "${SMOM_ROOT}" && "${cmd[@]}" 2>&1); then
|
||||
ok "${label} verification submission accepted."
|
||||
else
|
||||
warn "${label} verification submission did not complete cleanly. Check Blockscout manually."
|
||||
fi
|
||||
}
|
||||
|
||||
[[ -f "${UNISWAP_JSON}" ]] || fail "Missing deployment artifact ${UNISWAP_JSON}"
|
||||
[[ -f "${SUSHI_JSON}" ]] || fail "Missing deployment artifact ${SUSHI_JSON}"
|
||||
|
||||
UNISWAP_FACTORY="$(jq -r '.factory' "${UNISWAP_JSON}")"
|
||||
UNISWAP_ROUTER="$(jq -r '.router' "${UNISWAP_JSON}")"
|
||||
UNISWAP_WETH="$(jq -r '.weth' "${UNISWAP_JSON}")"
|
||||
UNISWAP_DEPLOYER="$(jq -r '.deployer' "${UNISWAP_JSON}")"
|
||||
|
||||
SUSHI_FACTORY="$(jq -r '.factory' "${SUSHI_JSON}")"
|
||||
SUSHI_ROUTER="$(jq -r '.router' "${SUSHI_JSON}")"
|
||||
SUSHI_WETH="$(jq -r '.weth' "${SUSHI_JSON}")"
|
||||
SUSHI_FEE_TO_SETTER="$(jq -r '.feeToSetter // .deployer' "${SUSHI_JSON}")"
|
||||
|
||||
log "Chain 138 native V2 Blockscout verification"
|
||||
log "RPC: ${RPC_URL}"
|
||||
log "Explorer API: ${BLOCKSCOUT_API_BASE}"
|
||||
log
|
||||
|
||||
if (( STATUS_ONLY )); then
|
||||
should_handle "UniswapV2Factory" && { is_verified "${UNISWAP_FACTORY}" "UniswapV2Factory" && ok "UniswapV2Factory already verified on Blockscout." || warn "UniswapV2Factory not yet verified on Blockscout."; }
|
||||
should_handle "UniswapV2Router" && { is_verified "${UNISWAP_ROUTER}" "UniswapV2Router02" && ok "UniswapV2Router already verified on Blockscout." || warn "UniswapV2Router not yet verified on Blockscout."; }
|
||||
should_handle "SushiSwapFactory" && { is_verified "${SUSHI_FACTORY}" "UniswapV2Factory" && ok "SushiSwapFactory already verified on Blockscout." || warn "SushiSwapFactory not yet verified on Blockscout."; }
|
||||
should_handle "SushiSwapRouter" && { is_verified "${SUSHI_ROUTER}" "UniswapV2Router02" && ok "SushiSwapRouter already verified on Blockscout." || warn "SushiSwapRouter not yet verified on Blockscout."; }
|
||||
exit 0
|
||||
fi
|
||||
|
||||
should_handle "UniswapV2Factory" && submit_verification \
|
||||
"UniswapV2Factory" \
|
||||
"${UNISWAP_FACTORY}" \
|
||||
"contracts/vendor/uniswap-v2-core/UniswapV2Factory.sol:UniswapV2Factory" \
|
||||
"UniswapV2Factory" \
|
||||
"constructor(address)" \
|
||||
"v0.5.16+commit.9c3226ce" \
|
||||
"1" \
|
||||
"${UNISWAP_DEPLOYER}"
|
||||
|
||||
should_handle "UniswapV2Router" && submit_verification \
|
||||
"UniswapV2Router" \
|
||||
"${UNISWAP_ROUTER}" \
|
||||
"contracts/vendor/uniswap-v2-periphery/UniswapV2Router02.sol:UniswapV2Router02" \
|
||||
"UniswapV2Router02" \
|
||||
"constructor(address,address)" \
|
||||
"v0.6.6+commit.6c089d02" \
|
||||
"1" \
|
||||
"${UNISWAP_FACTORY}" "${UNISWAP_WETH}"
|
||||
|
||||
should_handle "SushiSwapFactory" && submit_verification \
|
||||
"SushiSwapFactory" \
|
||||
"${SUSHI_FACTORY}" \
|
||||
"contracts/vendor/sushiswap-v2/UniswapV2Factory.sol:UniswapV2Factory" \
|
||||
"UniswapV2Factory" \
|
||||
"constructor(address)" \
|
||||
"v0.6.12+commit.27d51765" \
|
||||
"1" \
|
||||
"${SUSHI_FEE_TO_SETTER}"
|
||||
|
||||
should_handle "SushiSwapRouter" && submit_verification \
|
||||
"SushiSwapRouter" \
|
||||
"${SUSHI_ROUTER}" \
|
||||
"contracts/vendor/sushiswap-v2/UniswapV2Router02.sol:UniswapV2Router02" \
|
||||
"UniswapV2Router02" \
|
||||
"constructor(address,address)" \
|
||||
"v0.6.12+commit.27d51765" \
|
||||
"1" \
|
||||
"${SUSHI_FACTORY}" "${SUSHI_WETH}"
|
||||
|
||||
log
|
||||
ok "Chain 138 native V2 verification flow complete."
|
||||
545
scripts/verify/verify-chain138-route-execution-stack-blockscout.sh
Executable file
545
scripts/verify/verify-chain138-route-execution-stack-blockscout.sh
Executable file
@@ -0,0 +1,545 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Verify the deployed Chain 138 route execution stack and pilot venue contracts on Blockscout.
|
||||
#
|
||||
# Usage:
|
||||
# bash scripts/verify/verify-chain138-route-execution-stack-blockscout.sh
|
||||
# bash scripts/verify/verify-chain138-route-execution-stack-blockscout.sh --status-only
|
||||
# bash scripts/verify/verify-chain138-route-execution-stack-blockscout.sh --no-wait
|
||||
# bash scripts/verify/verify-chain138-route-execution-stack-blockscout.sh --only EnhancedSwapRouterV2,Chain138PilotCurve3Pool
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
SMOM_ROOT="${PROJECT_ROOT}/smom-dbis-138"
|
||||
|
||||
if [[ -f "${PROJECT_ROOT}/scripts/lib/load-project-env.sh" ]]; then
|
||||
# shellcheck source=/dev/null
|
||||
source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh"
|
||||
fi
|
||||
|
||||
command -v forge >/dev/null 2>&1 || { echo "ERROR: forge not found"; exit 1; }
|
||||
command -v node >/dev/null 2>&1 || { echo "ERROR: node not found"; exit 1; }
|
||||
command -v cast >/dev/null 2>&1 || { echo "ERROR: cast not found"; exit 1; }
|
||||
command -v jq >/dev/null 2>&1 || { echo "ERROR: jq not found"; exit 1; }
|
||||
command -v curl >/dev/null 2>&1 || { echo "ERROR: curl not found"; exit 1; }
|
||||
|
||||
RPC_URL="${RPC_URL_138:-${CHAIN138_RPC_URL:-http://192.168.11.211:8545}}"
|
||||
BLOCKSCOUT_URL="${CHAIN138_BLOCKSCOUT_INTERNAL_URL:-http://${IP_BLOCKSCOUT:-192.168.11.140}:4000}"
|
||||
BLOCKSCOUT_API_BASE="${CHAIN138_BLOCKSCOUT_API_BASE:-${BLOCKSCOUT_URL}/api/v2}"
|
||||
BLOCKSCOUT_PUBLIC_API_BASE="${CHAIN138_BLOCKSCOUT_PUBLIC_API_BASE:-https://explorer.d-bis.org/api/v2}"
|
||||
VERIFIER_PORT="${FORGE_VERIFIER_PROXY_PORT:-3080}"
|
||||
FORGE_VERIFIER_URL="${FORGE_VERIFIER_URL:-http://127.0.0.1:${VERIFIER_PORT}/api}"
|
||||
ROUTE_STACK_SOLC_VERSION="${ROUTE_STACK_SOLC_VERSION:-v0.8.20+commit.a1b79de6}"
|
||||
ROUTE_STACK_EVM_VERSION="${ROUTE_STACK_EVM_VERSION:-shanghai}"
|
||||
ROUTE_STACK_OPT_RUNS="${ROUTE_STACK_OPT_RUNS:-200}"
|
||||
|
||||
ONLY_LIST=""
|
||||
STATUS_ONLY=0
|
||||
NO_WAIT=0
|
||||
PROXY_PID=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--only) ONLY_LIST="${2:-}"; shift 2 ;;
|
||||
--status-only) STATUS_ONLY=1; shift ;;
|
||||
--no-wait) NO_WAIT=1; shift ;;
|
||||
*)
|
||||
echo "Unknown argument: $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
cleanup_proxy() {
|
||||
[[ -n "${PROXY_PID:-}" ]] && kill "${PROXY_PID}" 2>/dev/null || true
|
||||
}
|
||||
trap cleanup_proxy EXIT
|
||||
|
||||
should_handle() {
|
||||
local name="$1"
|
||||
[[ -n "${ONLY_LIST}" ]] && [[ ",${ONLY_LIST}," != *",${name},"* ]] && return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
log() { printf '%s\n' "$*"; }
|
||||
ok() { printf '[ok] %s\n' "$*"; }
|
||||
warn() { printf '[warn] %s\n' "$*" >&2; }
|
||||
fail() { printf '[fail] %s\n' "$*" >&2; exit 1; }
|
||||
|
||||
proxy_listening() {
|
||||
if command -v nc >/dev/null 2>&1; then
|
||||
nc -z -w 2 127.0.0.1 "${VERIFIER_PORT}" 2>/dev/null
|
||||
else
|
||||
timeout 2 bash -c "echo >/dev/tcp/127.0.0.1/${VERIFIER_PORT}" 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
start_proxy_if_needed() {
|
||||
if proxy_listening; then
|
||||
ok "Forge verification proxy already listening on ${VERIFIER_PORT}."
|
||||
return 0
|
||||
fi
|
||||
|
||||
log "Starting forge verification proxy on ${VERIFIER_PORT} -> ${BLOCKSCOUT_URL}"
|
||||
PORT="${VERIFIER_PORT}" BLOCKSCOUT_URL="${BLOCKSCOUT_URL}" node "${PROJECT_ROOT}/forge-verification-proxy/server.js" >/tmp/chain138-route-execution-blockscout-proxy.log 2>&1 &
|
||||
PROXY_PID=$!
|
||||
sleep 2
|
||||
proxy_listening || fail "Forge verification proxy failed to start. See /tmp/chain138-route-execution-blockscout-proxy.log"
|
||||
}
|
||||
|
||||
has_contract_bytecode() {
|
||||
local addr="$1"
|
||||
local code
|
||||
code="$(cast code "${addr}" --rpc-url "${RPC_URL}" 2>/dev/null | tr -d '\n\r \t' | tr '[:upper:]' '[:lower:]')" || true
|
||||
[[ -n "${code}" && "${code}" != "0x" && "${code}" != "0x0" ]]
|
||||
}
|
||||
|
||||
verification_status_json() {
|
||||
local addr="$1"
|
||||
local raw
|
||||
local base
|
||||
for base in "${BLOCKSCOUT_API_BASE}" "${BLOCKSCOUT_PUBLIC_API_BASE}"; do
|
||||
raw="$(curl --max-time 20 -fsS "${base}/smart-contracts/${addr}" 2>/dev/null || true)"
|
||||
if [[ -n "${raw}" ]] && jq -e 'type == "object"' >/dev/null 2>&1 <<<"${raw}"; then
|
||||
printf '%s' "${raw}"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
is_verified() {
|
||||
local addr="$1"
|
||||
local expected_name="$2"
|
||||
local json name compiler
|
||||
json="$(verification_status_json "${addr}")" || return 1
|
||||
name="$(jq -r '.name // empty' <<<"${json}")"
|
||||
compiler="$(jq -r '.compiler_version // empty' <<<"${json}")"
|
||||
[[ -n "${name}" && -n "${compiler}" && "${name}" == "${expected_name}" ]]
|
||||
}
|
||||
|
||||
submit_verification() {
|
||||
local label="$1"
|
||||
local addr="$2"
|
||||
local path="$3"
|
||||
local expected_name="$4"
|
||||
local constructor_sig="$5"
|
||||
shift 5
|
||||
local constructor_args=("$@")
|
||||
|
||||
start_proxy_if_needed
|
||||
has_contract_bytecode "${addr}" || fail "${label} has no bytecode at ${addr}"
|
||||
|
||||
if is_verified "${addr}" "${expected_name}"; then
|
||||
ok "${label} already verified on Blockscout."
|
||||
return 0
|
||||
fi
|
||||
|
||||
local cmd=(forge verify-contract "${addr}" "${path}" --chain-id 138 --verifier blockscout --verifier-url "${FORGE_VERIFIER_URL}" --rpc-url "${RPC_URL}" --flatten)
|
||||
if [[ -n "${constructor_sig}" ]]; then
|
||||
local encoded
|
||||
encoded="$(cast abi-encode "${constructor_sig}" "${constructor_args[@]}")"
|
||||
cmd+=(--constructor-args "${encoded}")
|
||||
fi
|
||||
|
||||
log "Submitting Blockscout verification for ${label} (${addr})"
|
||||
if (cd "${SMOM_ROOT}" && "${cmd[@]}" 2>&1); then
|
||||
ok "${label} verification submission accepted."
|
||||
else
|
||||
warn "${label} verification submission did not complete cleanly. Check Blockscout manually."
|
||||
fi
|
||||
}
|
||||
|
||||
artifact_dbg_path() {
|
||||
case "$1" in
|
||||
EnhancedSwapRouterV2) printf '%s' "${SMOM_ROOT}/artifacts/contracts/bridge/trustless/EnhancedSwapRouterV2.sol/EnhancedSwapRouterV2.dbg.json" ;;
|
||||
IntentBridgeCoordinatorV2) printf '%s' "${SMOM_ROOT}/artifacts/contracts/bridge/trustless/IntentBridgeCoordinatorV2.sol/IntentBridgeCoordinatorV2.dbg.json" ;;
|
||||
DodoRouteExecutorAdapter) printf '%s' "${SMOM_ROOT}/artifacts/contracts/bridge/trustless/adapters/DodoRouteExecutorAdapter.sol/DodoRouteExecutorAdapter.dbg.json" ;;
|
||||
DodoV3RouteExecutorAdapter) printf '%s' "${SMOM_ROOT}/artifacts/contracts/bridge/trustless/adapters/DodoV3RouteExecutorAdapter.sol/DodoV3RouteExecutorAdapter.dbg.json" ;;
|
||||
UniswapV3RouteExecutorAdapter) printf '%s' "${SMOM_ROOT}/artifacts/contracts/bridge/trustless/adapters/UniswapV3RouteExecutorAdapter.sol/UniswapV3RouteExecutorAdapter.dbg.json" ;;
|
||||
BalancerRouteExecutorAdapter) printf '%s' "${SMOM_ROOT}/artifacts/contracts/bridge/trustless/adapters/BalancerRouteExecutorAdapter.sol/BalancerRouteExecutorAdapter.dbg.json" ;;
|
||||
CurveRouteExecutorAdapter) printf '%s' "${SMOM_ROOT}/artifacts/contracts/bridge/trustless/adapters/CurveRouteExecutorAdapter.sol/CurveRouteExecutorAdapter.dbg.json" ;;
|
||||
OneInchRouteExecutorAdapter) printf '%s' "${SMOM_ROOT}/artifacts/contracts/bridge/trustless/adapters/OneInchRouteExecutorAdapter.sol/OneInchRouteExecutorAdapter.dbg.json" ;;
|
||||
Chain138PilotUniswapV3Router) printf '%s' "${SMOM_ROOT}/artifacts/contracts/bridge/trustless/pilot/Chain138PilotDexVenues.sol/Chain138PilotUniswapV3Router.dbg.json" ;;
|
||||
Chain138PilotBalancerVault) printf '%s' "${SMOM_ROOT}/artifacts/contracts/bridge/trustless/pilot/Chain138PilotDexVenues.sol/Chain138PilotBalancerVault.dbg.json" ;;
|
||||
Chain138PilotCurve3Pool) printf '%s' "${SMOM_ROOT}/artifacts/contracts/bridge/trustless/pilot/Chain138PilotDexVenues.sol/Chain138PilotCurve3Pool.dbg.json" ;;
|
||||
Chain138PilotOneInchAggregationRouter) printf '%s' "${SMOM_ROOT}/artifacts/contracts/bridge/trustless/pilot/Chain138PilotDexVenues.sol/Chain138PilotOneInchAggregationRouter.dbg.json" ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
foundry_artifact_json_path() {
|
||||
case "$1" in
|
||||
EnhancedSwapRouterV2) printf '%s' "${SMOM_ROOT}/out/EnhancedSwapRouterV2.sol/EnhancedSwapRouterV2.json" ;;
|
||||
IntentBridgeCoordinatorV2) printf '%s' "${SMOM_ROOT}/out/IntentBridgeCoordinatorV2.sol/IntentBridgeCoordinatorV2.json" ;;
|
||||
DodoRouteExecutorAdapter) printf '%s' "${SMOM_ROOT}/out/DodoRouteExecutorAdapter.sol/DodoRouteExecutorAdapter.json" ;;
|
||||
DodoV3RouteExecutorAdapter) printf '%s' "${SMOM_ROOT}/out/DodoV3RouteExecutorAdapter.sol/DodoV3RouteExecutorAdapter.json" ;;
|
||||
UniswapV3RouteExecutorAdapter) printf '%s' "${SMOM_ROOT}/out/UniswapV3RouteExecutorAdapter.sol/UniswapV3RouteExecutorAdapter.json" ;;
|
||||
BalancerRouteExecutorAdapter) printf '%s' "${SMOM_ROOT}/out/BalancerRouteExecutorAdapter.sol/BalancerRouteExecutorAdapter.json" ;;
|
||||
CurveRouteExecutorAdapter) printf '%s' "${SMOM_ROOT}/out/CurveRouteExecutorAdapter.sol/CurveRouteExecutorAdapter.json" ;;
|
||||
OneInchRouteExecutorAdapter) printf '%s' "${SMOM_ROOT}/out/OneInchRouteExecutorAdapter.sol/OneInchRouteExecutorAdapter.json" ;;
|
||||
Chain138PilotUniswapV3Router|Chain138PilotBalancerVault|Chain138PilotCurve3Pool|Chain138PilotOneInchAggregationRouter)
|
||||
printf '%s' "${SMOM_ROOT}/out/Chain138PilotDexVenues.sol/${1}.json"
|
||||
;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
runtime_hash_report() {
|
||||
local label="$1"
|
||||
local addr="$2"
|
||||
local artifact_json artifact_runtime chain_runtime
|
||||
|
||||
artifact_json="$(foundry_artifact_json_path "${label}")" || return 0
|
||||
[[ -f "${artifact_json}" ]] || return 0
|
||||
|
||||
artifact_runtime="$(jq -r '.deployedBytecode.object // empty' "${artifact_json}" | tr '[:upper:]' '[:lower:]')"
|
||||
chain_runtime="$(cast code "${addr}" --rpc-url "${RPC_URL}" 2>/dev/null | tr -d '\n\r \t' | tr '[:upper:]' '[:lower:]')" || true
|
||||
|
||||
[[ -n "${artifact_runtime}" && -n "${chain_runtime}" && "${chain_runtime}" != "0x" ]] || return 0
|
||||
|
||||
if [[ "${artifact_runtime}" != "${chain_runtime}" ]]; then
|
||||
warn "${label}: Foundry artifact runtime bytecode does not match deployed bytecode."
|
||||
warn "${label}: artifact_keccak=$(cast keccak "${artifact_runtime}") chain_keccak=$(cast keccak "${chain_runtime}")"
|
||||
fi
|
||||
}
|
||||
|
||||
submit_standard_input_from_artifact() {
|
||||
local label="$1"
|
||||
local addr="$2"
|
||||
local contract_path="$3"
|
||||
local constructor_args="$4"
|
||||
local dbg build input_file compiler_version evm_version optimization_runs optimization_enabled license_type response message
|
||||
|
||||
dbg="$(artifact_dbg_path "${label}")" || fail "${label}: missing dbg path mapping"
|
||||
[[ -f "${dbg}" ]] || fail "${label}: missing dbg artifact ${dbg}"
|
||||
build="$(jq -r '.buildInfo // .build_info // empty' "${dbg}")"
|
||||
[[ -n "${build}" && "${build}" != "null" ]] || fail "${label}: missing build-info reference in ${dbg}"
|
||||
build="$(cd "$(dirname "${dbg}")" && realpath "${build}")"
|
||||
[[ -f "${build}" ]] || fail "${label}: missing build-info file ${build}"
|
||||
|
||||
input_file="$(mktemp)"
|
||||
python3 - "${dbg}" "${build}" "${input_file}" "${contract_path%%:*}" <<'PY'
|
||||
import json
|
||||
import os
|
||||
import posixpath
|
||||
import re
|
||||
import sys
|
||||
|
||||
dbg_path, build_path, out_path, fallback_source = sys.argv[1:5]
|
||||
with open(dbg_path, "r", encoding="utf-8") as fh:
|
||||
dbg = json.load(fh)
|
||||
with open(build_path, "r", encoding="utf-8") as fh:
|
||||
build = json.load(fh)
|
||||
|
||||
source_name = dbg.get("sourceName") or dbg.get("source_name") or fallback_source
|
||||
if not source_name:
|
||||
raise SystemExit(f"missing sourceName in {dbg_path}")
|
||||
|
||||
input_data = build["input"]
|
||||
sources = input_data.get("sources", {})
|
||||
if source_name not in sources:
|
||||
raise SystemExit(f"source {source_name} missing from build-info input")
|
||||
|
||||
import_re = re.compile(r'import\s+(?:[^;]*?\s+from\s+)?["\']([^"\']+)["\']\s*;')
|
||||
|
||||
closure = set()
|
||||
stack = [source_name]
|
||||
while stack:
|
||||
current = stack.pop()
|
||||
if current in closure or current not in sources:
|
||||
continue
|
||||
closure.add(current)
|
||||
content = sources[current].get("content", "")
|
||||
for entry in import_re.findall(content):
|
||||
if entry.startswith("."):
|
||||
target = posixpath.normpath(posixpath.join(posixpath.dirname(current), entry))
|
||||
else:
|
||||
target = entry
|
||||
if target in sources and target not in closure:
|
||||
stack.append(target)
|
||||
|
||||
reduced = json.loads(json.dumps(input_data))
|
||||
reduced["sources"] = {name: sources[name] for name in sorted(closure)}
|
||||
|
||||
with open(out_path, "w", encoding="utf-8") as fh:
|
||||
json.dump(reduced, fh, separators=(",", ":"))
|
||||
PY
|
||||
compiler_version="$(jq -r '.solcLongVersion | "v" + .' "${build}")"
|
||||
evm_version="$(jq -r '.input.settings.evmVersion // "default"' "${build}")"
|
||||
optimization_runs="$(jq -r '.input.settings.optimizer.runs // 200' "${build}")"
|
||||
optimization_enabled="$(jq -r '.input.settings.optimizer.enabled // true' "${build}")"
|
||||
license_type="mit"
|
||||
|
||||
response="$(
|
||||
curl --max-time 180 -fsS -X POST \
|
||||
-F "compiler_version=${compiler_version}" \
|
||||
-F "contract_name=${contract_path}" \
|
||||
-F "autodetect_constructor_args=false" \
|
||||
-F "constructor_args=${constructor_args}" \
|
||||
-F "optimization_runs=${optimization_runs}" \
|
||||
-F "is_optimization_enabled=${optimization_enabled}" \
|
||||
-F "evm_version=${evm_version}" \
|
||||
-F "license_type=${license_type}" \
|
||||
-F "files[0]=@${input_file};type=application/json" \
|
||||
"${BLOCKSCOUT_URL}/api/v2/smart-contracts/${addr}/verification/via/standard-input"
|
||||
)" || {
|
||||
rm -f "${input_file}"
|
||||
fail "${label}: Blockscout standard-input submission failed."
|
||||
}
|
||||
rm -f "${input_file}"
|
||||
|
||||
message="$(jq -r '.message // empty' <<<"${response}")"
|
||||
if [[ "${message}" == "Smart-contract verification started" ]]; then
|
||||
ok "${label} standard-input verification submission accepted."
|
||||
return 0
|
||||
fi
|
||||
|
||||
warn "${label} standard-input verification returned: ${response}"
|
||||
return 1
|
||||
}
|
||||
|
||||
submit_standard_input_from_forge() {
|
||||
local label="$1"
|
||||
local addr="$2"
|
||||
local contract_path="$3"
|
||||
local constructor_args="$4"
|
||||
local input_file response message
|
||||
local compiler_version evm_version optimization_runs via_ir_flag artifact_json
|
||||
|
||||
compiler_version="${ROUTE_STACK_SOLC_VERSION}"
|
||||
evm_version="${ROUTE_STACK_EVM_VERSION}"
|
||||
optimization_runs="${ROUTE_STACK_OPT_RUNS}"
|
||||
via_ir_flag=(--via-ir)
|
||||
|
||||
artifact_json="$(foundry_artifact_json_path "${label}" || true)"
|
||||
if [[ -n "${artifact_json}" && -f "${artifact_json}" ]]; then
|
||||
compiler_version="v$(jq -r '.metadata.compiler.version // empty' "${artifact_json}")"
|
||||
evm_version="$(jq -r '.metadata.settings.evmVersion // "default"' "${artifact_json}")"
|
||||
optimization_runs="$(jq -r '.metadata.settings.optimizer.runs // 200' "${artifact_json}")"
|
||||
if [[ "$(jq -r '.metadata.settings.viaIR // false' "${artifact_json}")" != "true" ]]; then
|
||||
via_ir_flag=()
|
||||
fi
|
||||
fi
|
||||
|
||||
runtime_hash_report "${label}" "${addr}"
|
||||
input_file="$(mktemp)"
|
||||
(
|
||||
cd "${SMOM_ROOT}"
|
||||
forge verify-contract "${addr}" "${contract_path}" \
|
||||
--chain-id 138 \
|
||||
--root . \
|
||||
--compiler-version "${compiler_version}" \
|
||||
--num-of-optimizations "${optimization_runs}" \
|
||||
"${via_ir_flag[@]}" \
|
||||
--evm-version "${evm_version}" \
|
||||
--show-standard-json-input >"${input_file}"
|
||||
) || {
|
||||
rm -f "${input_file}"
|
||||
fail "${label}: failed to render Foundry standard-input from deployment sources."
|
||||
}
|
||||
|
||||
response="$(
|
||||
curl --max-time 180 -fsS -X POST \
|
||||
-F "compiler_version=${compiler_version}" \
|
||||
-F "contract_name=${contract_path}" \
|
||||
-F "autodetect_constructor_args=false" \
|
||||
-F "constructor_args=${constructor_args}" \
|
||||
-F "optimization_runs=${optimization_runs}" \
|
||||
-F "is_optimization_enabled=true" \
|
||||
-F "evm_version=${evm_version}" \
|
||||
-F "license_type=mit" \
|
||||
-F "files[0]=@${input_file};type=application/json" \
|
||||
"${BLOCKSCOUT_URL}/api/v2/smart-contracts/${addr}/verification/via/standard-input"
|
||||
)" || {
|
||||
rm -f "${input_file}"
|
||||
fail "${label}: Blockscout Foundry standard-input submission failed."
|
||||
}
|
||||
rm -f "${input_file}"
|
||||
|
||||
message="$(jq -r '.message // empty' <<<"${response}")"
|
||||
if [[ "${message}" == "Smart-contract verification started" ]]; then
|
||||
ok "${label} Foundry standard-input verification submission accepted."
|
||||
return 0
|
||||
fi
|
||||
|
||||
warn "${label} Foundry standard-input verification returned: ${response}"
|
||||
return 1
|
||||
}
|
||||
|
||||
submit_best_verification() {
|
||||
local label="$1"
|
||||
local addr="$2"
|
||||
local path="$3"
|
||||
local expected_name="$4"
|
||||
local constructor_sig="$5"
|
||||
shift 5
|
||||
local constructor_args=("$@")
|
||||
local encoded=""
|
||||
|
||||
if [[ -n "${constructor_sig}" ]]; then
|
||||
encoded="$(cast abi-encode "${constructor_sig}" "${constructor_args[@]}")"
|
||||
fi
|
||||
|
||||
# Prefer the Foundry deployment lineage for the route stack. The earlier
|
||||
# Hardhat dbg/build-info path drifted away from the actual deployed compiler/EVM
|
||||
# settings and is kept only as a compatibility fallback.
|
||||
if submit_standard_input_from_forge "${label}" "${addr}" "${path}" "${encoded}"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if artifact_dbg_path "${label}" >/dev/null 2>&1; then
|
||||
warn "${label}: falling back to artifact-derived standard-input after Foundry mismatch."
|
||||
submit_standard_input_from_artifact "${label}" "${addr}" "${path}" "${encoded}" || return 1
|
||||
return 0
|
||||
fi
|
||||
|
||||
warn "${label}: falling back to legacy Forge flattened verification path."
|
||||
submit_verification "${label}" "${addr}" "${path}" "${expected_name}" "${constructor_sig}" "${constructor_args[@]}"
|
||||
}
|
||||
|
||||
WETH="0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
|
||||
USDT="0x004b63A7B5b0E06f6bB6adb4a5F9f590BF3182D1"
|
||||
USDC="0x71D6687F38b93CCad569Fa6352c876eea967201b"
|
||||
DAI_PLACEHOLDER="0x6B175474E89094C44Da98b954EedeAC495271d0F"
|
||||
|
||||
ROUTER_V2="$(jq -r '.chains["138"].contracts.EnhancedSwapRouterV2' "${PROJECT_ROOT}/config/smart-contracts-master.json")"
|
||||
COORDINATOR_V2="$(jq -r '.chains["138"].contracts.IntentBridgeCoordinatorV2' "${PROJECT_ROOT}/config/smart-contracts-master.json")"
|
||||
DODO_ADAPTER="$(jq -r '.chains["138"].contracts.DodoRouteExecutorAdapter' "${PROJECT_ROOT}/config/smart-contracts-master.json")"
|
||||
DODO_V3_ADAPTER="$(jq -r '.chains["138"].contracts.DodoV3RouteExecutorAdapter' "${PROJECT_ROOT}/config/smart-contracts-master.json")"
|
||||
UNISWAP_V3_ADAPTER="$(jq -r '.chains["138"].contracts.UniswapV3RouteExecutorAdapter' "${PROJECT_ROOT}/config/smart-contracts-master.json")"
|
||||
BALANCER_ADAPTER="$(jq -r '.chains["138"].contracts.BalancerRouteExecutorAdapter' "${PROJECT_ROOT}/config/smart-contracts-master.json")"
|
||||
CURVE_ADAPTER="$(jq -r '.chains["138"].contracts.CurveRouteExecutorAdapter' "${PROJECT_ROOT}/config/smart-contracts-master.json")"
|
||||
ONEINCH_ADAPTER="$(jq -r '.chains["138"].contracts.OneInchRouteExecutorAdapter' "${PROJECT_ROOT}/config/smart-contracts-master.json")"
|
||||
PILOT_UNISWAP="$(jq -r '.chains["138"].contracts.PilotUniswapV3Router' "${PROJECT_ROOT}/config/smart-contracts-master.json")"
|
||||
PILOT_BALANCER="$(jq -r '.chains["138"].contracts.PilotBalancerVault' "${PROJECT_ROOT}/config/smart-contracts-master.json")"
|
||||
PILOT_CURVE="$(jq -r '.chains["138"].contracts.PilotCurve3Pool' "${PROJECT_ROOT}/config/smart-contracts-master.json")"
|
||||
PILOT_ONEINCH="$(jq -r '.chains["138"].contracts.PilotOneInchRouter' "${PROJECT_ROOT}/config/smart-contracts-master.json")"
|
||||
|
||||
log "Chain 138 route execution stack Blockscout verification"
|
||||
log "RPC: ${RPC_URL}"
|
||||
log "Explorer API: ${BLOCKSCOUT_API_BASE}"
|
||||
log
|
||||
|
||||
if (( STATUS_ONLY )); then
|
||||
for pair in \
|
||||
"EnhancedSwapRouterV2:${ROUTER_V2}:EnhancedSwapRouterV2" \
|
||||
"IntentBridgeCoordinatorV2:${COORDINATOR_V2}:IntentBridgeCoordinatorV2" \
|
||||
"DodoRouteExecutorAdapter:${DODO_ADAPTER}:DodoRouteExecutorAdapter" \
|
||||
"DodoV3RouteExecutorAdapter:${DODO_V3_ADAPTER}:DodoV3RouteExecutorAdapter" \
|
||||
"UniswapV3RouteExecutorAdapter:${UNISWAP_V3_ADAPTER}:UniswapV3RouteExecutorAdapter" \
|
||||
"BalancerRouteExecutorAdapter:${BALANCER_ADAPTER}:BalancerRouteExecutorAdapter" \
|
||||
"CurveRouteExecutorAdapter:${CURVE_ADAPTER}:CurveRouteExecutorAdapter" \
|
||||
"OneInchRouteExecutorAdapter:${ONEINCH_ADAPTER}:OneInchRouteExecutorAdapter" \
|
||||
"Chain138PilotUniswapV3Router:${PILOT_UNISWAP}:Chain138PilotUniswapV3Router" \
|
||||
"Chain138PilotBalancerVault:${PILOT_BALANCER}:Chain138PilotBalancerVault" \
|
||||
"Chain138PilotCurve3Pool:${PILOT_CURVE}:Chain138PilotCurve3Pool" \
|
||||
"Chain138PilotOneInchAggregationRouter:${PILOT_ONEINCH}:Chain138PilotOneInchAggregationRouter"
|
||||
do
|
||||
IFS=":" read -r label addr expected <<<"${pair}"
|
||||
should_handle "${label}" || continue
|
||||
if is_verified "${addr}" "${expected}"; then
|
||||
ok "${label} already verified on Blockscout."
|
||||
else
|
||||
warn "${label} not yet verified on Blockscout."
|
||||
fi
|
||||
done
|
||||
exit 0
|
||||
fi
|
||||
|
||||
should_handle "EnhancedSwapRouterV2" && submit_best_verification \
|
||||
"EnhancedSwapRouterV2" \
|
||||
"${ROUTER_V2}" \
|
||||
"contracts/bridge/trustless/EnhancedSwapRouterV2.sol:EnhancedSwapRouterV2" \
|
||||
"EnhancedSwapRouterV2" \
|
||||
"constructor(address,address,address,address)" \
|
||||
"${WETH}" "${USDT}" "${USDC}" "${DAI_PLACEHOLDER}"
|
||||
|
||||
should_handle "IntentBridgeCoordinatorV2" && submit_best_verification \
|
||||
"IntentBridgeCoordinatorV2" \
|
||||
"${COORDINATOR_V2}" \
|
||||
"contracts/bridge/trustless/IntentBridgeCoordinatorV2.sol:IntentBridgeCoordinatorV2" \
|
||||
"IntentBridgeCoordinatorV2" \
|
||||
"constructor(address)" \
|
||||
"${ROUTER_V2}"
|
||||
|
||||
should_handle "DodoRouteExecutorAdapter" && submit_best_verification \
|
||||
"DodoRouteExecutorAdapter" \
|
||||
"${DODO_ADAPTER}" \
|
||||
"contracts/bridge/trustless/adapters/DodoRouteExecutorAdapter.sol:DodoRouteExecutorAdapter" \
|
||||
"DodoRouteExecutorAdapter" \
|
||||
""
|
||||
|
||||
should_handle "DodoV3RouteExecutorAdapter" && submit_best_verification \
|
||||
"DodoV3RouteExecutorAdapter" \
|
||||
"${DODO_V3_ADAPTER}" \
|
||||
"contracts/bridge/trustless/adapters/DodoV3RouteExecutorAdapter.sol:DodoV3RouteExecutorAdapter" \
|
||||
"DodoV3RouteExecutorAdapter" \
|
||||
""
|
||||
|
||||
should_handle "UniswapV3RouteExecutorAdapter" && submit_best_verification \
|
||||
"UniswapV3RouteExecutorAdapter" \
|
||||
"${UNISWAP_V3_ADAPTER}" \
|
||||
"contracts/bridge/trustless/adapters/UniswapV3RouteExecutorAdapter.sol:UniswapV3RouteExecutorAdapter" \
|
||||
"UniswapV3RouteExecutorAdapter" \
|
||||
""
|
||||
|
||||
should_handle "BalancerRouteExecutorAdapter" && submit_best_verification \
|
||||
"BalancerRouteExecutorAdapter" \
|
||||
"${BALANCER_ADAPTER}" \
|
||||
"contracts/bridge/trustless/adapters/BalancerRouteExecutorAdapter.sol:BalancerRouteExecutorAdapter" \
|
||||
"BalancerRouteExecutorAdapter" \
|
||||
""
|
||||
|
||||
should_handle "CurveRouteExecutorAdapter" && submit_best_verification \
|
||||
"CurveRouteExecutorAdapter" \
|
||||
"${CURVE_ADAPTER}" \
|
||||
"contracts/bridge/trustless/adapters/CurveRouteExecutorAdapter.sol:CurveRouteExecutorAdapter" \
|
||||
"CurveRouteExecutorAdapter" \
|
||||
""
|
||||
|
||||
should_handle "OneInchRouteExecutorAdapter" && submit_best_verification \
|
||||
"OneInchRouteExecutorAdapter" \
|
||||
"${ONEINCH_ADAPTER}" \
|
||||
"contracts/bridge/trustless/adapters/OneInchRouteExecutorAdapter.sol:OneInchRouteExecutorAdapter" \
|
||||
"OneInchRouteExecutorAdapter" \
|
||||
""
|
||||
|
||||
should_handle "Chain138PilotUniswapV3Router" && submit_best_verification \
|
||||
"Chain138PilotUniswapV3Router" \
|
||||
"${PILOT_UNISWAP}" \
|
||||
"contracts/bridge/trustless/pilot/Chain138PilotDexVenues.sol:Chain138PilotUniswapV3Router" \
|
||||
"Chain138PilotUniswapV3Router" \
|
||||
""
|
||||
|
||||
should_handle "Chain138PilotBalancerVault" && submit_best_verification \
|
||||
"Chain138PilotBalancerVault" \
|
||||
"${PILOT_BALANCER}" \
|
||||
"contracts/bridge/trustless/pilot/Chain138PilotDexVenues.sol:Chain138PilotBalancerVault" \
|
||||
"Chain138PilotBalancerVault" \
|
||||
""
|
||||
|
||||
should_handle "Chain138PilotCurve3Pool" && submit_best_verification \
|
||||
"Chain138PilotCurve3Pool" \
|
||||
"${PILOT_CURVE}" \
|
||||
"contracts/bridge/trustless/pilot/Chain138PilotDexVenues.sol:Chain138PilotCurve3Pool" \
|
||||
"Chain138PilotCurve3Pool" \
|
||||
"constructor(address,address,address,uint256)" \
|
||||
"${USDT}" "${USDC}" "0x0000000000000000000000000000000000000000" "4"
|
||||
|
||||
should_handle "Chain138PilotOneInchAggregationRouter" && submit_best_verification \
|
||||
"Chain138PilotOneInchAggregationRouter" \
|
||||
"${PILOT_ONEINCH}" \
|
||||
"contracts/bridge/trustless/pilot/Chain138PilotDexVenues.sol:Chain138PilotOneInchAggregationRouter" \
|
||||
"Chain138PilotOneInchAggregationRouter" \
|
||||
""
|
||||
|
||||
if (( NO_WAIT )); then
|
||||
log
|
||||
ok "Chain 138 route execution stack verification submissions complete."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log
|
||||
ok "Chain 138 route execution stack verification flow complete."
|
||||
@@ -273,9 +273,16 @@ submit_v2_standard_input() {
|
||||
|
||||
compiler_version="v0.8.16+commit.07a7930e"
|
||||
license_type="busl_1_1"
|
||||
input_file="$(mktemp)"
|
||||
|
||||
jq '
|
||||
del(.settings.libraries[""].__CACHE_BREAKER__)
|
||||
| if (.settings.libraries[""]? == {}) then del(.settings.libraries[""]) else . end
|
||||
| if (.settings.libraries? == {}) then del(.settings.libraries) else . end
|
||||
' "${input}" > "${input_file}"
|
||||
|
||||
response="$(
|
||||
curl --max-time 30 -fsS -X POST \
|
||||
curl --max-time 120 -fsS -X POST \
|
||||
-F "compiler_version=${compiler_version}" \
|
||||
-F "contract_name=${path}" \
|
||||
-F "autodetect_constructor_args=false" \
|
||||
@@ -283,9 +290,13 @@ submit_v2_standard_input() {
|
||||
-F "optimization_runs=200" \
|
||||
-F "is_optimization_enabled=true" \
|
||||
-F "license_type=${license_type}" \
|
||||
-F "files[0]=@${input};type=application/json" \
|
||||
-F "files[0]=@${input_file};type=application/json" \
|
||||
"${BLOCKSCOUT_URL}/api/v2/smart-contracts/${addr}/verification/via/standard-input"
|
||||
)" || fail "${label}: Blockscout standard-input submission failed."
|
||||
)" || {
|
||||
rm -f "${input_file}"
|
||||
fail "${label}: Blockscout standard-input submission failed."
|
||||
}
|
||||
rm -f "${input_file}"
|
||||
|
||||
message="$(jq -r '.message // empty' <<<"${response}")"
|
||||
if [[ "${message}" == "Smart-contract verification started" ]]; then
|
||||
|
||||
Reference in New Issue
Block a user