#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" PROJECT_ROOT="$(cd "$REPO_ROOT/.." && pwd)" BUNDLE_JSON="$REPO_ROOT/config/gas-pmm-execution-bundle.json" OUT_DIR="$PROJECT_ROOT/reports/status" OUT_JSON="$OUT_DIR/gas-pmm-execution-bundle-latest.json" OUT_MD="$OUT_DIR/gas-pmm-execution-bundle-latest.md" source "$REPO_ROOT/scripts/lib/deployment/dotenv.sh" load_deployment_env --repo-root "$REPO_ROOT" mkdir -p "$OUT_DIR" json_escape() { jq -Rn --arg v "${1:-}" '$v' } resolve_env_from_list() { local joined="${1:-}" local value="" local key [[ -z "$joined" ]] && return 0 IFS='|' read -r -a keys <<< "$joined" for key in "${keys[@]}"; do if [[ -n "${!key:-}" ]]; then value="${!key}" break fi done printf '%s' "$value" } hex_to_addr() { local value="${1#0x}" [[ ${#value} -ge 40 ]] || return 1 printf '0x%s\n' "${value: -40}" } code_status() { local rpc="$1" local address="$2" if [[ -z "$rpc" || -z "$address" ]]; then printf 'missing' return fi local code="" code="$(timeout 12s cast code --rpc-url "$rpc" "$address" 2>/dev/null || true)" if [[ -n "$code" && "$code" != "0x" ]]; then printf 'has_code' else printf 'no_code' fi } symbol_call() { local rpc="$1" local address="$2" local value value="$(timeout 8s cast call --rpc-url "$rpc" "$address" "symbol()(string)" 2>/dev/null || true)" value="${value#\"}" value="${value%\"}" printf '%s' "$value" } normalize_key() { printf '%s' "$1" | tr '[:lower:]- ' '[:upper:]__' } append_finding() { local finding="$1" if [[ -n "$FINDINGS_JOINED" ]]; then FINDINGS_JOINED+="|$finding" else FINDINGS_JOINED="$finding" fi } emit_findings_json() { local joined="${1:-}" if [[ -z "$joined" ]]; then printf '[]' return fi jq -Rn --arg joined "$joined" '$joined | split("|") | map(select(length > 0))' } rollout_order_json="$(jq -c '[.chains[] | {chainId, network}]' "$BUNDLE_JSON")" generated_at="$(date -u +"%Y-%m-%dT%H:%M:%SZ")" json_file="$(mktemp)" md_file="$(mktemp)" { echo "{" echo " \"generatedAt\": $(json_escape "$generated_at")," echo " \"bundle\": $(jq '.bundleName' "$BUNDLE_JSON")," echo " \"description\": $(jq '.description' "$BUNDLE_JSON")," echo " \"poolDefaults\": $(jq '.poolDefaults' "$BUNDLE_JSON")," echo " \"rolloutOrder\": $rollout_order_json," echo " \"chains\": [" } >"$json_file" { echo "# Gas PMM Execution Bundle" echo echo "Generated at: \`$generated_at\`" echo echo "This bundle covers the remaining \`22\` planned gas-family DODO PMM rows across \`11\` public chains." echo echo "Execution posture:" echo echo "- Each chain has two target pools: wrapped-native self-quote and wrapped-native versus stable." echo "- The current expected pool addresses are still scaffold slots, so \`no_code\` is the normal pre-deploy state." echo "- Stable-quote pool creation needs a fresh \`STABLE_PRICE_1E18\` input at execution time." echo "- Wrapped-native quote defaults in this bundle use the repo's canonical or documented live contracts instead of the old \`0xaa...\` placeholders." echo "- The deploy step reuses the legacy integration constructor slots; those seed addresses are only deployment anchors, while the gas pairs themselves are created through generic \`createPool(...)\` calls." } >"$md_file" first_chain=1 chain_count=0 ready_count=0 blocked_count=0 while IFS= read -r chain_row; do chain_id="$(jq -r '.chainId' <<<"$chain_row")" network="$(jq -r '.network' <<<"$chain_row")" chain_key="$(jq -r '.chainKey' <<<"$chain_row")" rpc_envs_joined="$(jq -r '.rpcEnv | join("|")' <<<"$chain_row")" integration_env="$(jq -r '.integrationEnv' <<<"$chain_row")" dvm_envs_joined="$(jq -r '.dodoVendingMachineEnv | join("|")' <<<"$chain_row")" rpc="$(resolve_env_from_list "$rpc_envs_joined")" integration="${!integration_env:-}" dvm="$(resolve_env_from_list "$dvm_envs_joined")" base_symbol="$(jq -r '.baseToken.symbol' <<<"$chain_row")" base_address="$(jq -r '.baseToken.address' <<<"$chain_row")" wrapped_symbol="$(jq -r '.wrappedNativeQuote.symbol' <<<"$chain_row")" wrapped_envs_joined="$(jq -r '.wrappedNativeQuote.env | join("|")' <<<"$chain_row")" wrapped_default="$(jq -r '.wrappedNativeQuote.default' <<<"$chain_row")" wrapped_note="$(jq -r '.wrappedNativeQuote.note' <<<"$chain_row")" wrapped_address="$(resolve_env_from_list "$wrapped_envs_joined")" wrapped_address="${wrapped_address:-$wrapped_default}" stable_symbol="$(jq -r '.stableQuote.symbol' <<<"$chain_row")" stable_envs_joined="$(jq -r '.stableQuote.env | join("|")' <<<"$chain_row")" stable_default="$(jq -r '.stableQuote.default' <<<"$chain_row")" stable_note="$(jq -r '.stableQuote.note' <<<"$chain_row")" stable_address="$(resolve_env_from_list "$stable_envs_joined")" stable_address="${stable_address:-$stable_default}" integration_status="$(code_status "$rpc" "$integration")" dvm_status="$(code_status "$rpc" "$dvm")" base_status="$(code_status "$rpc" "$base_address")" wrapped_status="$(code_status "$rpc" "$wrapped_address")" stable_status="$(code_status "$rpc" "$stable_address")" wrapped_pair_row="$(jq -c '.pairs[] | select(.quoteSymbol == $quote)' --arg quote "$wrapped_symbol" <<<"$chain_row")" stable_pair_row="$(jq -c '.pairs[] | select(.quoteSymbol == $quote)' --arg quote "$stable_symbol" <<<"$chain_row")" wrapped_pair_name="$(jq -r '.pair' <<<"$wrapped_pair_row")" stable_pair_name="$(jq -r '.pair' <<<"$stable_pair_row")" wrapped_pool_expected="$(jq -r '.expectedPoolAddress' <<<"$wrapped_pair_row")" stable_pool_expected="$(jq -r '.expectedPoolAddress' <<<"$stable_pair_row")" wrapped_pool_status="$(code_status "$rpc" "$wrapped_pool_expected")" stable_pool_status="$(code_status "$rpc" "$stable_pool_expected")" FINDINGS_JOINED="" [[ -z "$rpc" ]] && append_finding "missing_rpc" [[ "$dvm_status" != "has_code" ]] && append_finding "missing_or_invalid_dodo_vending_machine" [[ "$base_status" != "has_code" ]] && append_finding "gas_mirror_base_missing_or_no_code" [[ "$wrapped_status" != "has_code" ]] && append_finding "wrapped_native_quote_missing_or_no_code" [[ "$stable_status" != "has_code" ]] && append_finding "stable_quote_missing_or_no_code" if [[ -n "$integration" && "$integration_status" == "no_code" ]]; then append_finding "integration_env_set_but_no_code" fi if [[ -z "$integration" || "$integration_status" != "has_code" ]]; then append_finding "integration_needs_deploy" fi [[ "$wrapped_pool_status" != "has_code" ]] && append_finding "wrapped_native_pool_not_live" [[ "$stable_pool_status" != "has_code" ]] && append_finding "stable_quote_pool_not_live" readiness="blocked" if [[ -n "$rpc" && "$dvm_status" == "has_code" && "$base_status" == "has_code" && "$wrapped_status" == "has_code" && "$stable_status" == "has_code" ]]; then readiness="ready_for_execution" fi if [[ "$readiness" == "ready_for_execution" ]]; then ready_count=$((ready_count + 1)) else blocked_count=$((blocked_count + 1)) fi chain_count=$((chain_count + 1)) normalized_chain_key="$(normalize_key "$chain_key")" forge_profile="default" if [[ "$chain_id" == "25" ]]; then forge_profile="cronos_legacy" fi dvm_primary_env="$(jq -r '.dodoVendingMachineEnv[0]' <<<"$chain_row")" deploy_cmd=$(cat <>"$json_file" fi first_chain=0 cat >>"$json_file" <>"$md_file" done < <(jq -c '.chains[]' "$BUNDLE_JSON") { echo echo " ]," echo " \"summary\": {" echo " \"chains\": $chain_count," echo " \"pairs\": $((chain_count * 2))," echo " \"readyForExecution\": $ready_count," echo " \"blocked\": $blocked_count" echo " }" echo "}" } >>"$json_file" jq . "$json_file" >"$OUT_JSON" mv "$md_file" "$OUT_MD" rm -f "$json_file" echo "Wrote:" echo " $OUT_JSON" echo " $OUT_MD"