Files
proxmox/scripts/deployment/run-engine-x-univ2-public-indexed-loop.sh
defiQUG 4ebf2d7902
Some checks failed
Deploy to Phoenix / validate (push) Failing after 1s
Deploy to Phoenix / deploy (push) Has been skipped
Deploy to Phoenix / deploy-atomic-swap-dapp (push) Has been skipped
Deploy to Phoenix / cloudflare (push) Has been skipped
chore(repo): sync operator workspace (config, scripts, docs, multi-chain)
Add optional Cosmos/Engine-X/act-runner templates, CWUSDC/EI-matrix tooling,
non-EVM route planner in multi-chain-execution (tests passing), token list and
extraction updates, and documentation (MetaMask matrix, GRU/CWUSDC packets).

Ignore institutional evidence tarballs/sha256 under reports/status.

Validated with: bash scripts/verify/run-all-validation.sh --skip-genesis

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 16:25:08 -07:00

170 lines
8.2 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
# shellcheck source=/home/intlc/projects/proxmox/scripts/lib/load-project-env.sh
source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh"
# shellcheck source=/home/intlc/projects/proxmox/scripts/lib/mev-protection.sh
source "${PROJECT_ROOT}/scripts/lib/mev-protection.sh"
: "${ETHEREUM_MAINNET_RPC:?ETHEREUM_MAINNET_RPC is required}"
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
USDC="${USDC_MAINNET:-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48}"
PAIR="${MAINNET_CWUSDC_USDC_UNIV2_PAIR:-0xC28706F899266b36BC43cc072b3a921BDf2C48D9}"
ROUTER="${CHAIN_1_UNISWAP_V2_ROUTER:-0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D}"
TARGET_USDC_OUT_RAW="${TARGET_USDC_OUT_RAW:-10000}"
SLIPPAGE_BPS="${SLIPPAGE_BPS:-100}"
DEADLINE_SECONDS="${DEADLINE_SECONDS:-900}"
EXECUTE="${EXECUTE:-0}"
STAMP="${ENGINE_X_UNIV2_LOOP_STAMP:-$(date -u +%Y%m%dT%H%M%SZ)}"
OUT_JSON="${OUT_JSON:-reports/status/engine-x-univ2-public-indexed-loop-${STAMP}.json}"
LATEST_JSON="${LATEST_JSON:-reports/status/engine-x-univ2-public-indexed-loop-latest.json}"
if [[ -n "${PRIVATE_KEY:-}" ]]; then
SIGNER="$(cast wallet address --private-key "${PRIVATE_KEY}")"
else
SIGNER="${DEPLOYER_ADDRESS:-}"
fi
if [[ -z "${SIGNER}" ]]; then
echo "Set PRIVATE_KEY or DEPLOYER_ADDRESS" >&2
exit 1
fi
if [[ "${EXECUTE}" == "1" && -z "${PRIVATE_KEY:-}" ]]; then
echo "PRIVATE_KEY is required when EXECUTE=1" >&2
exit 1
fi
TOKEN0="$(cast call "${PAIR}" 'token0()(address)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | grep -oE '0x[a-fA-F0-9]{40}' | head -1)"
TOKEN1="$(cast call "${PAIR}" 'token1()(address)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | grep -oE '0x[a-fA-F0-9]{40}' | head -1)"
if [[ "${TOKEN0,,}" != "${CWUSDC,,}" || "${TOKEN1,,}" != "${USDC,,}" ]]; then
echo "Configured pair is not token0=cWUSDC/token1=USDC: ${PAIR}" >&2
exit 1
fi
RESERVES_BEFORE="$(cast call "${PAIR}" 'getReserves()(uint112,uint112,uint32)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | tr '\n' ' ')"
CW_BAL_BEFORE="$(cast call "${CWUSDC}" 'balanceOf(address)(uint256)' "${SIGNER}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
USDC_BAL_BEFORE="$(cast call "${USDC}" 'balanceOf(address)(uint256)' "${SIGNER}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
CW_ALLOW_BEFORE="$(cast call "${CWUSDC}" 'allowance(address,address)(uint256)' "${SIGNER}" "${ROUTER}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
USDC_ALLOW_BEFORE="$(cast call "${USDC}" 'allowance(address,address)(uint256)' "${SIGNER}" "${ROUTER}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
ETH_BEFORE="$(cast balance "${SIGNER}" --rpc-url "${ETHEREUM_MAINNET_RPC}")"
GAS_PRICE_WEI="$(cast gas-price --rpc-url "${ETHEREUM_MAINNET_RPC}")"
BLOCK_BEFORE="$(cast block-number --rpc-url "${ETHEREUM_MAINNET_RPC}")"
CW_IN_RAW="$(cast call --json "${ROUTER}" 'getAmountsIn(uint256,address[])(uint256[])' "${TARGET_USDC_OUT_RAW}" "[${CWUSDC},${USDC}]" --rpc-url "${ETHEREUM_MAINNET_RPC}" | jq -r '.[0][0]')"
ROUNDTRIP_CW_OUT_RAW="$(cast call --json "${ROUTER}" 'getAmountsOut(uint256,address[])(uint256[])' "${TARGET_USDC_OUT_RAW}" "[${USDC},${CWUSDC}]" --rpc-url "${ETHEREUM_MAINNET_RPC}" | jq -r '.[0][-1]')"
MAX_CW_IN_RAW="$(( CW_IN_RAW * (10000 + SLIPPAGE_BPS) / 10000 + 1 ))"
MIN_CW_BACK_RAW="$(( ROUNDTRIP_CW_OUT_RAW * (10000 - SLIPPAGE_BPS) / 10000 ))"
if (( CW_BAL_BEFORE < MAX_CW_IN_RAW )); then
echo "Insufficient cWUSDC: need ${MAX_CW_IN_RAW}, have ${CW_BAL_BEFORE}" >&2
exit 1
fi
cat <<EOF
Engine X UniV2 public indexed loop plan
mode: ${EXECUTE}
pair: ${PAIR}
router: ${ROUTER}
signer: ${SIGNER}
target USDC out raw: ${TARGET_USDC_OUT_RAW}
cWUSDC max input raw: ${MAX_CW_IN_RAW}
expected cWUSDC input raw: ${CW_IN_RAW}
expected cWUSDC back raw: ${ROUNDTRIP_CW_OUT_RAW}
min cWUSDC back raw: ${MIN_CW_BACK_RAW}
reserves before: ${RESERVES_BEFORE}
EOF
mkdir -p "$(dirname "${OUT_JSON}")"
python3 - "${OUT_JSON}" "${LATEST_JSON}" \
"${EXECUTE}" "${STAMP}" "${BLOCK_BEFORE}" "${GAS_PRICE_WEI}" "${SIGNER}" "${PAIR}" "${ROUTER}" \
"${CWUSDC}" "${USDC}" "${TARGET_USDC_OUT_RAW}" "${CW_IN_RAW}" "${MAX_CW_IN_RAW}" \
"${ROUNDTRIP_CW_OUT_RAW}" "${MIN_CW_BACK_RAW}" "${RESERVES_BEFORE}" "${CW_BAL_BEFORE}" "${USDC_BAL_BEFORE}" \
"${CW_ALLOW_BEFORE}" "${USDC_ALLOW_BEFORE}" "${ETH_BEFORE}" <<'PY'
import json
from pathlib import Path
import sys
(
out_json, latest_json, execute, stamp, block, gas_price, signer, pair, router, cw, usdc,
target, cw_in, max_cw_in, cw_back, min_cw_back, reserves, cw_bal, usdc_bal, cw_allow,
usdc_allow, eth,
) = sys.argv[1:]
payload = {
"schema": "engine-x-univ2-public-indexed-loop/v1",
"executed": execute == "1",
"stamp": stamp,
"blockBefore": block,
"gasPriceWei": gas_price,
"signer": signer,
"pair": pair,
"router": router,
"tokens": {"cwusdc": cw, "usdc": usdc},
"targetUsdcOutRaw": target,
"expectedCwusdcInputRaw": cw_in,
"maxCwusdcInputRaw": max_cw_in,
"expectedCwusdcBackRaw": cw_back,
"minCwusdcBackRaw": min_cw_back,
"reservesBefore": reserves,
"balancesBefore": {"ethWei": eth, "cwusdcRaw": cw_bal, "usdcRaw": usdc_bal},
"allowancesBefore": {"cwusdcRaw": cw_allow, "usdcRaw": usdc_allow},
"transactions": {},
}
Path(out_json).write_text(json.dumps(payload, indent=2) + "\n")
Path(latest_json).write_text(json.dumps(payload, indent=2) + "\n")
PY
if [[ "${EXECUTE}" != "1" ]]; then
cat <<EOF
Dry-run only. To broadcast this exact public indexed loop:
EXECUTE=1 TARGET_USDC_OUT_RAW=${TARGET_USDC_OUT_RAW} SLIPPAGE_BPS=${SLIPPAGE_BPS} \\
bash scripts/deployment/run-engine-x-univ2-public-indexed-loop.sh
EOF
exit 0
fi
mev_require_private_for_action "engine-x-univ2-public-indexed-loop"
DEADLINE="$(( $(date +%s) + DEADLINE_SECONDS ))"
CW_APPROVE_TX=""
USDC_APPROVE_TX=""
FORWARD_TX=""
REVERSE_TX=""
if (( CW_ALLOW_BEFORE < MAX_CW_IN_RAW )); then
CW_APPROVE_TX="$(mev_cast_send "${CWUSDC}" 'approve(address,uint256)(bool)' "${ROUTER}" "${MAX_CW_IN_RAW}" --json | jq -r '.transactionHash')"
fi
FORWARD_TX="$(mev_cast_send "${ROUTER}" 'swapTokensForExactTokens(uint256,uint256,address[],address,uint256)' "${TARGET_USDC_OUT_RAW}" "${MAX_CW_IN_RAW}" "[${CWUSDC},${USDC}]" "${SIGNER}" "${DEADLINE}" --json | jq -r '.transactionHash')"
USDC_ALLOW_AFTER_FORWARD="$(cast call "${USDC}" 'allowance(address,address)(uint256)' "${SIGNER}" "${ROUTER}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
if (( USDC_ALLOW_AFTER_FORWARD < TARGET_USDC_OUT_RAW )); then
USDC_APPROVE_TX="$(mev_cast_send "${USDC}" 'approve(address,uint256)(bool)' "${ROUTER}" "${TARGET_USDC_OUT_RAW}" --json | jq -r '.transactionHash')"
fi
REVERSE_TX="$(mev_cast_send "${ROUTER}" 'swapExactTokensForTokens(uint256,uint256,address[],address,uint256)' "${TARGET_USDC_OUT_RAW}" "${MIN_CW_BACK_RAW}" "[${USDC},${CWUSDC}]" "${SIGNER}" "${DEADLINE}" --json | jq -r '.transactionHash')"
RESERVES_AFTER="$(cast call "${PAIR}" 'getReserves()(uint112,uint112,uint32)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | tr '\n' ' ')"
CW_BAL_AFTER="$(cast call "${CWUSDC}" 'balanceOf(address)(uint256)' "${SIGNER}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
USDC_BAL_AFTER="$(cast call "${USDC}" 'balanceOf(address)(uint256)' "${SIGNER}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
ETH_AFTER="$(cast balance "${SIGNER}" --rpc-url "${ETHEREUM_MAINNET_RPC}")"
python3 - "${OUT_JSON}" "${LATEST_JSON}" "${CW_APPROVE_TX}" "${FORWARD_TX}" "${USDC_APPROVE_TX}" "${REVERSE_TX}" "${RESERVES_AFTER}" "${CW_BAL_AFTER}" "${USDC_BAL_AFTER}" "${ETH_AFTER}" <<'PY'
import json
from pathlib import Path
import sys
out_json, latest_json, cw_approve, forward, usdc_approve, reverse, reserves, cw_bal, usdc_bal, eth = sys.argv[1:]
payload = json.loads(Path(out_json).read_text())
payload["executed"] = True
payload["transactions"] = {
"cwusdcApprove": cw_approve or None,
"forwardCwusdcToUsdc": forward,
"usdcApprove": usdc_approve or None,
"reverseUsdcToCwusdc": reverse,
}
payload["reservesAfter"] = reserves
payload["balancesAfter"] = {"ethWei": eth, "cwusdcRaw": cw_bal, "usdcRaw": usdc_bal}
Path(out_json).write_text(json.dumps(payload, indent=2) + "\n")
Path(latest_json).write_text(json.dumps(payload, indent=2) + "\n")
print(json.dumps(payload["transactions"], indent=2))
PY