Files
proxmox/scripts/deployment/send-eth-ei-matrix-wallets.sh
defiQUG 4fab998e51
All checks were successful
Deploy to Phoenix / deploy (push) Successful in 9s
chore: sync workspace docs, configs, and submodules
2026-04-18 12:07:15 -07:00

161 lines
5.6 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# Send a random amount between 5 and 9 ETH (inclusive) to each address in
# config/pmm-soak-wallet-grid.json (Elemental Imperium 33×33×6 matrix).
#
# Requires: cast (Foundry), jq, python3. Loads PRIVATE_KEY and RPC via load-project-env.sh.
#
# Usage:
# ./scripts/deployment/send-eth-ei-matrix-wallets.sh [--dry-run] [--limit N] [--offset N]
#
# --dry-run Print planned sends only (no transactions).
# --limit N Process at most N wallets (after offset). Default: all.
# --offset N Skip the first N wallets (resume / partial run).
#
# Gas (Chain 138 / Besu): defaults avoid stuck pending txs from near-zero EIP-1559 caps.
# Override if needed:
# EI_MATRIX_GAS_PRICE=100000000000
# EI_MATRIX_PRIORITY_GAS_PRICE=20000000000
#
# Nonces: each send uses an explicit --nonce from eth_getTransactionCount(..., "pending")
# and increments locally so --async does not race duplicate nonces.
#
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
DRY_RUN=false
LIMIT=""
OFFSET="0"
while [[ $# -gt 0 ]]; do
case "$1" in
--dry-run) DRY_RUN=true; shift ;;
--limit) LIMIT="${2:?}"; shift 2 ;;
--offset) OFFSET="${2:?}"; shift 2 ;;
*) echo "Unknown arg: $1" >&2; exit 1 ;;
esac
done
# shellcheck disable=SC1091
source "$PROJECT_ROOT/scripts/lib/load-project-env.sh"
LOCK_FILE="${PROJECT_ROOT}/reports/status/ei-matrix-eth-send.lock"
mkdir -p "$(dirname "$LOCK_FILE")"
exec 200>"$LOCK_FILE"
if ! flock -n 200; then
echo "Another send-eth-ei-matrix-wallets.sh is already running (lock: $LOCK_FILE)." >&2
exit 1
fi
RPC="${RPC_URL_138:-http://192.168.11.211:8545}"
GRID="$PROJECT_ROOT/config/pmm-soak-wallet-grid.json"
DEPLOYER_CANONICAL="0x4A666F96fC8764181194447A7dFdb7d471b301C8"
# Wei per gas — must exceed stuck-replacement threshold on busy pools (see script header).
EI_MATRIX_GAS_PRICE="${EI_MATRIX_GAS_PRICE:-100000000000}"
EI_MATRIX_PRIORITY_GAS_PRICE="${EI_MATRIX_PRIORITY_GAS_PRICE:-20000000000}"
[[ -f "$GRID" ]] || { echo "Missing $GRID" >&2; exit 1; }
command -v cast &>/dev/null || { echo "cast (Foundry) required" >&2; exit 1; }
command -v jq &>/dev/null || { echo "jq required" >&2; exit 1; }
[[ -n "${PRIVATE_KEY:-}" ]] || { echo "PRIVATE_KEY not set (source smom-dbis-138/.env or root .env)" >&2; exit 1; }
FROM_ADDR=$(cast wallet address --private-key "$PRIVATE_KEY")
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "EI matrix ETH distribution (random 59 ETH per wallet)"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "RPC: $RPC"
echo "Signer: $FROM_ADDR"
echo "Grid: $GRID"
echo "Dry-run: $DRY_RUN"
echo "Offset: $OFFSET Limit: ${LIMIT:-all}"
echo "Gas: maxFee=$EI_MATRIX_GAS_PRICE wei priorityFee=$EI_MATRIX_PRIORITY_GAS_PRICE wei"
echo ""
if [[ "${FROM_ADDR,,}" != "${DEPLOYER_CANONICAL,,}" ]]; then
echo "[WARN] Signer is not canonical deployer $DEPLOYER_CANONICAL — continuing anyway."
echo ""
fi
pending_nonce() {
local resp hex
resp=$(curl -sS -X POST "$RPC" -H "Content-Type: application/json" \
-d "{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionCount\",\"params\":[\"${FROM_ADDR}\",\"pending\"],\"id\":1}" 2>/dev/null) || return 1
hex=$(echo "$resp" | jq -r '.result // empty')
[[ -n "$hex" ]] || return 1
cast to-dec "$hex"
}
random_wei() {
python3 -c "import random; from decimal import Decimal; print(int(Decimal(str(random.uniform(5.0, 9.0))) * 10**18))"
}
ERR_LOG="${PROJECT_ROOT}/reports/status/ei-matrix-eth-send-failures.log"
mkdir -p "$(dirname "$ERR_LOG")"
if ! $DRY_RUN; then
NONCE=$(pending_nonce) || { echo "Could not read pending nonce for $FROM_ADDR" >&2; exit 1; }
echo "Starting nonce (pending): $NONCE"
echo ""
else
NONCE=0
fi
stream_addresses() {
if [[ -n "${LIMIT:-}" ]]; then
jq -r '.wallets[] | .address' "$GRID" | tail -n +$((OFFSET + 1)) | head -n "$LIMIT"
else
jq -r '.wallets[] | .address' "$GRID" | tail -n +$((OFFSET + 1))
fi
}
sent=0
failed=0
idx=$OFFSET
while read -r addr; do
wei=$(random_wei)
eth_approx=$(python3 -c "print(f'{$wei / 1e18:.6f}')")
if $DRY_RUN; then
echo "[dry-run] idx=$idx $addr ${wei} wei (~${eth_approx} ETH)"
else
GP="$EI_MATRIX_GAS_PRICE"
PP="$EI_MATRIX_PRIORITY_GAS_PRICE"
attempt=1
while [[ "$attempt" -le 2 ]]; do
if out=$(cast send "$addr" --value "$wei" --rpc-url "$RPC" --private-key "$PRIVATE_KEY" \
--nonce "$NONCE" \
--async \
--gas-price "$GP" \
--priority-gas-price "$PP" \
2>&1); then
tx=$(echo "$out" | tail -n1)
echo "[ok] idx=$idx nonce=$NONCE $addr ${eth_approx} ETH tx=$tx"
sent=$((sent + 1))
NONCE=$((NONCE + 1))
echo "$idx" > "${PROJECT_ROOT}/reports/status/ei-matrix-eth-send-last-idx.txt"
break
fi
if echo "$out" | grep -q "Replacement transaction underpriced" && [[ "$attempt" -eq 1 ]]; then
GP=$((GP * 2))
PP=$((PP * 2))
NONCE=$(pending_nonce) || true
attempt=$((attempt + 1))
continue
fi
echo "[fail] idx=$idx nonce=$NONCE $addr $out" | tee -a "$ERR_LOG" >&2
failed=$((failed + 1))
NONCE=$(pending_nonce) || true
break
done
fi
idx=$((idx + 1))
done < <(stream_addresses)
echo ""
if $DRY_RUN; then
echo "Dry-run complete (no transactions sent). Indices covered: $OFFSET..$((idx - 1))."
else
echo "Done. Sent: $sent Failed: $failed"
fi