chore: sync docs, config schemas, scripts, and meta task alignment

- Institutional / JVMTM / reserve-provenance / GRU transport + standards JSON
- Validation and verify scripts (Blockscout labels, x402, GRU preflight, P1 local path)
- Wormhole wiring in AGENTS, MCP_SETUP, MASTER_INDEX, 04-configuration README
- Meta docs, integration gaps, live verification log, architecture updates
- CI validate-config workflow updates

Operator/LAN items, submodule working trees, and public token-aggregation edge
routes remain follow-up (see TODOS_CONSOLIDATED P1).

Made-with: Cursor
This commit is contained in:
defiQUG
2026-03-31 22:31:39 -07:00
parent 00880304d4
commit 7ac74f432b
948 changed files with 47476 additions and 490 deletions

View File

@@ -29,8 +29,15 @@ One-line install (Debian/Ubuntu): `sudo apt install -y sshpass rsync dnsutils ip
- `backup-npmplus.sh` - Full NPMplus backup (database, API exports, certificates)
- `check-contracts-on-chain-138.sh` - Check that Chain 138 deployed contracts have bytecode on-chain (`cast code` for 31 addresses; requires `cast` and RPC access). Use `[RPC_URL]` or env `RPC_URL_138`; `--dry-run` lists addresses only (no RPC calls); `SKIP_EXIT=1` to exit 0 when RPC unreachable.
- `check-public-report-api.sh` - Verify that `explorer.d-bis.org/api/v1/report/*` and `/api/v1/networks` return token-aggregation JSON rather than Blockscout-style `/api/v1` responses. Use `SKIP_EXIT=1` for diagnostic-only mode. Set `SKIP_BRIDGE_ROUTES=0` to assert `/api/v1/bridge/routes`, and `SKIP_BRIDGE_PREFLIGHT=0` to assert `/api/v1/bridge/preflight` payload shape.
- `check-token-aggregation-chain138-api.sh` - Hits tokens, pools, quote, `bridge/routes`, `bridge/status`, `bridge/preflight`, and networks on both `/api/v1/*` and `/token-aggregation/api/v1/*`. `BASE_URL=https://explorer.d-bis.org` (default) or `http://192.168.11.140`.
- `check-gru-transport-preflight.sh` - Operator-focused GRU runtime preflight. Calls `/api/v1/bridge/preflight`, prints blocked pairs with `eligibilityBlockers` / `runtimeMissingRequirements`, and fails unless all active pairs are runtime-ready or `ALLOW_BLOCKED=1` is set.
- `check-cstar-v2-transport-stack.sh` - Predeploy Forge verifier for the `c* V2` bridge stack. Runs the base V2 token suite, legacy reserve-verifier compatibility suite, V2 reserve/verifier full L1/L2 round-trip suite, and the core `CWMultiTokenBridge` round-trip suite.
- `run-repo-green-test-path.sh` - Local deterministic green-path aggregate behind root `pnpm test`. Runs config validation, then the focused `smom-dbis-138` contract and service CI targets.
- `check-completion-status.sh` - One-command summary of repo-completable checks, public report API health, and pointers to operator/external remaining work.
- `reconcile-env-canonical.sh` - Emit recommended .env lines for Chain 138 (canonical source of truth); use to reconcile `smom-dbis-138/.env` with [CONTRACT_ADDRESSES_REFERENCE](../../docs/11-references/CONTRACT_ADDRESSES_REFERENCE.md). Usage: `./scripts/verify/reconcile-env-canonical.sh [--print]`
- `check-deployer-balance-blockscout-vs-rpc.sh` - Compare deployer native balance from Blockscout API vs RPC (to verify index matches current chain); see [EXPLORER_AND_BLOCKSCAN_REFERENCE](../../docs/11-references/EXPLORER_AND_BLOCKSCAN_REFERENCE.md)
- `sync-blockscout-address-labels-from-registry.sh` - Plan or sync Blockscout address labels from `address-registry-entry` JSON (`config/dbis-institutional/schemas/address-registry-entry.schema.json`: `blockscout.label`, `status: active`). Supports `--mode=http`, `--mode=db`, and `--mode=auto`; on the self-hosted Chain 138 explorer, `db` is the right live mode because `/api/v1/*` is token-aggregation, not a native Blockscout label-write API. DB mode writes primary labels into Blockscout `public.address_names` through CT `5000`. See `config/dbis-institutional/README.md` and [OMNL_DBIS_CORE_CHAIN138_SMART_VAULT_RTGS_RUNBOOK.md](../../docs/03-deployment/OMNL_DBIS_CORE_CHAIN138_SMART_VAULT_RTGS_RUNBOOK.md).
- `check-dependencies.sh` - Verify required tools (bash, curl, jq, openssl, ssh)
- `export-cloudflare-dns-records.sh` - Export Cloudflare DNS records
- `export-npmplus-config.sh` - Export NPMplus proxy hosts and certificates via API
@@ -43,7 +50,9 @@ One-line install (Debian/Ubuntu): `sudo apt install -y sshpass rsync dnsutils ip
## Task runners (no LAN vs from LAN)
- **From anywhere (no LAN/creds):** `../run-completable-tasks-from-anywhere.sh` — runs config validation, on-chain contract check, run-all-validation --skip-genesis, and reconcile-env-canonical.
- **From anywhere (no LAN/creds):** `../run-completable-tasks-from-anywhere.sh` — runs config validation, on-chain contract check, run-all-validation --skip-genesis, public report API diagnostics, and reconcile-env-canonical.
- **Completion snapshot:** `check-completion-status.sh` — summarizes what is complete locally and what still depends on operator or external execution.
- **Full LAN execution order:** `../run-full-operator-completion-from-lan.sh` — starts with the token-aggregation `/api/v1` repair, then Wave 0, verification, E2E, and optional operator-only deployment steps. Use `--dry-run` first.
- **From LAN (NPM_PASSWORD, optional PRIVATE_KEY):** `../run-operator-tasks-from-lan.sh` — runs W0-1 (NPMplus RPC fix), W0-3 (NPMplus backup), O-1 (Blockscout verification); use `--dry-run` to print commands only. See [ALL_TASKS_DETAILED_STEPS](../../docs/00-meta/ALL_TASKS_DETAILED_STEPS.md).
## Environment

View File

@@ -2,8 +2,9 @@
# Check whether Chain 138 deployed tokens (cUSDT, cUSDC) support ERC-2612 permit or ERC-3009.
# Used to determine x402 compatibility: thirdweb x402 requires permit or ERC-3009.
#
# Usage: ./scripts/verify/check-chain138-token-permit-support.sh [RPC_URL]
# Usage: ./scripts/verify/check-chain138-token-permit-support.sh [RPC_URL] [--token SYMBOL=ADDRESS]...
# RPC_URL: optional; default from RPC_URL_138 or CHAIN_138_RPC_URL or https://rpc-core.d-bis.org
# --token SYMBOL=ADDRESS: optional; inspect custom token inventory (repeatable)
# --dry-run: print RPC and token addresses only (no RPC calls).
#
# Exit: 0 if script runs; output is human-readable. Use output to fill CHAIN138_X402_TOKEN_SUPPORT.md.
@@ -14,19 +15,55 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
[[ -f "${SCRIPT_DIR}/../lib/load-project-env.sh" ]] && source "${SCRIPT_DIR}/../lib/load-project-env.sh" 2>/dev/null || true
DRY_RUN=""
RPC_ARG=""
for a in "$@"; do
if [[ "$a" == "--dry-run" ]]; then DRY_RUN=1; else [[ -z "$RPC_ARG" ]] && RPC_ARG="$a"; fi
declare -A TOKENS=()
TOKEN_ORDER=()
add_token() {
local spec="$1"
local symbol="${spec%%=*}"
local address="${spec#*=}"
if [[ -z "$symbol" || -z "$address" || "$symbol" == "$address" ]]; then
echo "ERROR: invalid token spec '$spec' (expected SYMBOL=ADDRESS)" >&2
exit 1
fi
TOKENS["$symbol"]="$address"
TOKEN_ORDER+=("$symbol")
}
while [[ $# -gt 0 ]]; do
case "$1" in
--dry-run)
DRY_RUN=1
shift
;;
--token)
[[ $# -ge 2 ]] || { echo "ERROR: --token requires SYMBOL=ADDRESS" >&2; exit 1; }
add_token "$2"
shift 2
;;
--token=*)
add_token "${1#--token=}"
shift
;;
*)
if [[ -z "$RPC_ARG" ]]; then
RPC_ARG="$1"
else
add_token "$1"
fi
shift
;;
esac
done
RPC="${RPC_ARG:-${RPC_URL_138:-${CHAIN_138_RPC_URL:-https://rpc-core.d-bis.org}}}"
# Token name, address (from CHAIN138_TOKEN_ADDRESSES.md)
declare -A TOKENS
TOKENS[cUSDT]="0x93E66202A11B1772E55407B32B44e5Cd8eda7f22"
TOKENS[cUSDC]="0xf22258f57794CC8E06237084b353Ab30fFfa640b"
if [[ ${#TOKEN_ORDER[@]} -eq 0 ]]; then
add_token "cUSDT=0x93E66202A11B1772E55407B32B44e5Cd8eda7f22"
add_token "cUSDC=0xf22258f57794CC8E06237084b353Ab30fFfa640b"
fi
# Test holder for nonces(address) call (any address is fine)
HOLDER="0x0000000000000000000000000000000000000001"
@@ -34,7 +71,7 @@ HOLDER="0x0000000000000000000000000000000000000001"
if [[ -n "$DRY_RUN" ]]; then
echo "=== Chain 138 token permit support check (--dry-run) ==="
echo "RPC: $RPC"
for sym in cUSDT cUSDC; do echo " $sym: ${TOKENS[$sym]}"; done
for sym in "${TOKEN_ORDER[@]}"; do echo " $sym: ${TOKENS[$sym]}"; done
exit 0
fi
@@ -48,7 +85,7 @@ if ! command -v cast &>/dev/null; then
exit 1
fi
for sym in cUSDT cUSDC; do
for sym in "${TOKEN_ORDER[@]}"; do
addr="${TOKENS[$sym]}"
echo "--- $sym ($addr) ---"

View File

@@ -0,0 +1,203 @@
#!/usr/bin/env bash
# Check whether Chain 138 is operationally ready for x402 and whether its payment tokens are x402-capable.
#
# Usage:
# ./scripts/verify/check-chain138-x402-readiness.sh [CORE_RPC] [PUBLIC_RPC] [EXPLORER_STATS] [--token SYMBOL=ADDRESS]...
# ./scripts/verify/check-chain138-x402-readiness.sh --strict
#
# Exit codes:
# 0 when the script runs successfully
# 1 when --strict is used and x402 is not fully ready
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
STRICT=0
POSITIONAL=()
declare -A TOKENS=()
TOKEN_ORDER=()
add_token() {
local spec="$1"
local symbol="${spec%%=*}"
local address="${spec#*=}"
if [[ -z "$symbol" || -z "$address" || "$symbol" == "$address" ]]; then
echo "ERROR: invalid token spec '$spec' (expected SYMBOL=ADDRESS)" >&2
exit 1
fi
TOKENS["$symbol"]="$address"
TOKEN_ORDER+=("$symbol")
}
while [[ $# -gt 0 ]]; do
case "$1" in
--strict)
STRICT=1
shift
;;
--token)
[[ $# -ge 2 ]] || { echo "ERROR: --token requires SYMBOL=ADDRESS" >&2; exit 1; }
add_token "$2"
shift 2
;;
--token=*)
add_token "${1#--token=}"
shift
;;
*)
POSITIONAL+=("$1")
shift
;;
esac
done
CORE_RPC="${POSITIONAL[0]:-${RPC_URL_138:-${CHAIN_138_RPC_URL:-http://192.168.11.211:8545}}}"
PUBLIC_RPC="${POSITIONAL[1]:-${PUBLIC_RPC_URL_138:-https://rpc.public-0138.defi-oracle.io}}"
EXPLORER_STATS="${POSITIONAL[2]:-${EXPLORER_STATS_URL_138:-https://explorer.d-bis.org/api/v2/stats}}"
if [[ ${#TOKEN_ORDER[@]} -eq 0 ]]; then
add_token "cUSDT=0x93E66202A11B1772E55407B32B44e5Cd8eda7f22"
add_token "cUSDC=0xf22258f57794CC8E06237084b353Ab30fFfa640b"
fi
HOLDER="0x0000000000000000000000000000000000000001"
ZERO_BYTES32="0x0000000000000000000000000000000000000000000000000000000000000000"
rpc_call() {
local url="$1"
local method="$2"
local params="${3:-[]}"
curl -sS --max-time 15 \
-H 'Content-Type: application/json' \
--data "{\"jsonrpc\":\"2.0\",\"method\":\"${method}\",\"params\":${params},\"id\":1}" \
"$url"
}
json_field() {
local json="$1"
local jq_expr="$2"
jq -r "$jq_expr" <<<"$json" 2>/dev/null || true
}
http_status() {
local url="$1"
local body_file="$2"
curl -k -sS --max-time 15 -o "$body_file" -w "%{http_code}" "$url"
}
echo "=== Chain 138 x402 readiness ==="
echo "Core RPC: $CORE_RPC"
echo "Public RPC: $PUBLIC_RPC"
echo "Explorer: $EXPLORER_STATS"
echo ""
core_ok=0
public_ok=0
explorer_ok=0
token_ready=0
core_block="n/a"
core_peers="n/a"
core_syncing="n/a"
public_client="n/a"
explorer_blocks="n/a"
if core_block_json="$(rpc_call "$CORE_RPC" "eth_blockNumber")"; then
core_block="$(json_field "$core_block_json" '.result // "n/a"')"
if [[ "$core_block" != "n/a" && "$core_block" != "null" ]]; then
core_ok=1
fi
fi
if [[ "$core_ok" -eq 1 ]]; then
core_peers="$(json_field "$(rpc_call "$CORE_RPC" "net_peerCount")" '.result // "n/a"')"
core_syncing="$(json_field "$(rpc_call "$CORE_RPC" "eth_syncing")" '.result')"
fi
public_body_file="$(mktemp)"
explorer_body_file="$(mktemp)"
trap 'rm -f "$public_body_file" "$explorer_body_file"' EXIT
public_status="$(curl -k -sS --max-time 15 -o "$public_body_file" -w "%{http_code}" \
-H 'Content-Type: application/json' \
--data '{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":1}' \
"$PUBLIC_RPC" || true)"
public_result="$(cat "$public_body_file" 2>/dev/null || true)"
public_client="$(json_field "$public_result" '.result // empty')"
if [[ "$public_status" == "200" && -n "$public_client" ]]; then
public_ok=1
fi
explorer_status="$(http_status "$EXPLORER_STATS" "$explorer_body_file" || true)"
explorer_result="$(cat "$explorer_body_file" 2>/dev/null || true)"
explorer_blocks="$(json_field "$explorer_result" '.total_blocks // "n/a"')"
if [[ "$explorer_status" == "200" && "$explorer_blocks" != "n/a" && "$explorer_blocks" != "null" ]]; then
explorer_ok=1
fi
echo "Operational readiness"
echo " core_rpc_ok: $core_ok"
echo " core_block: $core_block"
echo " core_peer_count: $core_peers"
echo " core_syncing: $core_syncing"
echo " public_rpc_ok: $public_ok"
echo " public_rpc_http: ${public_status:-n/a}"
echo " public_client: ${public_client:-n/a}"
echo " explorer_ok: $explorer_ok"
echo " explorer_http: ${explorer_status:-n/a}"
echo " explorer_blocks: $explorer_blocks"
echo ""
echo "Token compatibility"
if ! command -v cast >/dev/null 2>&1; then
echo " cast_available: 0"
echo " note: install foundry/cast to perform on-chain permit checks"
else
echo " cast_available: 1"
for sym in "${TOKEN_ORDER[@]}"; do
addr="${TOKENS[$sym]}"
permit_supported=0
auth_supported=0
if cast call "$addr" "nonces(address)(uint256)" "$HOLDER" --rpc-url "$CORE_RPC" >/dev/null 2>&1; then
permit_supported=1
fi
if cast call "$addr" "authorizationState(address,bytes32)(bool)" "$HOLDER" "$ZERO_BYTES32" --rpc-url "$CORE_RPC" >/dev/null 2>&1; then
auth_supported=1
fi
if [[ "$permit_supported" -eq 1 || "$auth_supported" -eq 1 ]]; then
token_ready=1
fi
echo " ${sym}_address: $addr"
echo " ${sym}_erc2612: $permit_supported"
echo " ${sym}_erc3009: $auth_supported"
done
fi
echo ""
if [[ "$core_ok" -eq 1 && "$public_ok" -eq 1 && "$explorer_ok" -eq 1 ]]; then
echo "Operational verdict: Chain 138 edge services are healthy."
else
echo "Operational verdict: Chain 138 edge services are not fully healthy."
fi
if [[ "$token_ready" -eq 1 ]]; then
echo "Token verdict: At least one canonical Chain 138 payment token is x402-capable."
else
echo "Token verdict: Canonical Chain 138 payment tokens are still not x402-capable."
fi
if [[ "$core_ok" -eq 1 && "$public_ok" -eq 1 && "$explorer_ok" -eq 1 && "$token_ready" -eq 1 ]]; then
echo "x402 verdict: READY"
else
echo "x402 verdict: BLOCKED"
echo " note: thirdweb x402 still needs an ERC-2612 or ERC-3009 payment token on Chain 138."
fi
if [[ "$STRICT" -eq 1 && ! ( "$core_ok" -eq 1 && "$public_ok" -eq 1 && "$explorer_ok" -eq 1 && "$token_ready" -eq 1 ) ]]; then
exit 1
fi

View File

@@ -0,0 +1,62 @@
#!/usr/bin/env bash
# Summarize repo-completable vs operator/external completion state in one place.
# Usage: bash scripts/verify/check-completion-status.sh
# Exit codes:
# 0 = all repo-completable checks passed and public API looks healthy
# 1 = one or more checks reported issues
# Set SKIP_EXIT=1 to always exit 0 after printing the summary.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
SKIP_EXIT="${SKIP_EXIT:-0}"
FAILURES=0
section() {
printf '\n=== %s ===\n' "$1"
}
run_check() {
local label="$1"
shift
printf -- '- %s\n' "$label"
if "$@"; then
printf ' [OK] %s\n' "$label"
else
printf ' [WARN] %s\n' "$label"
FAILURES=$((FAILURES + 1))
fi
}
section "Repo-Completable Checks"
run_check "Config validation" bash scripts/validation/validate-config-files.sh
run_check "All validation (--skip-genesis)" bash scripts/verify/run-all-validation.sh --skip-genesis
run_check "Submodule working trees" env SKIP_EXIT=0 bash scripts/verify/submodules-clean.sh
section "Public API Health"
run_check "Public report API" env SKIP_EXIT=0 KEEP_GOING=1 bash scripts/verify/check-public-report-api.sh
section "Status Interpretation"
cat <<'EOF'
- Repo-local validation is complete when the config, validation, and submodule checks pass.
- Public report API problems are usually operator-side nginx/proxy deployment issues, not repo code issues.
- Remaining non-local work is tracked in:
- docs/00-meta/STILL_NOT_DONE_EXECUTION_CHECKLIST.md
- docs/00-meta/OPERATOR_AND_EXTERNAL_COMPLETION_CHECKLIST.md
- docs/00-meta/COMPLETE_REQUIRED_OPTIONAL_RECOMMENDED_INDEX.md
EOF
section "Summary"
if (( FAILURES == 0 )); then
echo "- All repo-completable checks passed."
echo "- Public report API looks healthy."
else
echo "- Checks with warnings: $FAILURES"
echo "- Review the warnings above to distinguish repo-local cleanup from operator-side work."
fi
if (( FAILURES > 0 )) && [[ "$SKIP_EXIT" != "1" ]]; then
exit 1
fi

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# Check that Chain 138 deployed contracts have bytecode on-chain.
# Address list: 61 (core, CCIP, PMM, vault/reserve, oracle keeper path, CompliantFiatTokens). Source: CONTRACT_ADDRESSES_REFERENCE, ADDRESS_MATRIX.
# Address list: 64 (core, CCIP canonical+legacy routers, WETH9 canonical+legacy bridges, PMM, vault/reserve, oracle keeper path, CompliantFiatTokens, ISO20022Router). Aligns with smom-dbis-138/.env and ADDRESS_MATRIX.
# Usage: ./scripts/verify/check-contracts-on-chain-138.sh [RPC_URL] [--dry-run]
# Default RPC: from env RPC_URL_138 (Chain 138 Core standard) or config/ip-addresses.conf, else https://rpc-core.d-bis.org
# Optional: SKIP_EXIT=1 to exit 0 even when some addresses MISS (e.g. when RPC unreachable from this host).
@@ -14,9 +14,17 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
export PROJECT_ROOT
# Load project env so RPC_URL_138 (Chain 138 Core) from config/ip-addresses.conf or smom-dbis-138/.env is used
[[ -f "${SCRIPT_DIR}/../lib/load-project-env.sh" ]] && source "${SCRIPT_DIR}/../lib/load-project-env.sh" 2>/dev/null || true
# Load project env so RPC_URL_138 (Chain 138 Core) from config/ip-addresses.conf or smom-dbis-138/.env is used.
# export PROJECT_ROOT so load-project-env does not re-derive a wrong path from BASH_SOURCE and hit err_exit.
# Temporarily relax -e/-u: nested dotenv may invoke helpers not on PATH or reference unset vars (exit 127 / set -u).
if [[ -f "${SCRIPT_DIR}/../lib/load-project-env.sh" ]]; then
set +eu
# shellcheck source=../lib/load-project-env.sh
source "${SCRIPT_DIR}/../lib/load-project-env.sh" 2>/dev/null || true
set -euo pipefail
fi
# Parse args: first non-option is RPC_URL; --dry-run = print only, no cast calls
DRY_RUN=""
@@ -49,9 +57,11 @@ else
"0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9f" # WETH10
"0x99b3511a2d315a497c8112c1fdd8d508d4b1e506" # Multicall / Oracle Aggregator
"0x3304b747e565a97ec8ac220b0b6a1f6ffdb837e6" # Oracle Proxy
"0x8078A09637e47Fa5Ed34F626046Ea2094a5CDE5e" # CCIP Router
"0x42DAb7b888Dd382bD5Adcf9E038dBF1fD03b4817" # CCIP Router (canonical; CCIP_ROUTER / relay path)
"0x8078A09637e47Fa5Ed34F626046Ea2094a5CDE5e" # CCIP Router direct legacy (CCIP_ROUTER_DIRECT_LEGACY)
"0x105F8A15b819948a89153505762444Ee9f324684" # CCIP Sender
"0x971cD9D156f193df8051E48043C476e53ECd4693" # CCIPWETH9Bridge
"0xcacfd227A040002e49e2e01626363071324f820a" # CCIPWETH9Bridge (canonical sendCrossChain)
"0x971cD9D156f193df8051E48043C476e53ECd4693" # CCIPWETH9Bridge direct legacy (CCIPWETH9_BRIDGE_DIRECT_LEGACY)
"0xe0E93247376aa097dB308B92e6Ba36bA015535D0" # CCIPWETH10Bridge
"0xb7721dD53A8c629d9f1Ba31a5819AFe250002b03" # LINK
"0x93E66202A11B1772E55407B32B44e5Cd8eda7f22" # cUSDT
@@ -106,6 +116,7 @@ else
"0x54dBd40cF05e15906A2C21f600937e96787f5679" # cCADC
"0x290E52a8819A4fbD0714E517225429aA2B70EC6b" # cXAUC
"0x94e408E26c6FD8F4ee00b54dF19082FDA07dC96E" # cXAUT
"0xBf1BB3E73C2DB7c4aebCd7bf757cdD1C12dE9074" # ISO20022Router (explorer address-inventory ISO20022_ROUTER)
)
fi

View File

@@ -0,0 +1,55 @@
#!/usr/bin/env bash
# Verify that the c* V2 token, reserve, and c* <-> cW* transport stack are green before deploy.
# Usage: bash scripts/verify/check-cstar-v2-transport-stack.sh
#
# Env:
# DRY_RUN=1 Print the commands without executing them
set -euo pipefail
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SMOM_ROOT="${PROJECT_ROOT}/smom-dbis-138"
DRY_RUN="${DRY_RUN:-0}"
log() { printf '%s\n' "$*"; }
ok() { printf '[OK] %s\n' "$*"; }
run() {
if [[ "$DRY_RUN" == "1" ]]; then
printf '[DRY_RUN] %s\n' "$*"
return 0
fi
"$@"
}
if ! command -v forge >/dev/null 2>&1; then
printf '[FAIL] forge is required but not installed or not on PATH.\n' >&2
exit 1
fi
log "=== c* V2 transport stack verifier ==="
log "Repo: ${SMOM_ROOT}"
log ""
pushd "$SMOM_ROOT" >/dev/null
# Foundry's JSON cache occasionally drifts when toolchain output shapes change.
# Removing the generated cache keeps these focused suites reliable in CI and local runs.
rm -f cache/solidity-files-cache.json
run forge test --match-path "test/compliance/CompliantFiatTokenV2.t.sol"
ok "CompliantFiatTokenV2 base token suite passed."
run forge test --match-path "test/bridge/CWReserveVerifierVaultIntegration.t.sol"
ok "Legacy reserve-verifier bridge compatibility suite passed."
run forge test --match-path "test/bridge/CWReserveVerifierVaultV2Integration.t.sol"
ok "V2 reserve-verifier + full L1/L2 transport suite passed."
run forge test --match-path "test/bridge/CWMultiTokenBridge.t.sol"
ok "Core CWMultiTokenBridge round-trip suite passed."
popd >/dev/null
log ""
ok "c* V2 bridge and transport stack is green."

View File

@@ -0,0 +1,103 @@
#!/usr/bin/env bash
# Verify GRU Monetary Transport Layer runtime readiness via /api/v1/bridge/preflight.
# Usage: bash scripts/verify/check-gru-transport-preflight.sh [base_url]
# base_url: Optional API base, defaults to https://explorer.d-bis.org
#
# Exit codes:
# 0 = endpoint healthy and, unless ALLOW_BLOCKED=1, no blocked pairs remain
# 1 = endpoint unreachable, wrong payload, or blocked pairs remain
#
# Env:
# SKIP_EXIT=1 Print diagnostics but always exit 0
# ALLOW_BLOCKED=1 Treat blocked pairs as warnings instead of failures
set -euo pipefail
BASE_URL="${1:-${BASE_URL:-https://explorer.d-bis.org}}"
BASE_URL="${BASE_URL%/}"
SKIP_EXIT="${SKIP_EXIT:-0}"
ALLOW_BLOCKED="${ALLOW_BLOCKED:-0}"
HAD_FAILURE=0
log() { printf '%s\n' "$*"; }
ok() { printf '[OK] %s\n' "$*"; }
warn() { printf '[WARN] %s\n' "$*"; }
fail() {
printf '[FAIL] %s\n' "$*"
HAD_FAILURE=1
if [[ "$SKIP_EXIT" != "1" ]]; then
exit 1
fi
}
tmp_body="$(mktemp)"
trap 'rm -f "$tmp_body"' EXIT
fetch_preflight() {
local prefix
for prefix in "" "/token-aggregation"; do
local url="${BASE_URL}${prefix}/api/v1/bridge/preflight"
local code
code="$(curl -sS -o "$tmp_body" -w "%{http_code}" -m 25 "$url" 2>/dev/null || echo "000")"
if [[ "$code" == "200" ]]; then
printf '%s\n' "$prefix"
return 0
fi
done
return 1
}
log "=== GRU Transport preflight ==="
log "Base URL: $BASE_URL"
log ""
if ! prefix="$(fetch_preflight)"; then
fail "Could not fetch /api/v1/bridge/preflight on either /api/v1 or /token-aggregation/api/v1."
fi
if ! jq -e '
type == "object" and
(.gruTransport | type == "object") and
(.gruTransport.summary.transportPairs | type == "number") and
(.gruTransport.blockedPairs | type == "array") and
(.gruTransport.readyPairs | type == "array")
' "$tmp_body" >/dev/null 2>&1; then
summary="$(head -c 300 "$tmp_body" | tr '\n' ' ')"
fail "Unexpected /api/v1/bridge/preflight payload shape. Sample: $summary"
fi
transport_pairs="$(jq -r '.gruTransport.summary.transportPairs // 0' "$tmp_body")"
runtime_ready_pairs="$(jq -r '.gruTransport.summary.runtimeReadyTransportPairs // 0' "$tmp_body")"
blocked_pairs="$(jq -r '.gruTransport.blockedPairs | length' "$tmp_body")"
ready_pairs="$(jq -r '.gruTransport.readyPairs | length' "$tmp_body")"
display_path="${prefix}/api/v1/bridge/preflight"
if [[ -z "$prefix" ]]; then
display_path="/api/v1/bridge/preflight"
fi
ok "Preflight endpoint reachable at ${display_path}"
log "Transport pairs: $transport_pairs"
log "Runtime-ready pairs: $runtime_ready_pairs"
log "Ready pairs returned: $ready_pairs"
log "Blocked pairs returned: $blocked_pairs"
if (( blocked_pairs > 0 )); then
log ""
warn "Blocked GRU transport pairs:"
jq -r '
.gruTransport.blockedPairs[]
| "- \(.key): eligibilityBlockers=\(((.eligibilityBlockers // []) | join(",")) // "") runtimeMissingRequirements=\(((.runtimeMissingRequirements // []) | join(",")) // "")"
' "$tmp_body"
if [[ "$ALLOW_BLOCKED" != "1" ]]; then
fail "GRU transport preflight has blocked pairs. Set ALLOW_BLOCKED=1 for diagnostic-only mode."
else
warn "ALLOW_BLOCKED=1 set: blocked pairs reported without failing."
fi
else
ok "All active GRU transport pairs are runtime-ready."
fi
if [[ "$SKIP_EXIT" == "1" ]]; then
warn "SKIP_EXIT=1 set: diagnostic mode."
fi

View File

@@ -0,0 +1,128 @@
#!/usr/bin/env bash
# Verify that the public token-aggregation/report API is reachable and not misrouted to Blockscout.
# Usage: bash scripts/verify/check-public-report-api.sh [base_url]
# base_url: Optional API base, defaults to https://explorer.d-bis.org
#
# Exit codes:
# 0 = all expected endpoints returned token-aggregation-style JSON
# 1 = one or more endpoints returned the wrong shape or were unreachable
# Set SKIP_EXIT=1 to print diagnostics but exit 0.
# Set KEEP_GOING=1 to keep checking every endpoint before exiting non-zero.
# Set SKIP_BRIDGE_ROUTES=0 to assert /api/v1/bridge/routes payload shape.
# Set SKIP_BRIDGE_PREFLIGHT=0 to assert /api/v1/bridge/preflight payload shape.
set -euo pipefail
BASE_URL="${1:-https://explorer.d-bis.org}"
SKIP_EXIT="${SKIP_EXIT:-0}"
KEEP_GOING="${KEEP_GOING:-0}"
HAD_FAILURE=0
log() { printf '%s\n' "$*"; }
ok() { printf '[OK] %s\n' "$*"; }
warn() { printf '[WARN] %s\n' "$*"; }
fail() {
printf '[FAIL] %s\n' "$*"
HAD_FAILURE=1
if [[ "$SKIP_EXIT" != "1" && "$KEEP_GOING" != "1" ]]; then
exit 1
fi
}
check_json_shape() {
local name="$1"
local url="$2"
local jq_expr="$3"
local expected_desc="$4"
local response
local body
local status
if ! response="$(curl -sSL --max-time 20 -w $'\n%{http_code}' "$url" 2>/dev/null)"; then
fail "$name request failed: $url"
return 0
fi
status="$(printf '%s' "$response" | tail -n 1)"
body="$(printf '%s' "$response" | sed '$d')"
if printf '%s' "$body" | jq -e 'type == "object" and has("message") and has("result") and has("status")' >/dev/null 2>&1; then
fail "$name is returning Blockscout-style JSON (HTTP $status) instead of token-aggregation JSON. See docs/04-configuration/TOKEN_AGGREGATION_REPORT_API_RUNBOOK.md"
return 0
fi
if printf '%s' "$body" | jq -e 'type == "object" and has("error")' >/dev/null 2>&1; then
local api_error
api_error="$(printf '%s' "$body" | jq -r '.error' 2>/dev/null || echo 'unknown error')"
fail "$name returned token-aggregation error payload (HTTP $status): $api_error"
return 0
fi
if printf '%s' "$body" | jq -e "$jq_expr" >/dev/null 2>&1; then
ok "$name healthy ($expected_desc, HTTP $status)"
return 0
fi
local summary
summary="$(printf '%s' "$body" | head -c 240 | tr '\n' ' ')"
fail "$name returned unexpected payload (HTTP $status). Expected $expected_desc. Sample: $summary"
}
log "=== Public report API check ==="
log "Base URL: $BASE_URL"
log ""
check_json_shape \
"token-list" \
"$BASE_URL/api/v1/report/token-list?chainId=138" \
'type == "object" and (.tokens | type == "array")' \
'object with .tokens[]'
check_json_shape \
"coingecko report" \
"$BASE_URL/api/v1/report/coingecko?chainId=138" \
'type == "object"' \
'token-aggregation report JSON object'
check_json_shape \
"cmc report" \
"$BASE_URL/api/v1/report/cmc?chainId=138" \
'type == "object"' \
'token-aggregation report JSON object'
check_json_shape \
"networks" \
"$BASE_URL/api/v1/networks" \
'type == "object" and (.networks | type == "array")' \
'object with .networks[]'
# Bridge routes (requires token-aggregation build with GET /api/v1/bridge/routes). Off by default until edge is deployed.
if [[ "${SKIP_BRIDGE_ROUTES:-1}" != "1" ]]; then
check_json_shape \
"bridge-routes" \
"$BASE_URL/api/v1/bridge/routes" \
'type == "object" and (.chain138Bridges | type == "object") and (.routes | type == "object")' \
'object with .chain138Bridges and .routes'
fi
# GRU preflight (shape only; does not require all pairs to be runtime-ready). Off by default until edge is deployed.
if [[ "${SKIP_BRIDGE_PREFLIGHT:-1}" != "1" ]]; then
check_json_shape \
"bridge-preflight" \
"$BASE_URL/api/v1/bridge/preflight" \
'type == "object" and (.gruTransport | type == "object") and (.gruTransport.summary.transportPairs | type == "number") and (.gruTransport.blockedPairs | type == "array")' \
'object with .gruTransport.summary and .gruTransport.blockedPairs[]'
fi
log ""
if (( HAD_FAILURE > 0 )); then
if [[ "$SKIP_EXIT" == "1" ]]; then
warn "SKIP_EXIT=1 set: non-healthy endpoints were reported without failing."
elif [[ "$KEEP_GOING" == "1" ]]; then
exit 1
fi
elif [[ "$SKIP_EXIT" == "1" ]]; then
warn "SKIP_EXIT=1 set: non-healthy endpoints were reported without failing."
else
ok "Public report API endpoints look healthy."
fi

View File

@@ -0,0 +1,121 @@
#!/usr/bin/env bash
# E2E: every public RPC FQDN — HTTP JSON-RPC eth_chainId (+ WSS where listed).
# Exit 0 only if all HTTP checks pass; WSS failures warn unless STRICT_WSS=1 (then exit 1).
#
# Usage: bash scripts/verify/check-rpc-fqdns-e2e.sh
# Env: RPC_TIMEOUT_SEC (default 25), STRICT_WSS=1 to fail on wscat errors
set -euo pipefail
TO="${RPC_TIMEOUT_SEC:-25}"
BODY='{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}'
# Chain 138
EXPECT='0x8a'
# HTTP JSON-RPC hostnames (inventory: verify-end-to-end-routing.sh + RPC_ENDPOINTS_MASTER + NPM tw-core / core-2)
HTTP_FQDNS=(
rpc-http-pub.d-bis.org
rpc.d-bis.org
rpc2.d-bis.org
rpc-http-prv.d-bis.org
rpc-fireblocks.d-bis.org
rpc.public-0138.defi-oracle.io
rpc.defi-oracle.io
rpc-alltra.d-bis.org
rpc-alltra-2.d-bis.org
rpc-alltra-3.d-bis.org
rpc-hybx.d-bis.org
rpc-hybx-2.d-bis.org
rpc-hybx-3.d-bis.org
rpc.tw-core.d-bis.org
rpc-core-2.d-bis.org
rpc-core.d-bis.org
)
# WebSocket RPC hostnames (wss://)
WS_FQDNS=(
rpc-ws-pub.d-bis.org
ws.rpc.d-bis.org
ws.rpc2.d-bis.org
rpc-ws-prv.d-bis.org
ws.rpc-fireblocks.d-bis.org
wss.defi-oracle.io
wss.tw-core.d-bis.org
)
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "RPC FQDN E2E — eth_chainId (HTTP) + WSS smoke"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
http_fail=0
echo -e "${BLUE}--- HTTP (POST / JSON-RPC) ---${NC}"
for host in "${HTTP_FQDNS[@]}"; do
url="https://${host}"
if ! getent ahosts "$host" >/dev/null 2>&1; then
echo -e "${YELLOW}SKIP${NC} $url — hostname does not resolve (add DNS or use Core IP :8545)"
continue
fi
resp=$(mktemp)
code=$(curl -sS -m "$TO" -X POST "$url" \
-H 'Content-Type: application/json' \
-d "$BODY" \
-k -w '%{http_code}' -o "$resp" 2>/dev/null || echo "000")
cid=$(jq -r '.result // empty' "$resp" 2>/dev/null || true)
err=$(head -c 120 "$resp" 2>/dev/null | tr -d '\r\n')
rm -f "$resp"
if [[ "$code" == "200" && "$cid" == "$EXPECT" ]]; then
echo -e "${GREEN}OK${NC} $url chainId=$cid"
elif [[ "$code" == "200" && -n "$cid" ]]; then
echo -e "${YELLOW}WARN${NC} $url HTTP $code chainId=$cid (expected $EXPECT)"
((http_fail++)) || true
else
echo -e "${RED}FAIL${NC} $url HTTP $code ${err}"
((http_fail++)) || true
fi
done
echo ""
echo -e "${BLUE}--- WebSocket (wscat eth_chainId) ---${NC}"
ws_fail=0
if ! command -v wscat >/dev/null 2>&1; then
echo -e "${YELLOW}SKIP${NC} wscat not installed (npm i -g wscat)"
ws_fail=0
else
for host in "${WS_FQDNS[@]}"; do
if out=$(timeout "$((TO + 5))" wscat -n -c "wss://${host}" -x "$BODY" -w 8 2>&1); then
if echo "$out" | grep -q '"result"'; then
echo -e "${GREEN}OK${NC} wss://${host}"
else
echo -e "${YELLOW}OK*${NC} wss://${host} (connected, no JSON line)"
fi
else
echo -e "${RED}FAIL${NC} wss://${host} $(echo "$out" | tail -1)"
((ws_fail++)) || true
fi
done
fi
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
if [[ "$http_fail" -eq 0 ]]; then
echo -e "${GREEN}HTTP: all passed ($EXPECT)${NC}"
else
echo -e "${RED}HTTP: $http_fail failure(s)${NC}"
fi
if [[ "${STRICT_WSS:-0}" == "1" ]] && [[ "$ws_fail" -gt 0 ]]; then
echo -e "${RED}WSS: $ws_fail failure(s) (STRICT_WSS=1)${NC}"
exit 1
fi
if [[ "$http_fail" -gt 0 ]]; then
exit 1
fi
echo -e "${GREEN}Done.${NC}"
exit 0

View File

@@ -0,0 +1,68 @@
#!/usr/bin/env bash
# Verify token-aggregation HTTP surface for Chain 138 (pools, quotes, bridge routes, and GRU preflight).
# Usage: BASE_URL=https://explorer.d-bis.org bash scripts/verify/check-token-aggregation-chain138-api.sh
# Tries both /api/v1/* and /token-aggregation/api/v1/* (explorer nginx layouts differ).
set -euo pipefail
BASE_URL="${BASE_URL:-https://explorer.d-bis.org}"
BASE_URL="${BASE_URL%/}"
CUSDT="0x93E66202A11B1772E55407B32B44e5Cd8eda7f22"
CUSDC="0xf22258f57794CC8E06237084b353Ab30fFfa640b"
try_path() {
local prefix="$1"
local path="$2"
local url="${BASE_URL}${prefix}${path}"
local code
code=$(curl -sS -o /tmp/ta-check.json -w "%{http_code}" -m 25 "$url" || echo "000")
echo " $code ${prefix}${path}"
if [[ "$code" == 200 ]]; then
head -c 220 /tmp/ta-check.json
echo
fi
}
echo "== Token-aggregation checks against ${BASE_URL} =="
for prefix in "" "/token-aggregation"; do
echo ""
echo "-- prefix: ${prefix:-/} (root /api/v1) --"
try_path "${prefix}" "/api/v1/tokens?chainId=138&limit=3&includeDodoPool=true"
try_path "${prefix}" "/api/v1/tokens/${CUSDT}/pools?chainId=138"
try_path "${prefix}" "/api/v1/quote?chainId=138&tokenIn=${CUSDT}&tokenOut=${CUSDC}&amountIn=1000000"
try_path "${prefix}" "/api/v1/bridge/routes"
try_path "${prefix}" "/api/v1/bridge/status"
try_path "${prefix}" "/api/v1/bridge/preflight"
try_path "${prefix}" "/api/v1/networks"
done
echo ""
echo ""
echo "== bridge summary =="
for prefix in "" "/token-aggregation"; do
code=$(curl -sS -o /tmp/br.json -w "%{http_code}" -m 20 "${BASE_URL}${prefix}/api/v1/bridge/routes" 2>/dev/null || echo 000)
echo "${prefix:-/} -> HTTP $code"
if [[ "$code" == "200" ]] && command -v jq >/dev/null 2>&1; then
jq '{weth9: .chain138Bridges.weth9, weth10: .chain138Bridges.weth10}' /tmp/br.json 2>/dev/null || head -c 200 /tmp/br.json
echo
fi
done
echo ""
echo "== bridge/preflight summary =="
for prefix in "" "/token-aggregation"; do
code=$(curl -sS -o /tmp/gru-preflight.json -w "%{http_code}" -m 20 "${BASE_URL}${prefix}/api/v1/bridge/preflight" 2>/dev/null || echo 000)
echo "${prefix:-/} -> HTTP $code"
if [[ "$code" == "200" ]] && command -v jq >/dev/null 2>&1; then
jq '{transportPairs: .gruTransport.summary.transportPairs, runtimeReadyTransportPairs: .gruTransport.summary.runtimeReadyTransportPairs, blockedPairs: (.gruTransport.blockedPairs | length)}' /tmp/gru-preflight.json 2>/dev/null || head -c 200 /tmp/gru-preflight.json
echo
fi
done
echo ""
echo "Notes:"
echo " - Empty tokens/pools: set DATABASE_URL + migrations; RPC to 138; PMM integration now defaults on-chain if env unset."
echo " - bridge/routes 404: redeploy token-aggregation from repo (implements GET /api/v1/bridge/routes)."
echo " - bridge/preflight blocked pairs: run bash scripts/verify/check-gru-transport-preflight.sh [BASE_URL] for exact missing refs."
echo " - Health: curl -s http://127.0.0.1:3001/health on explorer VM (not always proxied as /health)."

View File

@@ -41,6 +41,7 @@ declare -A DOMAIN_ZONES=(
["rpc-http-pub.d-bis.org"]="d-bis.org"
["rpc-ws-pub.d-bis.org"]="d-bis.org"
["rpc-http-prv.d-bis.org"]="d-bis.org"
["rpc-core.d-bis.org"]="d-bis.org"
["rpc-ws-prv.d-bis.org"]="d-bis.org"
["dbis-admin.d-bis.org"]="d-bis.org"
["dbis-api.d-bis.org"]="d-bis.org"

View File

@@ -0,0 +1,42 @@
#!/usr/bin/env bash
# P1 local verification — no LAN deploys, no Proxmox SSH, no on-chain txs.
# Completes automatable slices documented in docs/00-meta/TODOS_CONSOLIDATED.md (P1-F*).
#
# Usage:
# ./scripts/verify/run-p1-local-verification.sh # config + completable
# ./scripts/verify/run-p1-local-verification.sh --with-iru-tests # + dbis_core pnpm test:iru-marketplace
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$ROOT"
WITH_IRU=0
for a in "$@"; do
[[ "$a" == "--with-iru-tests" ]] && WITH_IRU=1
done
echo "== P1 local verification (repo root: $ROOT) =="
echo ""
echo "[1/3] validate-config-files.sh"
bash scripts/validation/validate-config-files.sh
echo ""
echo "[2/3] run-completable-tasks-from-anywhere.sh"
./scripts/run-completable-tasks-from-anywhere.sh
echo ""
if [[ "$WITH_IRU" -eq 1 ]]; then
echo "[3/3] dbis_core pnpm test:iru-marketplace"
if command -v pnpm &>/dev/null; then
(cd dbis_core && pnpm test:iru-marketplace)
else
echo "SKIP: pnpm not installed; run: cd dbis_core && pnpm test:iru-marketplace"
fi
else
echo "[3/3] SKIP IRU tests (pass --with-iru-tests to run)"
fi
echo ""
echo "[OK] P1 local verification finished."

View File

@@ -0,0 +1,27 @@
#!/usr/bin/env bash
# Run the repo's local deterministic green-path tests for Chain 138 / GRU transport.
# Usage: bash scripts/verify/run-repo-green-test-path.sh
set -euo pipefail
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
log() { printf '%s\n' "$*"; }
ok() { printf '[OK] %s\n' "$*"; }
run_step() {
local label="$1"
shift
log ""
log "=== ${label} ==="
"$@"
}
run_step "Config validation" \
bash "$PROJECT_ROOT/scripts/validation/validate-config-files.sh"
run_step "Chain 138 package CI targets" \
pnpm --dir "$PROJECT_ROOT/smom-dbis-138" run test:ci
log ""
ok "Repo green-path tests passed."

View File

@@ -1,9 +1,11 @@
#!/usr/bin/env bash
# Exit 0 if every submodule has a clean working tree (no modified/untracked files).
# Use in CI or after merges: bash scripts/verify/submodules-clean.sh
# Set SKIP_EXIT=1 to report dirty submodules without failing.
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
cd "$ROOT"
SKIP_EXIT="${SKIP_EXIT:-0}"
tmp="$(mktemp)"
trap 'rm -f "$tmp"' EXIT
@@ -25,7 +27,10 @@ done < <(git config --file .gitmodules --get-regexp '^submodule\..*\.path$' | aw
if (( dirty )); then
echo "submodules-clean: dirty submodule working trees:" >&2
cat "$tmp" >&2
exit 1
if [[ "$SKIP_EXIT" != "1" ]]; then
exit 1
fi
exit 0
fi
echo "submodules-clean: OK (all submodules clean)"

View File

@@ -0,0 +1,284 @@
#!/usr/bin/env bash
# Sync address labels from DBIS institutional registry JSON into Blockscout.
# Default: print the planned action only. Use --apply to write.
#
# Supported modes:
# http - POST JSON to a Blockscout-compatible label endpoint
# db - write primary labels directly into Blockscout Postgres address_names
# auto - prefer HTTP if the route exists; otherwise fall back to DB sync
#
# Registry shape: config/dbis-institutional/schemas/address-registry-entry.schema.json
#
# Env (HTTP mode):
# BLOCKSCOUT_BASE_URL default https://explorer.d-bis.org
# BLOCKSCOUT_LABEL_PATH default /api/v1/labels
# BLOCKSCOUT_API_KEY optional Bearer token if the endpoint requires it
#
# Env (DB mode):
# BLOCKSCOUT_DB_SSH_HOST default root@192.168.11.12
# BLOCKSCOUT_DB_CT_VMID default 5000
# BLOCKSCOUT_DB_CONTAINER default blockscout-postgres
# BLOCKSCOUT_DB_USER default blockscout
# BLOCKSCOUT_DB_NAME default blockscout
#
# Usage:
# bash scripts/verify/sync-blockscout-address-labels-from-registry.sh file1.json [file2.json ...]
# bash scripts/verify/sync-blockscout-address-labels-from-registry.sh --from-dir config/dbis-institutional/registry
# bash scripts/verify/sync-blockscout-address-labels-from-registry.sh --apply --mode=db --from-dir config/dbis-institutional/registry
#
set -euo pipefail
APPLY=0
FROM_DIR=""
SYNC_MODE="${BLOCKSCOUT_SYNC_MODE:-auto}"
while [[ $# -gt 0 ]]; do
case "$1" in
--apply) APPLY=1; shift ;;
--from-dir=*)
FROM_DIR="${1#*=}"
shift
;;
--from-dir)
FROM_DIR="${2:?}"
shift 2
;;
--mode=*)
SYNC_MODE="${1#*=}"
shift
;;
--mode)
SYNC_MODE="${2:?}"
shift 2
;;
-h|--help)
sed -n '2,42p' "$0" | sed 's/^# \{0,1\}//'
exit 0
;;
*) break ;;
esac
done
case "$SYNC_MODE" in
auto|http|db) ;;
*)
echo "error: --mode must be one of: auto, http, db" >&2
exit 1
;;
esac
BASE_URL="${BLOCKSCOUT_BASE_URL:-https://explorer.d-bis.org}"
LABEL_PATH="${BLOCKSCOUT_LABEL_PATH:-/api/v1/labels}"
URL="${BASE_URL%/}${LABEL_PATH}"
BLOCKSCOUT_DB_SSH_HOST="${BLOCKSCOUT_DB_SSH_HOST:-root@192.168.11.12}"
BLOCKSCOUT_DB_CT_VMID="${BLOCKSCOUT_DB_CT_VMID:-5000}"
BLOCKSCOUT_DB_CONTAINER="${BLOCKSCOUT_DB_CONTAINER:-blockscout-postgres}"
BLOCKSCOUT_DB_USER="${BLOCKSCOUT_DB_USER:-blockscout}"
BLOCKSCOUT_DB_NAME="${BLOCKSCOUT_DB_NAME:-blockscout}"
files=()
if [[ -n "$FROM_DIR" ]]; then
if [[ ! -d "$FROM_DIR" ]]; then
echo "error: --from-dir not a directory: $FROM_DIR" >&2
exit 1
fi
while IFS= read -r -d '' f; do
files+=("$f")
done < <(find "$FROM_DIR" -maxdepth 1 -name '*.json' -print0 2>/dev/null || true)
else
files=("$@")
fi
if [[ ${#files[@]} -eq 0 ]]; then
echo "usage: $0 [--apply] [--mode auto|http|db] [--from-dir DIR] <registry.json> [...]" >&2
echo " or: REGISTRY_DIR=... $0 --from-dir \"\$REGISTRY_DIR\"" >&2
exit 1
fi
if ! command -v jq &>/dev/null; then
echo "error: jq is required" >&2
exit 1
fi
sql_quote() {
printf "%s" "$1" | sed "s/'/''/g"
}
probe_http_sync() {
local tmp status
tmp=$(mktemp)
status=$(curl -sS -o "$tmp" -w '%{http_code}' -X POST "$URL" -H 'Content-Type: application/json' --data '{}' || true)
local body
body=$(cat "$tmp")
rm -f "$tmp"
# 2xx/4xx except 404 means the route exists and reached a handler.
if [[ "$status" =~ ^(200|201|202|204|400|401|403|405|409|415|422)$ ]]; then
return 0
fi
if [[ "$status" == "404" && "$body" == *'"error":"Not found"'* ]]; then
return 1
fi
return 1
}
run_db_sql() {
local sql="$1"
ssh "$BLOCKSCOUT_DB_SSH_HOST" \
"pct exec ${BLOCKSCOUT_DB_CT_VMID} -- docker exec -i ${BLOCKSCOUT_DB_CONTAINER} psql -U ${BLOCKSCOUT_DB_USER} -d ${BLOCKSCOUT_DB_NAME} -v ON_ERROR_STOP=1 -f -" \
<<<"$sql"
}
emit_http() {
local display="$1"
local address="$2"
local label="$3"
local ltype="$4"
local body
body=$(jq -nc --arg a "$address" --arg l "$label" --arg t "$ltype" '{address:$a,label:$l,type:$t}')
if [[ "$APPLY" -ne 1 ]]; then
echo "PLAN mode=http file=$display"
echo " POST $URL"
echo " $body"
return 0
fi
local hdr=()
if [[ -n "${BLOCKSCOUT_API_KEY:-}" ]]; then
hdr=(-H "Authorization: Bearer ${BLOCKSCOUT_API_KEY}" -H "Content-Type: application/json")
else
hdr=(-H "Content-Type: application/json")
fi
echo "POST $display -> $URL"
curl -fsS "${hdr[@]}" -X POST "$URL" -d "$body" >/dev/null
echo "ok http $address"
}
emit_db() {
local display="$1"
local address="$2"
local label="$3"
local ltype="$4"
local normalized_address="${address#0x}"
normalized_address="${normalized_address#0X}"
normalized_address=$(printf '%s' "$normalized_address" | tr '[:upper:]' '[:lower:]')
if [[ ! "$normalized_address" =~ ^[0-9a-f]{40}$ ]]; then
echo "skip (invalid address): $display" >&2
return 0
fi
local metadata
metadata=$(jq -nc \
--arg source "registry" \
--arg registryFile "$display" \
--arg labelType "$ltype" \
'{source:$source,registryFile:$registryFile,labelType:$labelType}')
local sql
sql=$(cat <<SQL
INSERT INTO public.address_names (
address_hash,
name,
"primary",
inserted_at,
updated_at,
metadata
)
VALUES (
decode('$(sql_quote "$normalized_address")', 'hex'),
'$(sql_quote "$label")',
true,
NOW(),
NOW(),
'$(sql_quote "$metadata")'::jsonb
)
ON CONFLICT (address_hash) WHERE "primary" = true
DO UPDATE SET
name = EXCLUDED.name,
updated_at = EXCLUDED.updated_at,
metadata = COALESCE(public.address_names.metadata, '{}'::jsonb) || COALESCE(EXCLUDED.metadata, '{}'::jsonb);
SQL
)
if [[ "$APPLY" -ne 1 ]]; then
echo "PLAN mode=db file=$display"
echo " SSH $BLOCKSCOUT_DB_SSH_HOST -> CT $BLOCKSCOUT_DB_CT_VMID -> ${BLOCKSCOUT_DB_NAME}.public.address_names"
echo " address=$address label=$label type=$ltype"
return 0
fi
echo "UPSERT $display -> ${BLOCKSCOUT_DB_NAME}.public.address_names"
run_db_sql "$sql" >/dev/null
echo "ok db $address"
}
emit_one() {
local file="$1"
local display="${2:-$file}"
local mode="$3"
local blob
blob=$(jq -e . "$file" 2>/dev/null) || { echo "skip (invalid JSON): $display" >&2; return 0; }
local status address label ltype
status=$(echo "$blob" | jq -r '.status // "active"')
[[ "$status" == "active" ]] || { echo "skip (status=$status): $display" >&2; return 0; }
address=$(echo "$blob" | jq -r '.address // empty')
label=$(echo "$blob" | jq -r '.blockscout.label // empty')
ltype=$(echo "$blob" | jq -r '.blockscout.labelType // "contract"')
if [[ -z "$address" || -z "$label" ]]; then
echo "skip (missing address or blockscout.label): $display" >&2
return 0
fi
case "$mode" in
http) emit_http "$display" "$address" "$label" "$ltype" ;;
db) emit_db "$display" "$address" "$label" "$ltype" ;;
*)
echo "error: unsupported mode: $mode" >&2
return 1
;;
esac
}
SELECTED_MODE="$SYNC_MODE"
if [[ "$SYNC_MODE" == "auto" && "$APPLY" -eq 1 ]]; then
if probe_http_sync; then
SELECTED_MODE="http"
else
SELECTED_MODE="db"
fi
fi
for f in "${files[@]}"; do
[[ -f "$f" ]] || { echo "skip (not a file): $f" >&2; continue; }
if jq -e 'type == "object" and (.address|type=="string")' "$f" &>/dev/null; then
emit_one "$f" "$f" "$SELECTED_MODE" || exit 1
elif jq -e 'type == "array"' "$f" &>/dev/null; then
tmpdir=$(mktemp -d)
len=$(jq 'length' "$f")
for ((i = 0; i < len; i++)); do
jq ".[$i]" "$f" >"$tmpdir/single.json"
emit_one "$tmpdir/single.json" "$f (item $i)" "$SELECTED_MODE" || { rm -rf "$tmpdir"; exit 1; }
done
rm -rf "$tmpdir"
else
echo "skip (not object or array of objects): $f" >&2
fi
done
if [[ "$APPLY" -ne 1 ]]; then
echo ""
echo "Dry run only. Re-run with --apply. Use --mode=db for this self-hosted Blockscout when /api/v1 labels is not available."
else
echo ""
echo "Completed in mode=$SELECTED_MODE."
fi

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# Troubleshoot the 6 E2E RPC HTTP failures (405 at edge).
# Troubleshoot E2E RPC HTTP failures (405 at edge); tests 7 primary FQDNs (+ optional --lan NPM Host checks).
# Usage: bash scripts/verify/troubleshoot-rpc-failures.sh [--lan]
# --lan Also test NPMplus direct (192.168.11.167) with Host header; requires LAN access.
@@ -17,6 +17,7 @@ RPC_DOMAINS=(
"rpc.d-bis.org"
"rpc2.d-bis.org"
"rpc-http-prv.d-bis.org"
"rpc-core.d-bis.org"
"rpc.defi-oracle.io"
)
RPC_BODY='{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}'
@@ -35,7 +36,7 @@ info() { echo -e "${BLUE}[INFO]${NC} $1"; }
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Troubleshoot 6 RPC E2E failures (POST → public IP)"
echo "Troubleshoot RPC E2E failures (POST → public IP)"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""

View File

@@ -65,10 +65,13 @@ declare -A DOMAIN_TYPES_ALL=(
["ws.rpc.d-bis.org"]="rpc-ws"
["ws.rpc2.d-bis.org"]="rpc-ws"
["rpc-http-prv.d-bis.org"]="rpc-http"
["rpc-core.d-bis.org"]="rpc-http"
["rpc-ws-prv.d-bis.org"]="rpc-ws"
["rpc-fireblocks.d-bis.org"]="rpc-http"
["ws.rpc-fireblocks.d-bis.org"]="rpc-ws"
["admin.d-bis.org"]="web"
["dbis-admin.d-bis.org"]="web"
["core.d-bis.org"]="web"
["dbis-api.d-bis.org"]="api"
["dbis-api-2.d-bis.org"]="api"
["secure.d-bis.org"]="web"
@@ -111,6 +114,19 @@ declare -A DOMAIN_TYPES_ALL=(
["gitea.d-bis.org"]="web"
["dev.d-bis.org"]="web"
["codespaces.d-bis.org"]="web"
# DBIS institutional multi-portal program (optional-when-fail until provisioned)
["d-bis.org"]="web"
["www.d-bis.org"]="web"
["members.d-bis.org"]="web"
["developers.d-bis.org"]="web"
["data.d-bis.org"]="api"
["research.d-bis.org"]="web"
["policy.d-bis.org"]="web"
["ops.d-bis.org"]="web"
["identity.d-bis.org"]="web"
["status.d-bis.org"]="web"
["sandbox.d-bis.org"]="web"
["interop.d-bis.org"]="web"
)
# Private/admin profile domains (private RPC + Fireblocks RPC only).
declare -a PRIVATE_PROFILE_DOMAINS=(
@@ -174,7 +190,7 @@ else
fi
# Domains that are optional when any test fails (off-LAN, 502, unreachable); fail → skip so run passes.
_PUB_OPTIONAL_WHEN_FAIL="dapp.d-bis.org mifos.d-bis.org explorer.d-bis.org dbis-admin.d-bis.org dbis-api.d-bis.org dbis-api-2.d-bis.org secure.d-bis.org sankofa.nexus www.sankofa.nexus phoenix.sankofa.nexus www.phoenix.sankofa.nexus the-order.sankofa.nexus www.the-order.sankofa.nexus studio.sankofa.nexus keycloak.sankofa.nexus admin.sankofa.nexus portal.sankofa.nexus dash.sankofa.nexus docs.d-bis.org blockscout.defi-oracle.io mim4u.org www.mim4u.org secure.mim4u.org training.mim4u.org rpc-http-pub.d-bis.org rpc.d-bis.org rpc2.d-bis.org rpc.public-0138.defi-oracle.io rpc.defi-oracle.io ws.rpc.d-bis.org ws.rpc2.d-bis.org"
_PUB_OPTIONAL_WHEN_FAIL="dapp.d-bis.org mifos.d-bis.org explorer.d-bis.org admin.d-bis.org dbis-admin.d-bis.org core.d-bis.org dbis-api.d-bis.org dbis-api-2.d-bis.org secure.d-bis.org d-bis.org www.d-bis.org members.d-bis.org developers.d-bis.org data.d-bis.org research.d-bis.org policy.d-bis.org ops.d-bis.org identity.d-bis.org status.d-bis.org sandbox.d-bis.org interop.d-bis.org sankofa.nexus www.sankofa.nexus phoenix.sankofa.nexus www.phoenix.sankofa.nexus the-order.sankofa.nexus www.the-order.sankofa.nexus studio.sankofa.nexus keycloak.sankofa.nexus admin.sankofa.nexus portal.sankofa.nexus dash.sankofa.nexus docs.d-bis.org blockscout.defi-oracle.io mim4u.org www.mim4u.org secure.mim4u.org training.mim4u.org rpc-http-pub.d-bis.org rpc.d-bis.org rpc2.d-bis.org rpc-core.d-bis.org rpc.public-0138.defi-oracle.io rpc.defi-oracle.io ws.rpc.d-bis.org ws.rpc2.d-bis.org"
_PRIV_OPTIONAL_WHEN_FAIL="rpc-http-prv.d-bis.org rpc-ws-prv.d-bis.org rpc-fireblocks.d-bis.org ws.rpc-fireblocks.d-bis.org"
if [[ -z "${E2E_OPTIONAL_WHEN_FAIL:-}" ]]; then
if [[ "$PROFILE" == "private" ]]; then
@@ -199,6 +215,7 @@ declare -A E2E_HTTPS_PATH=(
["phoenix.sankofa.nexus"]="/health"
["www.phoenix.sankofa.nexus"]="/health"
["studio.sankofa.nexus"]="/studio/"
["data.d-bis.org"]="/v1/health"
)
# Expected apex URL for NPM www → canonical 301/308 (Location must use this host; path from E2E_HTTPS_PATH must appear when set)