Files
proxmox/scripts/verify/sweep-flash-selectors-chain138.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

164 lines
5.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# Read-only: scan deployed bytecode (Chain 138) for common flash / callback entrypoints.
# Address source: config/smart-contracts-master.json (chains.138.contracts) plus optional extras.
#
# Usage:
# RPC_URL_138=https://rpc-core.d-bis.org bash scripts/verify/sweep-flash-selectors-chain138.sh
# OUT_JSON=path/to/flash_candidates.json RPC_URL_138=... bash scripts/verify/sweep-flash-selectors-chain138.sh
#
# Requires: cast, jq. Does not use cast selectors --resolve (no OpenChain); matches 4-byte selectors only.
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
JSON="${ROOT}/config/smart-contracts-master.json"
RPC="${RPC_URL_138:-https://rpc-core.d-bis.org}"
OUT_JSON="${OUT_JSON:-${ROOT}/config/flash_candidates-chain138.json}"
CHAIN_KEY="${CHAIN_KEY:-138}"
if ! command -v cast >/dev/null || ! command -v jq >/dev/null; then
echo "ERROR: need cast and jq on PATH" >&2
exit 1
fi
if [[ ! -f "$JSON" ]]; then
echo "ERROR: missing $JSON" >&2
exit 1
fi
# Workspace-canonical PMM addresses (may differ from smart-contracts-master.json); always merged for sweep.
EXTRA_ADDRS=(
"0x5BDc62f1ae7D630c37A8B363a1d49845356Ee72d"
"0xff8d3b8fDF7B112759F076B69f4271D4209C0849"
"0x6fc60DEDc92a2047062294488539992710b99D71"
"0x9f74Be42725f2Aa072a9E0CdCce0E7203C510263"
"0xBe9e0B2d4cF6A3b2994d6f2f0904D2B165eB8ffC"
"0xD084b68cB4B1ef2cBA09CF99FB1B6552fd9b4859"
"0x89F7a1fcbBe104BeE96Da4b4b6b7d3AF85f7E661"
)
declare -A SIG_OF
while IFS= read -r line; do
sel="${line%%$'\t'*}"
sig="${line#*$'\t'}"
sel_lc=$(echo "$sel" | tr '[:upper:]' '[:lower:]')
SIG_OF[$sel_lc]="$sig"
done <<'EOF'
0xd0a494e4 flashLoan(uint256,uint256,address,bytes)
0xadf51de1 flashLoan(address,uint256,address,bytes)
0xf859ddd7 flashLoan(address,uint256,uint256,address,bytes)
0x5cffe9de flashLoan(address,address,uint256,bytes)
0x5c38449e flashLoan(address,address[],uint256[],bytes)
0xf740f328 flash(address,uint256,bytes)
0x10d1e85c uniswapV2Call(address,uint256,uint256,bytes)
0x244dac6e executeOperation(address,address,address,uint256,uint256,bytes)
0xfc08f9f6 executeOperation(address[],uint256[],uint256[],address,address,bytes)
0x3e0a794c operateAction(uint8,uint256,bytes)
0x2b2d17ad flashLoanSimple(address,uint256,bytes,uint16)
0x613255ab maxFlashLoan(address)(uint256)
0x88e492ab flashFees(address,address)(uint256)
0xeb2021c3 DVMFlashLoanCall(address,uint256,uint256,bytes)
0x4d7f652f DPPFlashLoanCall(address,uint256,uint256,bytes)
0x2eaeb2e6 DSPFlashLoanCall(address,uint256,uint256,bytes)
EOF
mapfile -t PAIRS < <(
jq -r --arg c "$CHAIN_KEY" '.chains[$c].contracts // {} | to_entries[] | "\(.key)\t\(.value)"' "$JSON"
)
for a in "${EXTRA_ADDRS[@]}"; do
PAIRS+=("EXTRA_CANONICAL"$'\t'"$a")
done
declare -A SEEN_ADDR
declare -a SCAN_ROWS=()
declare -a CANDIDATE_JSON=()
declare -a NO_CODE=()
declare -a ERRORS=()
cid=$(cast chain-id --rpc-url "$RPC" 2>/dev/null || echo "")
for row in "${PAIRS[@]}"; do
name="${row%%$'\t'*}"
addr="${row#*$'\t'}"
addr_lc=$(echo "$addr" | tr '[:upper:]' '[:lower:]')
if [[ -n "${SEEN_ADDR[$addr_lc]:-}" ]]; then
continue
fi
SEEN_ADDR[$addr_lc]=1
if [[ ! "$addr" =~ ^0x[0-9a-fA-F]{40}$ ]]; then
ERRORS+=("{\"name\":\"$name\",\"address\":\"$addr\",\"error\":\"invalid address\"}")
continue
fi
code=$(cast code "$addr" --rpc-url "$RPC" 2>&1) || true
if [[ "$code" == "0x" || -z "$code" ]]; then
NO_CODE+=("{\"name\":\"$(jq -cn --arg n "$name" '$n')\",\"address\":\"$addr\"}")
continue
fi
if [[ "$code" == Error:* ]]; then
ERRORS+=("{\"name\":\"$(jq -cn --arg n "$name" '$n')\",\"address\":\"$addr\",\"error\":$(jq -cn --arg m "$code" '$m')}")
continue
fi
sel_text=$(cast selectors "$code" 2>/dev/null || true)
matched=()
matched_sigs=()
while IFS= read -r sline; do
sel=$(echo "$sline" | awk '{print $1}' | tr '[:upper:]' '[:lower:]')
[[ "$sel" =~ ^0x[0-9a-f]{8}$ ]] || continue
if [[ -n "${SIG_OF[$sel]:-}" ]]; then
matched+=("$sel")
matched_sigs+=("${SIG_OF[$sel]}")
fi
done <<< "$sel_text"
if ((${#matched[@]} > 0)); then
ms=$(printf '%s\n' "${matched_sigs[@]}" | jq -R . | jq -s .)
mc=$(printf '%s\n' "${matched[@]}" | jq -R . | jq -s .)
CANDIDATE_JSON+=("$(jq -nc \
--arg name "$name" \
--arg addr "$addr" \
--argjson ms "$ms" \
--argjson mc "$mc" \
'{name:$name,address:$addr,matchedSelectors:$mc,matchedSignatures:$ms}')")
fi
SCAN_ROWS+=("{\"name\":$(jq -cn --arg n "$name" '$n'),\"address\":\"$addr\",\"bytecodeHexChars\":$((${#code} - 2)),\"flashMatchCount\":${#matched[@]}}")
done
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
ref=$(printf '%s\n' "${!SIG_OF[@]}" | sort -u | while read -r s; do
jq -nc --arg sel "$s" --arg sig "${SIG_OF[$s]}" '{selector:$sel,signature:$sig}'
done | jq -s .)
candidates_arr=$(printf '%s\n' "${CANDIDATE_JSON[@]}" | jq -s .)
scanned_arr=$(printf '%s\n' "${SCAN_ROWS[@]}" | jq -s .)
nocode_arr=$(printf '%s\n' "${NO_CODE[@]}" | jq -s .)
errors_arr=$(printf '%s\n' "${ERRORS[@]}" | jq -s .)
jq -nc \
--arg ts "$ts" \
--arg rpc "$RPC" \
--arg chainId "$cid" \
--argjson ref "$ref" \
--argjson candidates "$candidates_arr" \
--argjson scanned "$scanned_arr" \
--argjson noCode "$nocode_arr" \
--argjson errors "$errors_arr" \
'{
schemaVersion: 1,
generatedAt: $ts,
rpcUrl: $rpc,
chainId: ($chainId | tonumber? // $chainId),
description: "Heuristic flash/callback selector scan; false positives possible (e.g. unrelated executeOperation).",
flashSelectorsReference: $ref,
candidates: $candidates,
scannedContracts: $scanned,
emptyBytecode: $noCode,
errors: $errors
}' > "$OUT_JSON"
echo "Wrote $OUT_JSON"
echo "Candidates: $(jq '.candidates | length' "$OUT_JSON")"
jq '.candidates' "$OUT_JSON"