Files
proxmox/scripts/verify/check-gru-v2-chain138-readiness.sh
defiQUG dbd517b279 Sync workspace: config, docs, scripts, CI, operator rules, and submodule pointers.
- Update dbis_core, cross-chain-pmm-lps, explorer-monorepo, metamask-integration, pr-workspace/chains
- Omit embedded publish git dirs and empty placeholders from index

Made-with: Cursor
2026-04-12 06:12:20 -07:00

253 lines
8.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# Verify the live GRU c* V2 readiness state on Chain 138.
# Usage:
# bash scripts/verify/check-gru-v2-chain138-readiness.sh
# bash scripts/verify/check-gru-v2-chain138-readiness.sh --report-only
# RPC_URL=https://rpc-http-pub.d-bis.org bash scripts/verify/check-gru-v2-chain138-readiness.sh
#
# The script checks:
# - local CompliantFiatTokenV2 Foundry suite (optional via RUN_LOCAL_TESTS=1)
# - deployed bytecode for cUSDT V2 / cUSDC V2
# - UniversalAssetRegistry activation as GRU assets
# - core version/signing surface (name/symbol/versionTag/currencyCode/assetId/assetVersionId/DOMAIN_SEPARATOR)
# - promotion blockers (forwardCanonical still false, missing governance/supervision metadata ABI)
# - token metadata path is populated and uses decentralized URI format
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
export PROJECT_ROOT
if [[ -f "${PROJECT_ROOT}/scripts/lib/load-project-env.sh" ]]; then
set +eu
# shellcheck source=../lib/load-project-env.sh
source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh" 2>/dev/null || true
set -euo pipefail
fi
REPORT_ONLY=0
RUN_LOCAL_TESTS="${RUN_LOCAL_TESTS:-0}"
for arg in "$@"; do
case "$arg" in
--report-only) REPORT_ONLY=1 ;;
--run-local-tests) RUN_LOCAL_TESTS=1 ;;
*)
echo "Unknown argument: $arg" >&2
exit 2
;;
esac
done
need_cmd() {
command -v "$1" >/dev/null 2>&1 || {
echo "[FAIL] Missing required command: $1" >&2
exit 1
}
}
need_cmd cast
RPC_URL="${RPC_URL:-${RPC_URL_138_PUBLIC:-${RPC_URL_138:-https://rpc-http-pub.d-bis.org}}}"
REGISTRY="${UNIVERSAL_ASSET_REGISTRY:-0xAEE4b7fBe82E1F8295951584CBc772b8BBD68575}"
CUSDT_V2="${COMPLIANT_USDT_V2:-${CUSDT_V2_ADDRESS_138:-0x9FBfab33882Efe0038DAa608185718b772EE5660}}"
CUSDC_V2="${COMPLIANT_USDC_V2:-${CUSDC_V2_ADDRESS_138:-0x219522c60e83dEe01FC5b0329d6fA8fD84b9D13d}}"
BLOCKERS=()
WARNINGS=()
ok() { printf '[OK] %s\n' "$*"; }
warn() { printf '[WARN] %s\n' "$*"; WARNINGS+=("$*"); }
block() { printf '[BLOCKER] %s\n' "$*"; BLOCKERS+=("$*"); }
call_or_fail() {
local address="$1"
local signature="$2"
shift 2
cast call "$address" "$signature" "$@" --rpc-url "$RPC_URL" 2>/dev/null
}
call_or_placeholder() {
local address="$1"
local signature="$2"
shift 2
cast call "$address" "$signature" "$@" --rpc-url "$RPC_URL" 2>/dev/null || printf '__CALL_FAILED__'
}
trim_quotes() {
local value="$1"
value="${value#\"}"
value="${value%\"}"
printf '%s' "$value"
}
run_local_suite() {
local smom_root="${PROJECT_ROOT}/smom-dbis-138"
need_cmd forge
(
cd "$smom_root"
rm -f cache/solidity-files-cache.json
forge test --match-contract CompliantFiatTokenV2Test
)
}
check_token() {
local label="$1"
local address="$2"
local expected_symbol="$3"
local expected_currency="$4"
printf '\n=== %s ===\n' "$label"
printf 'Address: %s\n' "$address"
local code
code="$(cast code "$address" --rpc-url "$RPC_URL" 2>/dev/null || true)"
if [[ -z "$code" || "$code" == "0x" ]]; then
block "$label has no bytecode on Chain 138 ($address)"
return
fi
ok "$label bytecode present."
local name symbol version_tag currency forward_canonical asset_id asset_version_id domain_separator
name="$(trim_quotes "$(call_or_fail "$address" 'name()(string)')")"
symbol="$(trim_quotes "$(call_or_fail "$address" 'symbol()(string)')")"
version_tag="$(trim_quotes "$(call_or_fail "$address" 'versionTag()(string)')")"
currency="$(trim_quotes "$(call_or_fail "$address" 'currencyCode()(string)')")"
forward_canonical="$(call_or_fail "$address" 'forwardCanonical()(bool)')"
asset_id="$(call_or_fail "$address" 'assetId()(bytes32)')"
asset_version_id="$(call_or_fail "$address" 'assetVersionId()(bytes32)')"
domain_separator="$(call_or_fail "$address" 'DOMAIN_SEPARATOR()(bytes32)')"
printf 'name: %s\n' "$name"
printf 'symbol: %s\n' "$symbol"
printf 'versionTag: %s\n' "$version_tag"
printf 'currencyCode: %s\n' "$currency"
printf 'forwardCanonical: %s\n' "$forward_canonical"
printf 'assetId: %s\n' "$asset_id"
printf 'assetVersionId: %s\n' "$asset_version_id"
printf 'DOMAIN_SEPARATOR: %s\n' "$domain_separator"
[[ "$symbol" == "$expected_symbol" ]] || block "$label symbol mismatch (expected $expected_symbol, got $symbol)"
[[ "$currency" == "$expected_currency" ]] || block "$label currencyCode mismatch (expected $expected_currency, got $currency)"
[[ "$version_tag" == "2" ]] || block "$label versionTag is not 2 (got $version_tag)"
[[ "$domain_separator" != "0x0000000000000000000000000000000000000000000000000000000000000000" ]] || \
block "$label DOMAIN_SEPARATOR is zero"
local registry_active asset_type
registry_active="$(call_or_fail "$REGISTRY" 'isAssetActive(address)(bool)' "$address")"
asset_type="$(call_or_fail "$REGISTRY" 'getAssetType(address)(uint8)' "$address")"
printf 'registryActive: %s\n' "$registry_active"
printf 'registryAssetType: %s\n' "$asset_type"
[[ "$registry_active" == "true" ]] || block "$label is not active in UniversalAssetRegistry"
[[ "$asset_type" == "2" ]] || block "$label is not registered as AssetType.GRU (expected 2, got $asset_type)"
if [[ "$forward_canonical" != "true" ]]; then
block "$label is deployed and GRU-registered, but forwardCanonical is still false"
fi
local symbol_display token_uri legacy_aliases
symbol_display="$(trim_quotes "$(call_or_placeholder "$address" 'symbolDisplay()(string)')")"
token_uri="$(trim_quotes "$(call_or_placeholder "$address" 'tokenURI()(string)')")"
legacy_aliases="$(call_or_placeholder "$address" 'legacyAliases()(string[])')"
printf 'symbolDisplay: %s\n' "$symbol_display"
printf 'tokenURI: %s\n' "${token_uri:-<empty>}"
printf 'legacyAliases: %s\n' "$legacy_aliases"
if [[ -z "$token_uri" ]]; then
block "$label tokenURI is empty"
elif [[ "$token_uri" != ipfs://* ]]; then
block "$label tokenURI is not an ipfs:// URI ($token_uri)"
fi
local required_surface=(
"governanceProfileId()(bytes32)"
"supervisionProfileId()(bytes32)"
"storageNamespace()(bytes32)"
"governanceController()(address)"
"primaryJurisdiction()(string)"
"regulatoryDisclosureURI()(string)"
"reportingURI()(string)"
"canonicalUnderlyingAsset()(address)"
"supervisionRequired()(bool)"
"governmentApprovalRequired()(bool)"
"minimumUpgradeNoticePeriod()(uint256)"
"wrappedTransport()(bool)"
)
local fn value
for fn in "${required_surface[@]}"; do
value="$(call_or_placeholder "$address" "$fn")"
if [[ "$value" == "__CALL_FAILED__" ]]; then
block "$label is missing required GRU v2 surface: $fn"
else
printf '%s => %s\n' "$fn" "$value"
fi
done
}
audit_registry_orphans() {
local raw
raw="$(call_or_placeholder "$REGISTRY" 'getAssetsByType(uint8)(address[])' 2)"
if [[ "$raw" == "__CALL_FAILED__" ]]; then
warn "Could not enumerate AssetType.GRU entries from UniversalAssetRegistry."
return
fi
raw="${raw#[}"
raw="${raw%]}"
local registry_addresses=()
local item address code
IFS=',' read -r -a registry_addresses <<< "$raw"
for item in "${registry_addresses[@]}"; do
address="$(printf '%s' "$item" | xargs)"
[[ -z "$address" ]] && continue
code="$(cast code "$address" --rpc-url "$RPC_URL" 2>/dev/null || true)"
if [[ -z "$code" || "$code" == "0x" ]]; then
warn "UniversalAssetRegistry has an active GRU entry with no bytecode: $address"
fi
done
}
printf '=== GRU v2 Chain 138 readiness ===\n'
printf 'RPC: %s\n' "$RPC_URL"
printf 'UniversalAssetRegistry: %s\n' "$REGISTRY"
printf 'cUSDT V2: %s\n' "$CUSDT_V2"
printf 'cUSDC V2: %s\n' "$CUSDC_V2"
if [[ "$RUN_LOCAL_TESTS" == "1" ]]; then
printf '\nRunning local CompliantFiatTokenV2 Foundry suite...\n'
run_local_suite
ok "Local CompliantFiatTokenV2 suite passed."
else
warn "Skipping local Foundry suite. Re-run with --run-local-tests or RUN_LOCAL_TESTS=1 to include it."
fi
check_token "cUSDT V2" "$CUSDT_V2" "cUSDT" "USD"
check_token "cUSDC V2" "$CUSDC_V2" "cUSDC" "USD"
audit_registry_orphans
printf '\n=== Summary ===\n'
printf 'Warnings: %s\n' "${#WARNINGS[@]}"
printf 'Blockers: %s\n' "${#BLOCKERS[@]}"
if [[ "${#WARNINGS[@]}" -gt 0 ]]; then
printf '\nWarnings:\n'
for item in "${WARNINGS[@]}"; do
printf ' - %s\n' "$item"
done
fi
if [[ "${#BLOCKERS[@]}" -gt 0 ]]; then
printf '\nPromotion blockers:\n'
for item in "${BLOCKERS[@]}"; do
printf ' - %s\n' "$item"
done
if [[ "$REPORT_ONLY" -eq 1 ]]; then
exit 0
fi
exit 1
fi
ok "GRU v2 assets are ready for forward-canonical promotion on Chain 138."