Enhance .env configuration with Infura support and add new RPC endpoints for various networks. Update package.json with new deployment scripts for Engine X. Improve public LP compliance documentation in runbooks and scripts, including guidance for public pair repairs and funding strategies.
All checks were successful
Deploy to Phoenix / validate (push) Successful in 1m11s
Deploy to Phoenix / deploy (push) Successful in 43s
Deploy to Phoenix / deploy-atomic-swap-dapp (push) Successful in 1m32s
phoenix-deploy Deployed to cloudflare-sync
Deploy to Phoenix / cloudflare (push) Successful in 38s

This commit is contained in:
defiQUG
2026-05-07 18:19:37 -07:00
parent ec6217fdc3
commit dd02f4b59b
41 changed files with 3164 additions and 23 deletions

View File

@@ -40,26 +40,26 @@ DEFAULT_ENV = ROOT / "smom-dbis-138" / ".env"
ZERO = "0x0000000000000000000000000000000000000000"
# Defaults when .env has no RPC for a chain (prefer setting INFURA_PROJECT_ID + load-project-env, or per-chain *_RPC in .env).
DEFAULT_RPC: dict[str, str] = {
"1": "https://eth.llamarpc.com",
"1": "https://ethereum.publicnode.com",
"10": "https://mainnet.optimism.io",
"25": "https://evm.cronos.org",
"56": "https://bsc-dataseed.binance.org",
"100": "https://rpc.gnosischain.com",
"137": "https://polygon-rpc.com",
"8453": "https://mainnet.base.org",
"42161": "https://arbitrum-one.publicnode.com",
"42161": "https://arb1.arbitrum.io/rpc",
"42220": "https://forno.celo.org",
"43114": "https://avalanche-c-chain.publicnode.com",
"43114": "https://api.avax.network/ext/bc/C/rpc",
"1111": "https://api.wemix.com",
}
# Extra public RPCs (retry when primary fails — connection resets, rate limits).
RPC_FALLBACKS: dict[str, list[str]] = {
"1": [
"https://ethereum.publicnode.com",
"https://eth.llamarpc.com",
"https://1rpc.io/eth",
"https://rpc.ankr.com/eth",
],
"137": ["https://polygon-bor.publicnode.com", "https://1rpc.io/matic"],
"42161": ["https://arbitrum.llamarpc.com"],
@@ -85,6 +85,58 @@ RPC_KEYS: dict[str, list[str]] = {
}
def _rpc_env_key_set() -> set[str]:
return {k for ks in RPC_KEYS.values() for k in ks} | {
"INFURA_PROJECT_ID",
"INFURA_API_KEY",
"RPC_URL_MAINNET",
}
def merge_rpc_os_into(env: dict[str, str]) -> None:
"""Process env overrides .env for RPC-related keys (so `source load-project-env.sh` applies)."""
for k in _rpc_env_key_set():
v = os.environ.get(k, "").strip()
if v:
env[k] = v
def apply_eth_mainnet_rpc_alias(env: dict[str, str]) -> None:
"""Match load-project-env.sh: dotenv often sets ETH_MAINNET_RPC_URL only."""
if not resolve(env, "ETHEREUM_MAINNET_RPC"):
alt = resolve(env, "ETH_MAINNET_RPC_URL", "")
if alt:
env["ETHEREUM_MAINNET_RPC"] = alt
def apply_infura_rpc_defaults(env: dict[str, str]) -> None:
"""When INFURA_PROJECT_ID or INFURA_API_KEY is set, fill first unset RPC var per supported chain."""
pid = (env.get("INFURA_PROJECT_ID") or env.get("INFURA_API_KEY") or "").strip()
if not pid:
return
def chain_has_rpc(cid: str) -> bool:
return any(resolve(env, k) for k in RPC_KEYS.get(cid, []))
infura_by_chain: dict[str, str] = {
"1": f"https://mainnet.infura.io/v3/{pid}",
"10": f"https://optimism-mainnet.infura.io/v3/{pid}",
"56": f"https://bnb-mainnet.infura.io/v3/{pid}",
"100": f"https://gnosis-mainnet.infura.io/v3/{pid}",
"137": f"https://polygon-mainnet.infura.io/v3/{pid}",
"8453": f"https://base-mainnet.infura.io/v3/{pid}",
"42161": f"https://arbitrum-mainnet.infura.io/v3/{pid}",
"42220": f"https://celo-mainnet.infura.io/v3/{pid}",
"43114": f"https://avalanche-mainnet.infura.io/v3/{pid}",
}
for cid, url in infura_by_chain.items():
if chain_has_rpc(cid):
continue
keys = RPC_KEYS.get(cid, [])
if keys:
env[keys[0]] = url
def load_dotenv(path: Path) -> dict[str, str]:
out: dict[str, str] = {}
if not path.is_file():
@@ -388,6 +440,9 @@ def main() -> int:
args = ap.parse_args()
env = load_dotenv(args.env)
merge_rpc_os_into(env)
apply_eth_mainnet_rpc_alias(env)
apply_infura_rpc_defaults(env)
dep = deployer_address(env, args.deployer)
if not dep:
print("No deployer: set PRIVATE_KEY or DEPLOYER_ADDRESS in .env or pass --deployer", file=sys.stderr)

View File

@@ -0,0 +1,5 @@
#!/usr/bin/env bash
# Resume mainnet cWUSDC EI matrix mints from ei-matrix-cwusdc-mint-last-idx.txt + 1.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
exec "$SCRIPT_DIR/mint-cwusdc-ei-matrix-wallets.sh" --resume-next "$@"

View File

@@ -0,0 +1,89 @@
#!/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"
: "${ETHEREUM_MAINNET_RPC:?ETHEREUM_MAINNET_RPC is required}"
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
USDC="${USDC_MAINNET:-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48}"
FACTORY="${CHAIN_1_UNISWAP_V3_FACTORY:-0x1F98431c8aD98523631AE4a59f267346ea31F984}"
FEE="${ENGINE_X_UNIV3_FEE:-100}"
MAX_ABS_TICK="${ENGINE_X_INDEXED_MAX_ABS_TICK:-100}"
MIN_LIQUIDITY="${ENGINE_X_INDEXED_MIN_LIQUIDITY:-1}"
MAX_PROOF_SWAP_AMOUNT="${ENGINE_X_INDEXED_MAX_PROOF_SWAP_AMOUNT:-1000000}"
VERIFY="${VERIFY:-1}"
EXECUTE="${EXECUTE:-0}"
OWNER="${ENGINE_X_INDEXED_OWNER:-${DEPLOYER_ADDRESS:-}}"
if [[ -n "${PRIVATE_KEY:-}" ]]; then
OWNER="$(cast wallet address --private-key "${PRIVATE_KEY}")"
fi
if [[ -z "${OWNER}" ]]; then
echo "Set PRIVATE_KEY, DEPLOYER_ADDRESS, or ENGINE_X_INDEXED_OWNER" >&2
exit 1
fi
if [[ "${EXECUTE}" == "1" && -z "${PRIVATE_KEY:-}" ]]; then
echo "PRIVATE_KEY is required when EXECUTE=1" >&2
exit 1
fi
TOKEN0="$(printf '%s\n%s\n' "${CWUSDC}" "${USDC}" | tr '[:upper:]' '[:lower:]' | sort | sed -n '1p')"
TOKEN1="$(printf '%s\n%s\n' "${CWUSDC}" "${USDC}" | tr '[:upper:]' '[:lower:]' | sort | sed -n '2p')"
POOL="${ENGINE_X_UNIV3_POOL:-$(cast call "${FACTORY}" 'getPool(address,address,uint24)(address)' "${TOKEN0}" "${TOKEN1}" "${FEE}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | grep -oE '0x[a-fA-F0-9]{40}' | head -1)}"
if [[ "${POOL}" == "0x0000000000000000000000000000000000000000" ]]; then
cat <<EOF
Engine X indexed-liquidity vault deployment blocked
UniV3 cWUSDC/USDC pool is not deployed for fee ${FEE}.
Create/fund the public pool first, then rerun this script.
EOF
exit 0
fi
VERIFY_ARGS=()
if [[ "${VERIFY}" == "1" ]]; then
VERIFY_ARGS+=(--verify)
fi
CREATE_CMD_EXEC=(
forge create
--broadcast
--rpc-url "${ETHEREUM_MAINNET_RPC}"
--private-key "${PRIVATE_KEY:-}"
"${VERIFY_ARGS[@]}"
contracts/flash/DBISEngineXIndexedLiquidityVault.sol:DBISEngineXIndexedLiquidityVault
--constructor-args
"${CWUSDC}" "${USDC}" "${POOL}" "${OWNER}" "${MAX_ABS_TICK}" "${MIN_LIQUIDITY}" "${MAX_PROOF_SWAP_AMOUNT}"
)
cat <<EOF
Engine X indexed-liquidity vault deployment plan
mode: ${EXECUTE}
owner: ${OWNER}
cWUSDC: ${CWUSDC}
USDC: ${USDC}
UniV3 pool: ${POOL}
fee: ${FEE}
max abs tick: ${MAX_ABS_TICK}
min liquidity: ${MIN_LIQUIDITY}
max proof swap amount raw: ${MAX_PROOF_SWAP_AMOUNT}
EOF
if [[ "${EXECUTE}" != "1" ]]; then
cat <<EOF
Dry-run only. Review command:
cd smom-dbis-138
forge create --broadcast --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY" ${VERIFY_ARGS[*]} contracts/flash/DBISEngineXIndexedLiquidityVault.sol:DBISEngineXIndexedLiquidityVault --constructor-args "${CWUSDC}" "${USDC}" "${POOL}" "${OWNER}" "${MAX_ABS_TICK}" "${MIN_LIQUIDITY}" "${MAX_PROOF_SWAP_AMOUNT}"
EOF
exit 0
fi
pushd "${PROJECT_ROOT}/smom-dbis-138" >/dev/null
"${CREATE_CMD_EXEC[@]}"
popd >/dev/null

View File

@@ -0,0 +1,118 @@
#!/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"
: "${ETHEREUM_MAINNET_RPC:?ETHEREUM_MAINNET_RPC is required}"
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
USDC="${USDC_MAINNET:-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48}"
XAUT="${XAUT_MAINNET:-0x68749665FF8D2d112Fa859AA293F07A622782F38}"
XAUT_USD_PRICE6="${ENGINE_X_XAUT_USD_PRICE6:-3226640000}"
LTV_BPS="${ENGINE_X_LTV_BPS:-8000}"
MAX_ROUND_TRIP_LOSS_BPS="${ENGINE_X_MAX_ROUND_TRIP_LOSS_BPS:-100}"
POOL_CWUSDC_RAW="${ENGINE_X_POOL_CWUSDC_RAW:-85763529}"
POOL_USDC_RAW="${ENGINE_X_POOL_USDC_RAW:-85763529}"
LENDER_USDC_RAW="${ENGINE_X_LENDER_USDC_RAW:-5000000}"
FLASH_FEE_BPS="${ENGINE_X_FLASH_FEE_BPS:-5}"
MAX_FLASH_LOAN_RAW="${ENGINE_X_MAX_FLASH_LOAN_RAW:-0}"
SEED_AFTER_DEPLOY="${SEED_AFTER_DEPLOY:-0}"
VERIFY="${VERIFY:-1}"
EXECUTE="${EXECUTE:-0}"
OWNER="${ENGINE_X_OWNER:-${DEPLOYER_ADDRESS:-}}"
if [[ -n "${PRIVATE_KEY:-}" ]]; then
OWNER="$(cast wallet address --private-key "${PRIVATE_KEY}")"
fi
SURPLUS_RECEIVER="${ENGINE_X_SURPLUS_RECEIVER:-${OWNER}}"
if [[ -z "${OWNER}" || -z "${SURPLUS_RECEIVER}" ]]; then
echo "Set PRIVATE_KEY, DEPLOYER_ADDRESS, ENGINE_X_OWNER, and/or ENGINE_X_SURPLUS_RECEIVER" >&2
exit 1
fi
if [[ "${EXECUTE}" == "1" && -z "${PRIVATE_KEY:-}" ]]; then
echo "PRIVATE_KEY is required when EXECUTE=1" >&2
exit 1
fi
VERIFY_ARGS=()
if [[ "${VERIFY}" == "1" ]]; then
VERIFY_ARGS+=(--verify)
fi
CREATE_CMD_EXEC=(
forge create
--broadcast
--rpc-url "${ETHEREUM_MAINNET_RPC}"
--private-key "${PRIVATE_KEY:-}"
"${VERIFY_ARGS[@]}"
contracts/flash/DBISEngineXVirtualBatchVault.sol:DBISEngineXVirtualBatchVault
--constructor-args
"${CWUSDC}" "${USDC}" "${XAUT}" "${OWNER}" "${SURPLUS_RECEIVER}"
"${XAUT_USD_PRICE6}" "${LTV_BPS}" "${MAX_ROUND_TRIP_LOSS_BPS}"
)
cat <<EOF
Engine X v2 Mainnet deployment plan
mode: ${EXECUTE}
owner: ${OWNER}
surplus receiver: ${SURPLUS_RECEIVER}
cWUSDC: ${CWUSDC}
USDC: ${USDC}
XAUt: ${XAUT}
XAUt price6: ${XAUT_USD_PRICE6}
LTV bps: ${LTV_BPS}
max round-trip loss bps: ${MAX_ROUND_TRIP_LOSS_BPS}
default seed: ${POOL_CWUSDC_RAW} cWUSDC raw / ${POOL_USDC_RAW} USDC raw
lender bucket: ${LENDER_USDC_RAW} USDC raw
flash fee bps: ${FLASH_FEE_BPS}
max flash loan raw: ${MAX_FLASH_LOAN_RAW}
EOF
if [[ "${EXECUTE}" != "1" ]]; then
cat <<EOF
Dry-run only. Review commands:
cd smom-dbis-138
forge create --broadcast --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY" ${VERIFY_ARGS[*]} contracts/flash/DBISEngineXVirtualBatchVault.sol:DBISEngineXVirtualBatchVault --constructor-args "${CWUSDC}" "${USDC}" "${XAUT}" "${OWNER}" "${SURPLUS_RECEIVER}" "${XAUT_USD_PRICE6}" "${LTV_BPS}" "${MAX_ROUND_TRIP_LOSS_BPS}"
After deploy, export the new address:
export DBIS_ENGINE_X_V2_VAULT=<deployed-vault-address>
Optional seed/fund/risk controls:
cast send "\$DBIS_ENGINE_X_V2_VAULT" 'setFlashFeeBps(uint256)' "${FLASH_FEE_BPS}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
cast send "\$DBIS_ENGINE_X_V2_VAULT" 'setMaxFlashLoanAmount(uint256)' "${MAX_FLASH_LOAN_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
cast send "${CWUSDC}" 'approve(address,uint256)' "\$DBIS_ENGINE_X_V2_VAULT" "${POOL_CWUSDC_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
cast send "${USDC}" 'approve(address,uint256)' "\$DBIS_ENGINE_X_V2_VAULT" "$((POOL_USDC_RAW + LENDER_USDC_RAW))" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
cast send "\$DBIS_ENGINE_X_V2_VAULT" 'seedPool(uint256,uint256)' "${POOL_CWUSDC_RAW}" "${POOL_USDC_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
cast send "\$DBIS_ENGINE_X_V2_VAULT" 'fundLender(uint256)' "${LENDER_USDC_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
EOF
exit 0
fi
pushd "${PROJECT_ROOT}/smom-dbis-138" >/dev/null
DEPLOY_OUT="$("${CREATE_CMD_EXEC[@]}")"
popd >/dev/null
printf '%s\n' "${DEPLOY_OUT}"
VAULT="$(printf '%s\n' "${DEPLOY_OUT}" | grep -oE 'Deployed to: 0x[a-fA-F0-9]{40}' | awk '{print $3}' | tail -1)"
if [[ -z "${VAULT}" ]]; then
echo "Could not parse deployed vault address" >&2
exit 1
fi
cast send "${VAULT}" 'setFlashFeeBps(uint256)' "${FLASH_FEE_BPS}" --rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
cast send "${VAULT}" 'setMaxFlashLoanAmount(uint256)' "${MAX_FLASH_LOAN_RAW}" --rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
if [[ "${SEED_AFTER_DEPLOY}" == "1" ]]; then
cast send "${CWUSDC}" 'approve(address,uint256)' "${VAULT}" "${POOL_CWUSDC_RAW}" --rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
cast send "${USDC}" 'approve(address,uint256)' "${VAULT}" "$((POOL_USDC_RAW + LENDER_USDC_RAW))" --rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
cast send "${VAULT}" 'seedPool(uint256,uint256)' "${POOL_CWUSDC_RAW}" "${POOL_USDC_RAW}" --rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
cast send "${VAULT}" 'fundLender(uint256)' "${LENDER_USDC_RAW}" --rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
fi
echo "DBIS_ENGINE_X_V2_VAULT=${VAULT}"

View File

@@ -0,0 +1,99 @@
#!/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"
: "${ETHEREUM_MAINNET_RPC:?ETHEREUM_MAINNET_RPC is required}"
XAUT="${XAUT_MAINNET:-0x68749665FF8D2d112Fa859AA293F07A622782F38}"
USDC="${USDC_MAINNET:-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48}"
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
XAUT_USD_PRICE6="${ENGINE_X_XAUT_USD_PRICE6:-3226640000}"
LTV_BPS="${ENGINE_X_BORROW_LTV_BPS:-7500}"
LIQUIDATION_THRESHOLD_BPS="${ENGINE_X_BORROW_LIQUIDATION_THRESHOLD_BPS:-8000}"
MIN_HEALTH_FACTOR_BPS="${ENGINE_X_BORROW_MIN_HEALTH_FACTOR_BPS:-11000}"
LIQUIDATION_BONUS_BPS="${ENGINE_X_BORROW_LIQUIDATION_BONUS_BPS:-500}"
MAX_BORROW_USDC_RAW="${ENGINE_X_BORROW_MAX_USDC_RAW:-0}"
PRICE_SOURCE_HASH="${ENGINE_X_XAUT_PRICE_SOURCE_HASH:-$(cast keccak "dbis-engine-x:xaut-usd-price6:${XAUT_USD_PRICE6}")}"
VERIFY="${VERIFY:-1}"
EXECUTE="${EXECUTE:-0}"
OWNER="${ENGINE_X_BORROW_OWNER:-${DEPLOYER_ADDRESS:-}}"
if [[ -n "${PRIVATE_KEY:-}" ]]; then
OWNER="$(cast wallet address --private-key "${PRIVATE_KEY}")"
fi
if [[ -z "${OWNER}" ]]; then
echo "Set PRIVATE_KEY, DEPLOYER_ADDRESS, or ENGINE_X_BORROW_OWNER" >&2
exit 1
fi
if [[ "${EXECUTE}" == "1" && -z "${PRIVATE_KEY:-}" ]]; then
echo "PRIVATE_KEY is required when EXECUTE=1" >&2
exit 1
fi
VERIFY_ARGS=()
if [[ "${VERIFY}" == "1" ]]; then
VERIFY_ARGS+=(--verify)
fi
CREATE_CMD_EXEC=(
forge create
--broadcast
--rpc-url "${ETHEREUM_MAINNET_RPC}"
--private-key "${PRIVATE_KEY:-}"
"${VERIFY_ARGS[@]}"
contracts/flash/DBISEngineXXautUsdcBorrowVault.sol:DBISEngineXXautUsdcBorrowVault
--constructor-args
"${XAUT}" "${USDC}" "${CWUSDC}" "${OWNER}"
"${XAUT_USD_PRICE6}" "${LTV_BPS}" "${LIQUIDATION_THRESHOLD_BPS}" "${MIN_HEALTH_FACTOR_BPS}"
"${LIQUIDATION_BONUS_BPS}" "${MAX_BORROW_USDC_RAW}" "${PRICE_SOURCE_HASH}"
)
cat <<EOF
Engine X XAUt/USDC borrow vault deployment plan
mode: ${EXECUTE}
owner: ${OWNER}
XAUt: ${XAUT}
USDC: ${USDC}
cWUSDC proof token: ${CWUSDC}
XAUt price6: ${XAUT_USD_PRICE6}
price source hash: ${PRICE_SOURCE_HASH}
LTV bps: ${LTV_BPS}
liquidation threshold bps: ${LIQUIDATION_THRESHOLD_BPS}
min health factor bps: ${MIN_HEALTH_FACTOR_BPS}
liquidation bonus bps: ${LIQUIDATION_BONUS_BPS}
max borrow USDC raw: ${MAX_BORROW_USDC_RAW}
Boundary:
The vault lends only pre-funded official USDC. It does not create USDC and it
does not accept cWUSDC as debt repayment. cWUSDC-sourced repayment proofs still
settle with actual USDC and only attach public swap/audit/peg hashes.
EOF
if [[ "${EXECUTE}" != "1" ]]; then
cat <<EOF
Dry-run only. Review command:
cd smom-dbis-138
forge create --broadcast --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY" ${VERIFY_ARGS[*]} contracts/flash/DBISEngineXXautUsdcBorrowVault.sol:DBISEngineXXautUsdcBorrowVault --constructor-args "${XAUT}" "${USDC}" "${CWUSDC}" "${OWNER}" "${XAUT_USD_PRICE6}" "${LTV_BPS}" "${LIQUIDATION_THRESHOLD_BPS}" "${MIN_HEALTH_FACTOR_BPS}" "${LIQUIDATION_BONUS_BPS}" "${MAX_BORROW_USDC_RAW}" "${PRICE_SOURCE_HASH}"
EOF
exit 0
fi
pushd "${PROJECT_ROOT}/smom-dbis-138" >/dev/null
DEPLOY_OUT="$("${CREATE_CMD_EXEC[@]}")"
popd >/dev/null
printf '%s\n' "${DEPLOY_OUT}"
VAULT="$(printf '%s\n' "${DEPLOY_OUT}" | grep -oE 'Deployed to: 0x[a-fA-F0-9]{40}' | awk '{print $3}' | tail -1)"
if [[ -z "${VAULT}" ]]; then
echo "Could not parse deployed borrow vault address" >&2
exit 1
fi
echo "DBIS_ENGINE_X_XAUT_USDC_BORROW_VAULT=${VAULT}"

View File

@@ -0,0 +1,238 @@
#!/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"
: "${ETHEREUM_MAINNET_RPC:?ETHEREUM_MAINNET_RPC is required}"
VAULT="${ENGINE_X_VAULT:-0x9a22a3e272A364D64240dE6bda796FcA421cA7E9}"
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
USDC="${USDC_MAINNET:-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48}"
FACTORY="${CHAIN_1_UNISWAP_V3_FACTORY:-0x1F98431c8aD98523631AE4a59f267346ea31F984}"
POSITION_MANAGER="${CHAIN_1_UNISWAP_V3_POSITION_MANAGER:-0xC36442b4a4522E871399CD717aBDD847Ab11FE88}"
FEE="${ENGINE_X_UNIV3_FEE:-100}"
TICK_LOWER="${ENGINE_X_UNIV3_TICK_LOWER:--100}"
TICK_UPPER="${ENGINE_X_UNIV3_TICK_UPPER:-100}"
SQRT_PRICE_X96="${ENGINE_X_UNIV3_SQRT_PRICE_X96:-79228162514264337593543950336}"
DEADLINE_SECONDS="${DEADLINE_SECONDS:-1800}"
EXECUTE="${EXECUTE:-0}"
INCLUDE_LENDER_USDC="${INCLUDE_LENDER_USDC:-0}"
MIGRATION_AMOUNT_RAW="${MIGRATION_AMOUNT_RAW:-}"
OWNER="$(cast call "${VAULT}" 'owner()(address)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | grep -oE '0x[a-fA-F0-9]{40}' | head -1)"
SIGNER="${DEPLOYER_ADDRESS:-${OWNER}}"
if [[ -n "${PRIVATE_KEY:-}" ]]; then
SIGNER="$(cast wallet address --private-key "${PRIVATE_KEY}")"
fi
if [[ "${EXECUTE}" == "1" && -z "${PRIVATE_KEY:-}" ]]; then
echo "PRIVATE_KEY is required when EXECUTE=1" >&2
exit 1
fi
if [[ "${EXECUTE}" == "1" && "${SIGNER,,}" != "${OWNER,,}" ]]; then
echo "EXECUTE=1 signer must be the Engine X vault owner" >&2
echo " signer: ${SIGNER}" >&2
echo " owner: ${OWNER}" >&2
exit 1
fi
POOL_CWUSDC_RAW="$(cast call "${VAULT}" 'poolCwusdcReserve()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
POOL_USDC_RAW="$(cast call "${VAULT}" 'poolUsdcReserve()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
LENDER_USDC_RAW="$(cast call "${VAULT}" 'lenderUsdcAvailable()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
VAULT_CWUSDC_RAW="$(cast call "${CWUSDC}" 'balanceOf(address)(uint256)' "${VAULT}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
VAULT_USDC_RAW="$(cast call "${USDC}" 'balanceOf(address)(uint256)' "${VAULT}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
FEE_TICK_SPACING="$(cast call "${FACTORY}" 'feeAmountTickSpacing(uint24)(int24)' "${FEE}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
ACCOUNTING_AWARE_SUPPORTED="0"
if cast call "${VAULT}" 'maxFlashLoan(address)(uint256)' "${USDC}" --rpc-url "${ETHEREUM_MAINNET_RPC}" >/dev/null 2>&1; then
ACCOUNTING_AWARE_SUPPORTED="1"
fi
if [[ "${FEE_TICK_SPACING}" == "0" ]]; then
echo "Uniswap v3 fee tier is not enabled on the configured factory: ${FEE}" >&2
exit 1
fi
if [[ "${EXECUTE}" == "1" && "${ACCOUNTING_AWARE_SUPPORTED}" != "1" ]]; then
echo "EXECUTE=1 requires an upgraded accounting-aware Engine X vault" >&2
echo " vault: ${VAULT}" >&2
exit 1
fi
eval "$(
python3 - "${CWUSDC}" "${USDC}" "${POOL_CWUSDC_RAW}" "${POOL_USDC_RAW}" \
"${LENDER_USDC_RAW}" "${VAULT_CWUSDC_RAW}" "${VAULT_USDC_RAW}" \
"${INCLUDE_LENDER_USDC}" "${MIGRATION_AMOUNT_RAW}" "${FEE_TICK_SPACING}" \
"${TICK_LOWER}" "${TICK_UPPER}" <<'PY'
from decimal import Decimal
import sys
(
cwusdc,
usdc,
pool_cw,
pool_usdc,
lender_usdc,
vault_cw,
vault_usdc,
include_lender,
override_amount,
spacing,
tick_lower,
tick_upper,
) = sys.argv[1:]
pool_cw = int(pool_cw)
pool_usdc = int(pool_usdc)
lender_usdc = int(lender_usdc)
vault_cw = int(vault_cw)
vault_usdc = int(vault_usdc)
spacing = int(spacing)
tick_lower = int(tick_lower)
tick_upper = int(tick_upper)
if tick_lower >= tick_upper:
raise SystemExit("tick lower must be less than tick upper")
if tick_lower % spacing != 0 or tick_upper % spacing != 0:
raise SystemExit(f"ticks must be multiples of tick spacing {spacing}")
available_usdc = vault_usdc if include_lender == "1" else max(vault_usdc - lender_usdc, 0)
amount = min(pool_cw, pool_usdc, vault_cw, available_usdc)
if override_amount:
amount = int(override_amount)
if amount <= 0:
raise SystemExit("no balanced vault liquidity is available to migrate")
if amount > vault_cw:
raise SystemExit("migration amount exceeds vault cWUSDC balance")
if amount > vault_usdc:
raise SystemExit("migration amount exceeds vault USDC balance")
if include_lender != "1" and amount > available_usdc:
raise SystemExit("migration amount would consume lender USDC; set INCLUDE_LENDER_USDC=1 only if intentional")
addrs = sorted([cwusdc.lower(), usdc.lower()])
token0, token1 = addrs
amount0 = amount if token0 == cwusdc.lower() else amount
amount1 = amount if token1 == usdc.lower() else amount
def units(raw: int) -> str:
return f"{Decimal(raw) / Decimal(10**6):f}"
def emit(name, value):
print(f"{name}='{value}'")
emit("TOKEN0", token0)
emit("TOKEN1", token1)
emit("AMOUNT0_RAW", amount0)
emit("AMOUNT1_RAW", amount1)
emit("MIGRATE_RAW", amount)
emit("MIGRATE_UNITS", units(amount))
emit("POOL_CWUSDC_UNITS", units(pool_cw))
emit("POOL_USDC_UNITS", units(pool_usdc))
emit("LENDER_USDC_UNITS", units(lender_usdc))
emit("VAULT_CWUSDC_UNITS", units(vault_cw))
emit("VAULT_USDC_UNITS", units(vault_usdc))
emit("POOL_USDC_AVAILABLE_FOR_MIGRATION_RAW", available_usdc)
emit("POOL_USDC_AVAILABLE_FOR_MIGRATION_UNITS", units(available_usdc))
PY
)"
POOL="$(cast call "${FACTORY}" 'getPool(address,address,uint24)(address)' "${TOKEN0}" "${TOKEN1}" "${FEE}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | grep -oE '0x[a-fA-F0-9]{40}' | head -1)"
SIMULATED_POOL=""
if [[ "${POOL}" == "0x0000000000000000000000000000000000000000" ]]; then
SIMULATED_POOL="$(cast call "${POSITION_MANAGER}" 'createAndInitializePoolIfNecessary(address,address,uint24,uint160)(address)' \
"${TOKEN0}" "${TOKEN1}" "${FEE}" "${SQRT_PRICE_X96}" --rpc-url "${ETHEREUM_MAINNET_RPC}" \
| grep -oE '0x[a-fA-F0-9]{40}' | head -1 || true)"
fi
POOL_SLOT0=""
POOL_LIQUIDITY=""
if [[ "${POOL}" != "0x0000000000000000000000000000000000000000" ]]; then
POOL_SLOT0="$(cast call "${POOL}" 'slot0()(uint160,int24,uint16,uint16,uint16,uint8,bool)' --rpc-url "${ETHEREUM_MAINNET_RPC}")"
POOL_LIQUIDITY="$(cast call "${POOL}" 'liquidity()(uint128)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
fi
DEADLINE="$(( $(date +%s) + DEADLINE_SECONDS ))"
cat <<EOF
Engine X indexed-liquidity migration plan
mode: ${EXECUTE}
vault: ${VAULT}
vault owner: ${OWNER}
signer/recipient: ${SIGNER}
Engine X virtual vault state
accounted pool: ${POOL_CWUSDC_UNITS} cWUSDC / ${POOL_USDC_UNITS} USDC
lender bucket: ${LENDER_USDC_UNITS} USDC
actual token balances: ${VAULT_CWUSDC_UNITS} cWUSDC / ${VAULT_USDC_UNITS} USDC
USDC available without lender bucket: ${POOL_USDC_AVAILABLE_FOR_MIGRATION_UNITS}
Uniswap v3 public proof surface
factory: ${FACTORY}
position manager: ${POSITION_MANAGER}
fee: ${FEE}
tick spacing: ${FEE_TICK_SPACING}
ticks: [${TICK_LOWER}, ${TICK_UPPER}]
initial sqrtPriceX96: ${SQRT_PRICE_X96}
existing pool: ${POOL}
simulated pool if created: ${SIMULATED_POOL:-n/a}
existing slot0: ${POOL_SLOT0:-n/a}
existing liquidity: ${POOL_LIQUIDITY:-n/a}
Migration sizing
migrate: ${MIGRATE_UNITS} cWUSDC + ${MIGRATE_UNITS} USDC
token0: ${TOKEN0} amount0 raw: ${AMOUNT0_RAW}
token1: ${TOKEN1} amount1 raw: ${AMOUNT1_RAW}
Boundary
This migrates tiny Engine X proof liquidity into a public indexable UniV3 position.
It does not meet the 2,500/2,500 policy floor or the 10,000/10,000 preferred evidence target.
accounting-aware vault APIs detected: ${ACCOUNTING_AWARE_SUPPORTED}
If this is 0, deploy the upgraded Engine X vault before broadcasting the migration.
EOF
if [[ "${EXECUTE}" != "1" ]]; then
if [[ "${ACCOUNTING_AWARE_SUPPORTED}" != "1" ]]; then
cat <<EOF
Dry-run only. No broadcast commands were emitted for this vault because it does not expose
the upgraded accounting-aware API. Deploy the upgraded Engine X vault, seed/migrate the
balanced proof liquidity into that vault, then rerun with:
ENGINE_X_VAULT=<upgraded-vault-address> EXECUTE=0 bash scripts/deployment/migrate-engine-x-vault-to-mainnet-cwusdc-usdc-univ3.sh
EOF
exit 0
fi
cat <<EOF
Dry-run only. Review these commands before any broadcast:
cast send "${VAULT}" 'withdrawPoolLiquidity(address,uint256,uint256)' "${SIGNER}" "${MIGRATE_RAW}" "${MIGRATE_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
cast send "${POSITION_MANAGER}" 'createAndInitializePoolIfNecessary(address,address,uint24,uint160)' "${TOKEN0}" "${TOKEN1}" "${FEE}" "${SQRT_PRICE_X96}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
cast send "${TOKEN0}" 'approve(address,uint256)' "${POSITION_MANAGER}" "${AMOUNT0_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
cast send "${TOKEN1}" 'approve(address,uint256)' "${POSITION_MANAGER}" "${AMOUNT1_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
cast send "${POSITION_MANAGER}" 'mint((address,address,uint24,int24,int24,uint256,uint256,uint256,uint256,address,uint256))' "(${TOKEN0},${TOKEN1},${FEE},${TICK_LOWER},${TICK_UPPER},${AMOUNT0_RAW},${AMOUNT1_RAW},0,0,${SIGNER},${DEADLINE})" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY" -vv
EOF
exit 0
fi
cast send "${VAULT}" 'withdrawPoolLiquidity(address,uint256,uint256)' "${SIGNER}" "${MIGRATE_RAW}" "${MIGRATE_RAW}" \
--rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
cast send "${POSITION_MANAGER}" 'createAndInitializePoolIfNecessary(address,address,uint24,uint160)' \
"${TOKEN0}" "${TOKEN1}" "${FEE}" "${SQRT_PRICE_X96}" \
--rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
cast send "${TOKEN0}" 'approve(address,uint256)' "${POSITION_MANAGER}" "${AMOUNT0_RAW}" \
--rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
cast send "${TOKEN1}" 'approve(address,uint256)' "${POSITION_MANAGER}" "${AMOUNT1_RAW}" \
--rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
cast send "${POSITION_MANAGER}" 'mint((address,address,uint24,int24,int24,uint256,uint256,uint256,uint256,address,uint256))' \
"(${TOKEN0},${TOKEN1},${FEE},${TICK_LOWER},${TICK_UPPER},${AMOUNT0_RAW},${AMOUNT1_RAW},0,0,${SIGNER},${DEADLINE})" \
--rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}" -vv
NEW_POOL="$(cast call "${FACTORY}" 'getPool(address,address,uint24)(address)' "${TOKEN0}" "${TOKEN1}" "${FEE}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | grep -oE '0x[a-fA-F0-9]{40}' | head -1)"
echo "Post-migration UniV3 pool: ${NEW_POOL}"
cast call "${NEW_POOL}" 'slot0()(uint160,int24,uint16,uint16,uint16,uint8,bool)' --rpc-url "${ETHEREUM_MAINNET_RPC}"
cast call "${NEW_POOL}" 'liquidity()(uint128)' --rpc-url "${ETHEREUM_MAINNET_RPC}"

View File

@@ -0,0 +1,339 @@
#!/usr/bin/env bash
# Mint Ethereum mainnet cWUSDC directly to each address in config/pmm-soak-wallet-grid.json
# (EI matrix). Requires PRIVATE_KEY with MINTER_ROLE on the cWUSDC token.
#
# Modes (exactly one):
# --mint-raw R Same raw units minted to every wallet in the slice.
# --total-mint-raw B Total supply to mint across the slice, split with ±spread
# then renormalized to B (same algorithm as transfer distribution).
#
# Usage:
# ./scripts/deployment/mint-cwusdc-ei-matrix-wallets.sh [--dry-run] [--limit N] [--offset N|--resume-next]
# (--mint-raw R | --total-mint-raw B [--spread-pct S])
#
# --quiet-dry-run With --dry-run, suppress per-wallet lines.
# --legacy Pass --legacy to cast send.
#
# Env: ETHEREUM_MAINNET_RPC, CWUSDC_MAINNET, PRIVATE_KEY,
# EI_MATRIX_MINT_GAS_EST (default 60000), EI_MATRIX_GAS_HEADROOM_BPS (default 10500),
# EI_MATRIX_SKIP_GAS_CHECK=1 to bypass ETH preflight.
#
# Progress: reports/status/ei-matrix-cwusdc-mint-last-idx.txt
# Failures: reports/status/ei-matrix-cwusdc-mint-failures.log
# Lock: reports/status/ei-matrix-cwusdc-mint.lock
#
# On-chain: cWUSDC uses CompliantWrappedToken-style mint(address,uint256) for MINTER_ROLE.
# If mint reverts (reserve policy, roles), fix on-chain state before retrying.
#
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"
OFFSET_EXPLICIT=false
RESUME_NEXT=false
SPREAD_PCT="${EI_MATRIX_SPREAD_PCT:-15}"
CAST_LEGACY=false
QUIET_DRY_RUN=false
MINT_RAW=""
TOTAL_MINT_RAW=""
while [[ $# -gt 0 ]]; do
case "$1" in
--dry-run) DRY_RUN=true; shift ;;
--quiet-dry-run) QUIET_DRY_RUN=true; shift ;;
--limit) LIMIT="${2:?}"; shift 2 ;;
--resume-next) RESUME_NEXT=true; shift ;;
--offset) OFFSET="${2:?}"; OFFSET_EXPLICIT=true; shift 2 ;;
--spread-pct) SPREAD_PCT="${2:?}"; shift 2 ;;
--mint-raw) MINT_RAW="${2:?}"; shift 2 ;;
--total-mint-raw) TOTAL_MINT_RAW="${2:?}"; shift 2 ;;
--legacy) CAST_LEGACY=true; shift ;;
*) echo "Unknown arg: $1" >&2; exit 1 ;;
esac
done
LAST_IDX_FILE="${EI_MATRIX_CWUSDC_MINT_LAST_IDX_FILE:-${PROJECT_ROOT}/reports/status/ei-matrix-cwusdc-mint-last-idx.txt}"
if $RESUME_NEXT && $OFFSET_EXPLICIT; then
echo "Use only one of --offset or --resume-next." >&2
exit 1
fi
if $RESUME_NEXT; then
[[ -f "$LAST_IDX_FILE" ]] || { echo "Missing last-index file for --resume-next: $LAST_IDX_FILE" >&2; exit 1; }
_last="$(tr -d '[:space:]' < "$LAST_IDX_FILE" || echo "")"
[[ -n "$_last" ]] || { echo "Empty $LAST_IDX_FILE" >&2; exit 1; }
OFFSET=$((_last + 1))
echo "Resume-next (mint): last completed idx=$_last → offset=$OFFSET"
fi
if [[ -n "$MINT_RAW" && -n "$TOTAL_MINT_RAW" ]]; then
echo "Use only one of --mint-raw or --total-mint-raw." >&2
exit 1
fi
if [[ -z "$MINT_RAW" && -z "$TOTAL_MINT_RAW" ]]; then
echo "Set --mint-raw or --total-mint-raw." >&2
exit 1
fi
# shellcheck disable=SC1091
source "$PROJECT_ROOT/scripts/lib/load-project-env.sh"
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
PUBLIC_ETH_RPC="${ETHEREUM_MAINNET_PUBLIC_RPC:-https://ethereum-rpc.publicnode.com}"
RPC="${ETHEREUM_MAINNET_RPC:-${RPC_URL_1:-${ETH_MAINNET_RPC_URL:-$PUBLIC_ETH_RPC}}}"
BALANCE_RPC="${EI_MATRIX_BALANCE_RPC:-$RPC}"
LOCK_FILE="${PROJECT_ROOT}/reports/status/ei-matrix-cwusdc-mint.lock"
MANIFEST_DIR="${PROJECT_ROOT}/reports/status"
mkdir -p "$MANIFEST_DIR"
exec 200>"$LOCK_FILE"
if ! flock -n 200; then
echo "Another mint-cwusdc-ei-matrix-wallets.sh is already running (lock: $LOCK_FILE)." >&2
exit 1
fi
GRID="$PROJECT_ROOT/config/pmm-soak-wallet-grid.json"
DEPLOYER_CANONICAL="0x4A666F96fC8764181194447A7dFdb7d471b301C8"
[[ -f "$GRID" ]] || { echo "Missing $GRID" >&2; exit 1; }
command -v cast &>/dev/null || { echo "cast required" >&2; exit 1; }
command -v jq &>/dev/null || { echo "jq required" >&2; exit 1; }
[[ -n "${PRIVATE_KEY:-}" ]] || { echo "PRIVATE_KEY not set" >&2; exit 1; }
FROM_ADDR=$(cast wallet address --private-key "$PRIVATE_KEY")
CHAIN_ID=$(cast chain-id --rpc-url "$RPC" 2>/dev/null | tr -d '[:space:]' || true)
[[ -n "$CHAIN_ID" ]] || CHAIN_ID="1"
if [[ "$CHAIN_ID" != "1" ]]; then
echo "[WARN] chain-id=$CHAIN_ID (expected 1)." >&2
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"
}
token_decimals() {
cast call "$CWUSDC" 'decimals()(uint8)' --rpc-url "$BALANCE_RPC" 2>/dev/null | awk '{print $1}'
}
generate_spread_amounts_raw() {
local count="$1" budget="$2" spread="$3"
python3 - "$count" "$budget" "$spread" <<'PY'
import random
import sys
n = int(sys.argv[1])
budget = int(sys.argv[2])
spread = float(sys.argv[3])
if n <= 0:
sys.exit("count must be positive")
if budget < 0:
sys.exit("budget must be non-negative")
if spread < 0 or spread > 100:
sys.exit("spread-pct must be in [0, 100]")
base = 10000
low_w = max(1, (100 * base - int(spread * base)) // 100)
high_w = (100 * base + int(spread * base)) // 100
w = [random.randint(low_w, high_w) for _ in range(n)]
s = sum(w)
raw = [(budget * wi) // s for wi in w]
rem = budget - sum(raw)
for i in range(rem):
raw[i % n] += 1
for x in raw:
print(x)
PY
}
stream_addresses() {
if [[ -n "${LIMIT:-}" ]]; then
jq -r --argjson o "$OFFSET" --argjson l "$LIMIT" '.wallets[$o:$o+$l][] | .address' "$GRID"
else
jq -r --argjson o "$OFFSET" '.wallets[$o:][] | .address' "$GRID"
fi
}
ERR_LOG="${PROJECT_ROOT}/reports/status/ei-matrix-cwusdc-mint-failures.log"
LAST_IDX="${PROJECT_ROOT}/reports/status/ei-matrix-cwusdc-mint-last-idx.txt"
matrix_try_mint() {
local addr="$1" raw_amt="$2" idx="$3"
local dec human out tx attempt=1
dec="${DECIMALS:-6}"
if [[ "$raw_amt" == "0" ]]; then
echo "[skip] idx=$idx $addr zero raw"
return 0
fi
human=$(python3 -c "d=int('$dec'); a=int('$raw_amt'); print(f'{a / (10**d):.{min(d,8)}f}')" 2>/dev/null || echo "$raw_amt")
if $DRY_RUN; then
if ! $QUIET_DRY_RUN; then
echo "[dry-run] idx=$idx $addr raw=$raw_amt (~$human)"
fi
return 0
fi
local cast_extra=()
$CAST_LEGACY && cast_extra+=(--legacy)
while [[ "$attempt" -le 2 ]]; do
if out=$(cast send "$CWUSDC" "mint(address,uint256)" "$addr" "$raw_amt" \
--rpc-url "$RPC" --private-key "$PRIVATE_KEY" \
--nonce "$NONCE" "${cast_extra[@]}" 2>&1); then
tx=$(echo "$out" | tail -n1)
echo "[ok] idx=$idx nonce=$NONCE $addr raw=$raw_amt (~$human) tx=$tx"
sent=$((sent + 1))
NONCE=$((NONCE + 1))
echo "$idx" > "$LAST_IDX"
return 0
fi
if [[ "$attempt" -eq 1 ]] && echo "$out" | grep -qi 'nonce too low'; then
NONCE=$(pending_nonce) || true
echo "[retry] idx=$idx nonce refreshed to $NONCE (nonce too low)" >&2
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
return 0
done
}
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "EI matrix cWUSDC mint (mainnet)"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "RPC: $RPC"
echo "Token: $CWUSDC"
echo "Signer: $FROM_ADDR"
echo "Grid: $GRID"
echo "Dry-run: $DRY_RUN Quiet: $QUIET_DRY_RUN"
echo "Offset: $OFFSET Limit: ${LIMIT:-all}"
if [[ -n "$MINT_RAW" ]]; then
echo "Mode: fixed --mint-raw $MINT_RAW per wallet"
else
echo "Mode: --total-mint-raw $TOTAL_MINT_RAW spread: ±${SPREAD_PCT}% normalized"
fi
echo ""
if [[ "${FROM_ADDR,,}" != "${DEPLOYER_CANONICAL,,}" ]]; then
echo "[WARN] Signer is not canonical deployer $DEPLOYER_CANONICAL — minter role may still be granted."
echo ""
fi
DECIMALS=$(token_decimals || echo "6")
ADDR_TMP=$(mktemp)
AMOUNTS_TMP=$(mktemp)
cleanup_tmp() {
[[ -f "$ADDR_TMP" ]] && rm -f "$ADDR_TMP"
[[ -f "$AMOUNTS_TMP" ]] && rm -f "$AMOUNTS_TMP"
}
trap cleanup_tmp EXIT
stream_addresses > "$ADDR_TMP"
WALLET_COUNT=$(wc -l < "$ADDR_TMP" | tr -d '[:space:]')
if [[ -z "$WALLET_COUNT" || "$WALLET_COUNT" -eq 0 ]]; then
echo "No wallets in range (offset=$OFFSET limit=${LIMIT:-all})." >&2
exit 1
fi
if [[ -n "$MINT_RAW" ]]; then
awk -v r="$MINT_RAW" '{print r}' "$ADDR_TMP" > "$AMOUNTS_TMP"
BUDGET_RAW=$((MINT_RAW * WALLET_COUNT))
else
BUDGET_RAW="$TOTAL_MINT_RAW"
if [[ "$BUDGET_RAW" -le 0 ]]; then
echo "total-mint-raw must be positive." >&2
exit 1
fi
generate_spread_amounts_raw "$WALLET_COUNT" "$BUDGET_RAW" "$SPREAD_PCT" > "$AMOUNTS_TMP"
fi
SUM_CHECK=$(awk '{s+=$1} END {print s}' "$AMOUNTS_TMP")
if [[ "$SUM_CHECK" != "$BUDGET_RAW" ]]; then
echo "INTERNAL: amount sum $SUM_CHECK != budget $BUDGET_RAW" >&2
exit 1
fi
AMOUNTS_SHA256=$(sha256sum "$AMOUNTS_TMP" | awk '{print $1}')
TS=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
MANIFEST="$MANIFEST_DIR/ei-matrix-cwusdc-mint-manifest-${TS//:/-}.json"
cat >"$MANIFEST" <<EOF
{
"version": 1,
"kind": "ei-matrix-cwusdc-mint",
"timestamp": "$TS",
"chainId": 1,
"token": "$CWUSDC",
"signer": "$FROM_ADDR",
"offset": $OFFSET,
"limit": ${LIMIT:-null},
"walletCount": $WALLET_COUNT,
"budgetRaw": "$BUDGET_RAW",
"fixedMintRaw": ${MINT_RAW:-null},
"spreadPct": ${SPREAD_PCT},
"amountsSha256": "$AMOUNTS_SHA256",
"manifestPath": "$MANIFEST"
}
EOF
echo "Manifest: $MANIFEST"
echo "Amounts SHA256: $AMOUNTS_SHA256"
echo ""
GAS_EST="${EI_MATRIX_MINT_GAS_EST:-60000}"
HEADROOM_BPS="${EI_MATRIX_GAS_HEADROOM_BPS:-10500}"
ETH_WEI=$(cast balance "$FROM_ADDR" --rpc-url "$BALANCE_RPC" 2>/dev/null | awk '{print $1}' || echo "0")
ETH_HUMAN=$(python3 -c "print(f'{int(\"$ETH_WEI\") / 1e18:.6f}')" 2>/dev/null || echo "?")
echo "Signer ETH (gas): ${ETH_WEI} wei (~$ETH_HUMAN ETH)"
if ! $DRY_RUN && [[ "${EI_MATRIX_SKIP_GAS_CHECK:-}" != "1" ]]; then
GAS_PRICE_WEI=$(cast gas-price --rpc-url "$RPC" 2>/dev/null | awk '{print $1}' | head -1)
[[ -n "$GAS_PRICE_WEI" ]] || GAS_PRICE_WEI=0
MIN_WEI=$(python3 -c "c=int('$WALLET_COUNT'); g=int('$GAS_EST'); p=int('$GAS_PRICE_WEI'); b=int('$HEADROOM_BPS'); print(c*g*p*b//10000)")
if python3 -c "import sys; sys.exit(0 if int('$ETH_WEI') >= int('$MIN_WEI') else 1)"; then
echo "Gas preflight OK: est ${GAS_EST} gas/tx × $WALLET_COUNT × gasPrice $GAS_PRICE_WEI × (${HEADROOM_BPS}/10000) ≈ $MIN_WEI wei."
else
echo "Insufficient ETH for gas preflight. Need ≈ $MIN_WEI wei." >&2
echo "Set EI_MATRIX_SKIP_GAS_CHECK=1 to override (operator risk)." >&2
exit 1
fi
fi
echo ""
echo "Sample (first 3, last 3):"
_s_idx=$OFFSET
while IFS= read -r s_addr && IFS= read -r s_raw <&3; do
h=$(python3 -c "d=int('$DECIMALS'); a=int('$s_raw'); print(f'{a / (10**d):.6f}')" 2>/dev/null || echo "$s_raw")
echo " idx=$_s_idx $s_addr raw=$s_raw (~$h cWUSDC)"
_s_idx=$((_s_idx + 1))
done < <(head -3 "$ADDR_TMP") 3< <(head -3 "$AMOUNTS_TMP")
_s_idx=$((OFFSET + WALLET_COUNT - 3))
while IFS= read -r s_addr && IFS= read -r s_raw <&3; do
h=$(python3 -c "d=int('$DECIMALS'); a=int('$s_raw'); print(f'{a / (10**d):.6f}')" 2>/dev/null || echo "$s_raw")
echo " idx=$_s_idx $s_addr raw=$s_raw (~$h cWUSDC)"
_s_idx=$((_s_idx + 1))
done < <(tail -3 "$ADDR_TMP") 3< <(tail -3 "$AMOUNTS_TMP")
echo ""
sent=0
failed=0
idx=$OFFSET
NONCE=$(pending_nonce) || { echo "Could not read pending nonce" >&2; exit 1; }
echo "Starting nonce (pending): $NONCE"
echo ""
while IFS=$'\t' read -r addr raw_amt; do
matrix_try_mint "$addr" "$raw_amt" "$idx"
idx=$((idx + 1))
done < <(paste -d $'\t' "$ADDR_TMP" "$AMOUNTS_TMP")
if $DRY_RUN; then
echo "Dry-run complete. Indices covered: $OFFSET..$((idx - 1))."
else
echo "Done. Mint txs attempted: sent=$sent failed=$failed"
fi

View File

@@ -0,0 +1,68 @@
#!/usr/bin/env bash
# Single operator pipeline: preflight + mint cWUSDC to every EI matrix wallet on Ethereum mainnet.
#
# This does NOT bridge from Chain 138 — it mints on mainnet via MINTER_ROLE on CWUSDC_MAINNET.
#
# Usage:
# ./scripts/deployment/pipeline-ei-matrix-mint-cwusdc.sh --dry-run --mint-raw 1000000
# ./scripts/deployment/pipeline-ei-matrix-mint-cwusdc.sh --total-mint-raw 1000000000000 --spread-pct 15
# ./scripts/deployment/pipeline-ei-matrix-mint-cwusdc.sh --mint-raw 1000000 -- --limit 10 # extra args after --
#
# Env: loads scripts/lib/load-project-env.sh (PRIVATE_KEY, ETHEREUM_MAINNET_RPC, CWUSDC_MAINNET).
#
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
PASS=()
while [[ $# -gt 0 ]]; do
if [[ "$1" == "--" ]]; then shift; PASS+=("$@"); break; fi
PASS+=("$1")
shift
done
# shellcheck disable=SC1091
source "$PROJECT_ROOT/scripts/lib/load-project-env.sh"
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
PUBLIC_ETH_RPC="${ETHEREUM_MAINNET_PUBLIC_RPC:-https://ethereum-rpc.publicnode.com}"
RPC="${ETHEREUM_MAINNET_RPC:-${RPC_URL_1:-${ETH_MAINNET_RPC_URL:-$PUBLIC_ETH_RPC}}}"
echo "══════════════════════════════════════════════════════════════"
echo "Pipeline: EI matrix mainnet cWUSDC mint"
echo "══════════════════════════════════════════════════════════════"
echo "Grid: config/pmm-soak-wallet-grid.json"
echo "Token: $CWUSDC"
echo "RPC: $RPC"
echo ""
command -v cast &>/dev/null || { echo "cast required" >&2; exit 1; }
[[ -n "${PRIVATE_KEY:-}" ]] || { echo "PRIVATE_KEY not set" >&2; exit 1; }
FROM=$(cast wallet address --private-key "$PRIVATE_KEY")
CID=$(cast chain-id --rpc-url "$RPC" 2>/dev/null | tr -d '[:space:]' || echo "?")
echo "Signer: $FROM"
echo "Chain ID: $CID (expected 1)"
if [[ "$CID" != "1" ]]; then
echo "[WARN] Not Ethereum mainnet — aborting." >&2
exit 1
fi
ROLE=$(cast keccak "MINTER_ROLE()")
# AccessControl MINTER_ROLE is keccak256 of the string "MINTER_ROLE" for OZ — use cast keccak
ROLE=$(cast keccak "MINTER_ROLE")
if HR=$(cast call "$CWUSDC" "hasRole(bytes32,address)(bool)" "$ROLE" "$FROM" --rpc-url "$RPC" 2>/dev/null); then
if [[ "${HR,,}" != *true* ]]; then
echo "[WARN] hasRole(MINTER_ROLE) returned false for signer — mints will likely revert." >&2
else
echo "Preflight: MINTER_ROLE on cWUSDC for signer — OK"
fi
else
echo "[WARN] Could not call hasRole (ABI may differ) — continuing." >&2
fi
echo ""
echo "→ Running mint-cwusdc-ei-matrix-wallets.sh ${PASS[*]}"
echo ""
exec "$SCRIPT_DIR/mint-cwusdc-ei-matrix-wallets.sh" "${PASS[@]}"

View File

@@ -0,0 +1,93 @@
#!/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"
: "${ETHEREUM_MAINNET_RPC:?ETHEREUM_MAINNET_RPC is required}"
if [[ -z "${ENGINE_X_INDEXED_LIQUIDITY_VAULT:-}" ]]; then
cat <<'EOF'
Engine X indexed proof recording blocked
ENGINE_X_INDEXED_LIQUIDITY_VAULT is not configured.
Deploy the indexed-liquidity proof vault first:
pnpm engine-x:indexed-vault-deploy
EOF
exit 0
fi
EXECUTE="${EXECUTE:-0}"
RECIPIENT="${RECIPIENT:-${DEPLOYER_ADDRESS:-}}"
EXACT_OUTPUT_RAW="${EXACT_OUTPUT_RAW:-10000}"
PUBLIC_SWAP_TX_HASH_PROVIDED="${PUBLIC_SWAP_TX_HASH+x}"
LIQUIDITY_TX_HASH_PROVIDED="${LIQUIDITY_TX_HASH+x}"
ISO_HASH_PROVIDED="${ISO_HASH+x}"
AUDIT_HASH_PROVIDED="${AUDIT_HASH+x}"
PEG_HASH_PROVIDED="${PEG_HASH+x}"
PROOF_ID="${PROOF_ID:-$(cast keccak "engine-x:indexed-proof:dry-run:${ENGINE_X_INDEXED_LIQUIDITY_VAULT}:${EXACT_OUTPUT_RAW}")}"
PUBLIC_SWAP_TX_HASH="${PUBLIC_SWAP_TX_HASH:-$(cast keccak "engine-x:placeholder:public-swap")}"
LIQUIDITY_TX_HASH="${LIQUIDITY_TX_HASH:-$(cast keccak "engine-x:placeholder:liquidity")}"
ISO_HASH="${ISO_HASH:-$(cast keccak "engine-x:placeholder:iso")}"
AUDIT_HASH="${AUDIT_HASH:-$(cast keccak "engine-x:placeholder:audit")}"
PEG_HASH="${PEG_HASH:-$(cast keccak "engine-x:placeholder:peg")}"
if [[ -n "${PRIVATE_KEY:-}" ]]; then
SIGNER="$(cast wallet address --private-key "${PRIVATE_KEY}")"
RECIPIENT="${RECIPIENT:-${SIGNER}}"
else
SIGNER="${DEPLOYER_ADDRESS:-}"
fi
if [[ -z "${RECIPIENT}" || -z "${SIGNER}" ]]; then
echo "Set RECIPIENT and DEPLOYER_ADDRESS or PRIVATE_KEY" >&2
exit 1
fi
if [[ "${EXECUTE}" == "1" && -z "${PRIVATE_KEY:-}" ]]; then
echo "PRIVATE_KEY is required when EXECUTE=1" >&2
exit 1
fi
PLACEHOLDER_USED="0"
if [[ -z "${PUBLIC_SWAP_TX_HASH_PROVIDED}" || -z "${LIQUIDITY_TX_HASH_PROVIDED}" || -z "${ISO_HASH_PROVIDED}" || -z "${AUDIT_HASH_PROVIDED}" || -z "${PEG_HASH_PROVIDED}" ]]; then
PLACEHOLDER_USED="1"
fi
if [[ "${EXECUTE}" == "1" && "${PLACEHOLDER_USED}" == "1" ]]; then
echo "EXECUTE=1 requires PUBLIC_SWAP_TX_HASH, LIQUIDITY_TX_HASH, ISO_HASH, AUDIT_HASH, and PEG_HASH" >&2
exit 1
fi
STATE="$(cast call "${ENGINE_X_INDEXED_LIQUIDITY_VAULT}" 'currentPoolState()(uint160,int24,uint128,uint256,uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}")"
cat <<EOF
Engine X indexed proof recording plan
mode: ${EXECUTE}
vault: ${ENGINE_X_INDEXED_LIQUIDITY_VAULT}
signer: ${SIGNER}
recipient: ${RECIPIENT}
exact output raw: ${EXACT_OUTPUT_RAW}
proof id: ${PROOF_ID}
public swap tx hash: ${PUBLIC_SWAP_TX_HASH}
liquidity tx hash: ${LIQUIDITY_TX_HASH}
iso hash: ${ISO_HASH}
audit hash: ${AUDIT_HASH}
peg hash: ${PEG_HASH}
current pool state: ${STATE}
placeholder inputs used: ${PLACEHOLDER_USED}
EOF
if [[ "${EXECUTE}" != "1" ]]; then
cat <<EOF
Dry-run only. Use real tx/proof hashes before broadcasting:
cast send "${ENGINE_X_INDEXED_LIQUIDITY_VAULT}" 'recordIndexedProof((bytes32,bytes32,bytes32,address,uint256,bytes32,bytes32,bytes32))' "(${PROOF_ID},${PUBLIC_SWAP_TX_HASH},${LIQUIDITY_TX_HASH},${RECIPIENT},${EXACT_OUTPUT_RAW},${ISO_HASH},${AUDIT_HASH},${PEG_HASH})" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
EOF
exit 0
fi
cast send "${ENGINE_X_INDEXED_LIQUIDITY_VAULT}" \
'recordIndexedProof((bytes32,bytes32,bytes32,address,uint256,bytes32,bytes32,bytes32))' \
"(${PROOF_ID},${PUBLIC_SWAP_TX_HASH},${LIQUIDITY_TX_HASH},${RECIPIENT},${EXACT_OUTPUT_RAW},${ISO_HASH},${AUDIT_HASH},${PEG_HASH})" \
--rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"

View File

@@ -0,0 +1,155 @@
#!/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"
: "${ETHEREUM_MAINNET_RPC:?ETHEREUM_MAINNET_RPC is required}"
: "${PRIVATE_KEY:?PRIVATE_KEY is required}"
PAIR="${MAINNET_CWUSDC_USDC_UNIV2_PAIR:-0xC28706F899266b36BC43cc072b3a921BDf2C48D9}"
ROUTER="${CHAIN_1_UNISWAP_V2_ROUTER:-0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D}"
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
USDC="${USDC_MAINNET:-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48}"
SLIPPAGE_BPS="${SLIPPAGE_BPS:-100}"
USDC_KEEP_RAW="${MAINNET_PUBLIC_LP_USDC_KEEP_RAW:-10000}"
EXECUTE="${EXECUTE:-0}"
SIGNER="$(cast wallet address --private-key "${PRIVATE_KEY}")"
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)"
RESERVES="$(cast call "${PAIR}" 'getReserves()(uint112,uint112,uint32)' --rpc-url "${ETHEREUM_MAINNET_RPC}")"
WALLET_USDC_RAW="$(cast call "${USDC}" 'balanceOf(address)(uint256)' "${SIGNER}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | sed -E 's/[[:space:]].*$//')"
WALLET_CWUSDC_RAW="$(cast call "${CWUSDC}" 'balanceOf(address)(uint256)' "${SIGNER}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | sed -E 's/[[:space:]].*$//')"
PLAN="$(
python3 - "${CWUSDC}" "${USDC}" "${TOKEN0}" "${TOKEN1}" "${RESERVES}" "${WALLET_USDC_RAW}" "${WALLET_CWUSDC_RAW}" "${SLIPPAGE_BPS}" "${USDC_KEEP_RAW}" <<'PY'
from decimal import Decimal, ROUND_FLOOR, ROUND_CEILING, getcontext
import re
import sys
getcontext().prec = 80
cwusdc, usdc, token0, token1, reserves, wallet_usdc, wallet_cwusdc, slippage_bps, usdc_keep = sys.argv[1:]
# Cast prints reserves as one uint112 per line; ignore bracket scientific notation.
_lines = [ln.strip() for ln in reserves.strip().splitlines() if ln.strip()]
_nums = []
for ln in _lines:
m = re.match(r"^(\d+)", ln)
if m:
_nums.append(int(m.group(1)))
if len(_nums) < 2:
raise SystemExit("could not parse pair reserves")
reserve0, reserve1 = _nums[:2]
if token0.lower() == cwusdc.lower() and token1.lower() == usdc.lower():
base_raw, quote_raw = reserve0, reserve1
elif token1.lower() == cwusdc.lower() and token0.lower() == usdc.lower():
base_raw, quote_raw = reserve1, reserve0
else:
raise SystemExit("pair tokens do not match cWUSDC/USDC")
wallet_usdc_raw = int(wallet_usdc)
wallet_cwusdc_raw = int(wallet_cwusdc)
slippage = int(slippage_bps)
keep_raw = int(usdc_keep)
fee = Decimal("0.997")
x = Decimal(base_raw)
y = Decimal(quote_raw)
if y <= 0 or x <= y:
raise SystemExit("pair does not look quote-side short; aborting canary repair")
# Solve for quote-in q such that post-swap reserves are equal:
# (y + q) * (y + 0.997q) = x * y
a = fee
b = y * (Decimal(1) + fee)
c = y * y - x * y
q = (-b + (b * b - Decimal(4) * a * c).sqrt()) / (Decimal(2) * a)
quote_in_raw = int(q.to_integral_value(rounding=ROUND_CEILING))
quote_in_fee = Decimal(quote_in_raw) * fee
base_out = x * quote_in_fee / (y + quote_in_fee)
min_base_out_raw = int((base_out * Decimal(10000 - slippage) / Decimal(10000)).to_integral_value(rounding=ROUND_FLOOR))
if wallet_usdc_raw < quote_in_raw + keep_raw:
raise SystemExit(
f"insufficient USDC for canary plus keep reserve: need {quote_in_raw + keep_raw}, have {wallet_usdc_raw}"
)
balanced_quote_add_raw = max(wallet_usdc_raw - quote_in_raw - keep_raw, 0)
balanced_base_add_raw = min(wallet_cwusdc_raw + int(base_out), balanced_quote_add_raw)
min_balanced_raw = int((Decimal(balanced_base_add_raw) * Decimal(10000 - slippage) / Decimal(10000)).to_integral_value(rounding=ROUND_FLOOR))
def emit(name, value):
print(f"{name}='{value}'")
emit("BASE_RESERVE_RAW", base_raw)
emit("QUOTE_RESERVE_RAW", quote_raw)
emit("QUOTE_IN_RAW", quote_in_raw)
emit("EXPECTED_BASE_OUT_RAW", int(base_out.to_integral_value(rounding=ROUND_FLOOR)))
emit("MIN_BASE_OUT_RAW", min_base_out_raw)
emit("BALANCED_ADD_RAW", balanced_base_add_raw)
emit("MIN_BALANCED_ADD_RAW", min_balanced_raw)
emit("USDC_KEEP_RAW_EFFECTIVE", keep_raw)
PY
)" || { echo "Canary planner failed (likely insufficient USDC vs computed quote-in)." >&2; exit 1; }
eval "${PLAN}"
# UniV2 router is source of truth for swap output; CP closed-form above can diverge on extreme reserves.
ROUTER_AMOUNTS="$(cast call "${ROUTER}" "getAmountsOut(uint256,address[])(uint256[])" "${QUOTE_IN_RAW}" "[${USDC},${CWUSDC}]" --rpc-url "${ETHEREUM_MAINNET_RPC}")"
# Second hop amount is the cWUSDC out; require wide digits so we do not confuse brackets with reserves.
EXPECTED_BASE_OUT_RAW="$(python3 -c 'import re,sys; s=sys.argv[1]; nums=[int(x) for x in re.findall(r"\b\d{10,}\b", s)]; print(nums[-1] if nums else 0)' "${ROUTER_AMOUNTS}")"
MIN_BASE_OUT_RAW=$(( EXPECTED_BASE_OUT_RAW * (10000 - SLIPPAGE_BPS) / 10000 ))
if [[ "${EXPECTED_BASE_OUT_RAW}" -eq 0 ]]; then
echo "router getAmountsOut returned 0; aborting" >&2
exit 1
fi
cat <<EOF
Mainnet cWUSDC/USDC UniV2 public canary plan
mode: ${EXECUTE}
pair: ${PAIR}
signer: ${SIGNER}
reserves raw before: ${BASE_RESERVE_RAW} cWUSDC / ${QUOTE_RESERVE_RAW} USDC
quote repair swap: ${QUOTE_IN_RAW} USDC raw
expected cWUSDC out (router): ${EXPECTED_BASE_OUT_RAW} raw
min cWUSDC out (${SLIPPAGE_BPS} bps slip): ${MIN_BASE_OUT_RAW} raw
balanced add after repair: ${BALANCED_ADD_RAW} raw per side
USDC keep reserve: ${USDC_KEEP_RAW_EFFECTIVE} raw
This is a tiny public LP canary, not policy-floor liquidity.
EOF
if [[ "${EXECUTE}" != "1" ]]; then
cat <<EOF
Dry-run only. To broadcast after reviewing the numbers:
EXECUTE=1 bash scripts/deployment/repair-mainnet-cwusdc-usdc-univ2-canary.sh
EOF
exit 0
fi
DEADLINE="$(( $(date +%s) + 1800 ))"
cast send "${USDC}" 'approve(address,uint256)(bool)' "${ROUTER}" "${QUOTE_IN_RAW}" \
--private-key "${PRIVATE_KEY}" --rpc-url "${ETHEREUM_MAINNET_RPC}"
cast send "${ROUTER}" 'swapExactTokensForTokens(uint256,uint256,address[],address,uint256)' \
"${QUOTE_IN_RAW}" "${MIN_BASE_OUT_RAW}" "[${USDC},${CWUSDC}]" "${SIGNER}" "${DEADLINE}" \
--private-key "${PRIVATE_KEY}" --rpc-url "${ETHEREUM_MAINNET_RPC}"
if [[ "${BALANCED_ADD_RAW}" != "0" ]]; then
cast send "${CWUSDC}" 'approve(address,uint256)(bool)' "${ROUTER}" "${BALANCED_ADD_RAW}" \
--private-key "${PRIVATE_KEY}" --rpc-url "${ETHEREUM_MAINNET_RPC}"
cast send "${USDC}" 'approve(address,uint256)(bool)' "${ROUTER}" "${BALANCED_ADD_RAW}" \
--private-key "${PRIVATE_KEY}" --rpc-url "${ETHEREUM_MAINNET_RPC}"
cast send "${ROUTER}" 'addLiquidity(address,address,uint256,uint256,uint256,uint256,address,uint256)' \
"${CWUSDC}" "${USDC}" "${BALANCED_ADD_RAW}" "${BALANCED_ADD_RAW}" \
"${MIN_BALANCED_ADD_RAW}" "${MIN_BALANCED_ADD_RAW}" "${SIGNER}" "${DEADLINE}" \
--private-key "${PRIVATE_KEY}" --rpc-url "${ETHEREUM_MAINNET_RPC}"
fi
bash "${PROJECT_ROOT}/scripts/verify/snapshot-mainnet-cwusdc-usdc-preflight.sh"
bash "${PROJECT_ROOT}/scripts/verify/plan-mainnet-cwusdc-usdc-repeg.sh"

View File

@@ -0,0 +1,124 @@
#!/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"
: "${ETHEREUM_MAINNET_RPC:?ETHEREUM_MAINNET_RPC is required}"
VAULT="${ENGINE_X_VAULT:-0x9a22a3e272A364D64240dE6bda796FcA421cA7E9}"
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
USDC="${USDC_MAINNET:-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48}"
RECIPIENT="${RETIRE_RECIPIENT:-${DEPLOYER_ADDRESS:-}}"
ALLOW_STALE_ACCOUNTING_RETIREMENT="${ALLOW_STALE_ACCOUNTING_RETIREMENT:-0}"
EXECUTE="${EXECUTE:-0}"
if [[ -n "${PRIVATE_KEY:-}" ]]; then
SIGNER="$(cast wallet address --private-key "${PRIVATE_KEY}")"
RECIPIENT="${RETIRE_RECIPIENT:-${SIGNER}}"
else
SIGNER="${DEPLOYER_ADDRESS:-}"
fi
if [[ -z "${RECIPIENT}" ]]; then
echo "Set RETIRE_RECIPIENT 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
OWNER="$(cast call "${VAULT}" 'owner()(address)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | grep -oE '0x[a-fA-F0-9]{40}' | head -1)"
POOL_CWUSDC_RAW="$(cast call "${VAULT}" 'poolCwusdcReserve()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}' || echo 0)"
POOL_USDC_RAW="$(cast call "${VAULT}" 'poolUsdcReserve()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}' || echo 0)"
LENDER_USDC_RAW="$(cast call "${VAULT}" 'lenderUsdcAvailable()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}' || echo 0)"
VAULT_CWUSDC_RAW="$(cast call "${CWUSDC}" 'balanceOf(address)(uint256)' "${VAULT}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
VAULT_USDC_RAW="$(cast call "${USDC}" 'balanceOf(address)(uint256)' "${VAULT}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
ACCOUNTING_AWARE_SUPPORTED="0"
if cast call "${VAULT}" 'maxFlashLoan(address)(uint256)' "${USDC}" --rpc-url "${ETHEREUM_MAINNET_RPC}" >/dev/null 2>&1; then
ACCOUNTING_AWARE_SUPPORTED="1"
fi
if [[ "${EXECUTE}" == "1" && "${SIGNER,,}" != "${OWNER,,}" ]]; then
echo "EXECUTE=1 signer must be the vault owner" >&2
echo " signer: ${SIGNER}" >&2
echo " owner: ${OWNER}" >&2
exit 1
fi
eval "$(
python3 - "${POOL_CWUSDC_RAW}" "${POOL_USDC_RAW}" "${LENDER_USDC_RAW}" "${VAULT_CWUSDC_RAW}" "${VAULT_USDC_RAW}" <<'PY'
from decimal import Decimal
import sys
pool_cw, pool_usdc, lender_usdc, vault_cw, vault_usdc = map(int, sys.argv[1:])
def units(raw):
return f"{Decimal(raw) / Decimal(10**6):f}"
def emit(k, v):
print(f"{k}='{v}'")
emit("POOL_CWUSDC_UNITS", units(pool_cw))
emit("POOL_USDC_UNITS", units(pool_usdc))
emit("LENDER_USDC_UNITS", units(lender_usdc))
emit("VAULT_CWUSDC_UNITS", units(vault_cw))
emit("VAULT_USDC_UNITS", units(vault_usdc))
emit("BALANCED_POOL_WITHDRAW_RAW", min(pool_cw, pool_usdc, vault_cw, max(vault_usdc - lender_usdc, 0)))
PY
)"
cat <<EOF
Engine X legacy vault retirement plan
mode: ${EXECUTE}
vault: ${VAULT}
owner: ${OWNER}
signer: ${SIGNER:-n/a}
recipient: ${RECIPIENT}
accounting-aware API: ${ACCOUNTING_AWARE_SUPPORTED}
accounted pool: ${POOL_CWUSDC_UNITS} cWUSDC / ${POOL_USDC_UNITS} USDC
lender bucket: ${LENDER_USDC_UNITS} USDC
actual balances: ${VAULT_CWUSDC_UNITS} cWUSDC / ${VAULT_USDC_UNITS} USDC
EOF
if [[ "${ACCOUNTING_AWARE_SUPPORTED}" == "1" ]]; then
cat <<EOF
Accounting-aware retirement commands:
cast send "${VAULT}" 'withdrawPoolLiquidity(address,uint256,uint256)' "${RECIPIENT}" "${BALANCED_POOL_WITHDRAW_RAW}" "${BALANCED_POOL_WITHDRAW_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
cast send "${VAULT}" 'withdrawLenderUsdc(address,uint256)' "${RECIPIENT}" "${LENDER_USDC_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
EOF
if [[ "${EXECUTE}" == "1" ]]; then
cast send "${VAULT}" 'withdrawPoolLiquidity(address,uint256,uint256)' "${RECIPIENT}" "${BALANCED_POOL_WITHDRAW_RAW}" "${BALANCED_POOL_WITHDRAW_RAW}" --rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
cast send "${VAULT}" 'withdrawLenderUsdc(address,uint256)' "${RECIPIENT}" "${LENDER_USDC_RAW}" --rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
fi
exit 0
fi
cat <<EOF
This vault does not expose accounting-aware retirement APIs. Default behavior is report-only.
Set ALLOW_STALE_ACCOUNTING_RETIREMENT=1 only when the vault is being permanently retired
and no future proof will rely on its internal accounting.
EOF
if [[ "${ALLOW_STALE_ACCOUNTING_RETIREMENT}" != "1" ]]; then
exit 0
fi
cat <<EOF
Legacy full-token retirement commands:
cast send "${VAULT}" 'withdraw(address,address,uint256)' "${CWUSDC}" "${RECIPIENT}" "${VAULT_CWUSDC_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
cast send "${VAULT}" 'withdraw(address,address,uint256)' "${USDC}" "${RECIPIENT}" "${VAULT_USDC_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
EOF
if [[ "${EXECUTE}" == "1" ]]; then
cast send "${VAULT}" 'withdraw(address,address,uint256)' "${CWUSDC}" "${RECIPIENT}" "${VAULT_CWUSDC_RAW}" --rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
cast send "${VAULT}" 'withdraw(address,address,uint256)' "${USDC}" "${RECIPIENT}" "${VAULT_USDC_RAW}" --rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
fi

View File

@@ -0,0 +1,269 @@
#!/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"
: "${ETHEREUM_MAINNET_RPC:?ETHEREUM_MAINNET_RPC is required}"
VAULT="${ENGINE_X_VAULT:-0x9a22a3e272A364D64240dE6bda796FcA421cA7E9}"
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
XAUT="${XAUT_MAINNET:-0x68749665FF8D2d112Fa859AA293F07A622782F38}"
LOOPS="${LOOPS:-1}"
EXACT_OUTPUT_PER_LOOP_RAW="${EXACT_OUTPUT_PER_LOOP_RAW:-10000}"
DEBT_RAW="${DEBT_RAW:-}"
ROUNDING_RECEIVER="${ROUNDING_RECEIVER:-}"
RECIPIENT="${RECIPIENT:-}"
EXECUTE="${EXECUTE:-0}"
STAMP="${ENGINE_X_LOOP_PROOF_STAMP:-$(date -u +%Y%m%dT%H%M%SZ)}"
OUT_JSON="${OUT_JSON:-reports/status/engine-x-loop-proof-${STAMP}.json}"
OUT_MD="${OUT_MD:-reports/status/engine-x-loop-proof-${STAMP}.md}"
LATEST_JSON="${LATEST_JSON:-reports/status/engine-x-loop-proof-latest.json}"
LATEST_MD="${LATEST_MD:-reports/status/engine-x-loop-proof-latest.md}"
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
RECIPIENT="${RECIPIENT:-${SIGNER}}"
ROUNDING_RECEIVER="${ROUNDING_RECEIVER:-${SIGNER}}"
PROOF_ID="${PROOF_ID:-$(cast keccak "dbis-engine-x:loop-proof:${SIGNER}:${RECIPIENT}:${EXACT_OUTPUT_PER_LOOP_RAW}:${LOOPS}:${STAMP}")}"
ISO_HASH="${ISO_HASH:-$(cast keccak "dbis-engine-x:loop-proof:iso:${PROOF_ID}")}"
AUDIT_HASH="${AUDIT_HASH:-$(cast keccak "dbis-engine-x:loop-proof:audit:${PROOF_ID}")}"
PEG_HASH="${PEG_HASH:-$(cast keccak "dbis-engine-x:loop-proof:peg:${PROOF_ID}")}"
POOL_CWUSDC_RAW="$(cast call "${VAULT}" 'poolCwusdcReserve()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
POOL_USDC_RAW="$(cast call "${VAULT}" 'poolUsdcReserve()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
LENDER_USDC_RAW="$(cast call "${VAULT}" 'lenderUsdcAvailable()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
if [[ -z "${DEBT_RAW}" ]]; then
DEBT_RAW="$(
python3 - "${POOL_CWUSDC_RAW}" "${POOL_USDC_RAW}" "${EXACT_OUTPUT_PER_LOOP_RAW}" "${LENDER_USDC_RAW}" <<'PY'
import sys
reserve_cw = int(sys.argv[1])
reserve_usdc = int(sys.argv[2])
target = int(sys.argv[3])
max_debt = int(sys.argv[4])
def amount_in(amount_out, reserve_in, reserve_out):
if amount_out <= 0 or reserve_in <= 0 or reserve_out <= amount_out:
raise ValueError("bad getAmountIn inputs")
return reserve_in * amount_out * 1000 // ((reserve_out - amount_out) * 997) + 1
def amount_out(amount_in, reserve_in, reserve_out):
if amount_in <= 0 or reserve_in <= 0 or reserve_out <= 0:
raise ValueError("bad getAmountOut inputs")
return amount_in * 997 * reserve_out // (reserve_in * 1000 + amount_in * 997)
for debt in range(1, max_debt + 1):
cw_in = amount_in(debt, reserve_cw, reserve_usdc)
cw_reserve_after_in = reserve_cw + cw_in
usdc_reserve_after_out = reserve_usdc - debt
cw_out = amount_out(debt, usdc_reserve_after_out, cw_reserve_after_in)
if cw_out >= target:
print(debt)
raise SystemExit(0)
raise SystemExit("no debt size can reach exact output within lender bucket")
PY
)"
fi
mapfile -t PREVIEW < <(
cast call "${VAULT}" \
'previewVirtualProof(uint256,uint256)(uint256,uint256,uint256,uint256,uint256,uint256,uint256)' \
"${DEBT_RAW}" "${LOOPS}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}'
)
COLLATERAL_XAUT_RAW="${PREVIEW[0]}"
CWUSDC_IN_PER_LOOP_RAW="${PREVIEW[1]}"
CWUSDC_OUT_PER_LOOP_RAW="${PREVIEW[2]}"
CWUSDC_LOSS_PER_LOOP_RAW="${PREVIEW[3]}"
TOTAL_CWUSDC_IN_RAW="${PREVIEW[4]}"
TOTAL_CWUSDC_OUT_RAW="${PREVIEW[5]}"
TOTAL_NEUTRALIZED_RAW="${PREVIEW[6]}"
EXACT_OUTPUT_TOTAL_RAW="$((EXACT_OUTPUT_PER_LOOP_RAW * LOOPS))"
OUTPUT_ROUNDING_RAW="$((TOTAL_CWUSDC_OUT_RAW - EXACT_OUTPUT_TOTAL_RAW))"
if (( OUTPUT_ROUNDING_RAW < 0 )); then
echo "Preview output is lower than requested exact output" >&2
exit 1
fi
CWUSDC_BAL_RAW="$(cast call "${CWUSDC}" 'balanceOf(address)(uint256)' "${SIGNER}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
XAUT_BAL_RAW="$(cast call "${XAUT}" 'balanceOf(address)(uint256)' "${SIGNER}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
CWUSDC_ALLOWANCE_RAW="$(cast call "${CWUSDC}" 'allowance(address,address)(uint256)' "${SIGNER}" "${VAULT}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
XAUT_ALLOWANCE_RAW="$(cast call "${XAUT}" 'allowance(address,address)(uint256)' "${SIGNER}" "${VAULT}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
PROOF_USED="$(cast call "${VAULT}" 'usedProofIds(bytes32)(bool)' "${PROOF_ID}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | tr -d '[:space:]')"
if [[ "${PROOF_USED}" == "true" ]]; then
echo "Proof ID is already used: ${PROOF_ID}" >&2
exit 1
fi
if (( CWUSDC_BAL_RAW < TOTAL_CWUSDC_IN_RAW )); then
echo "Insufficient cWUSDC balance" >&2
exit 1
fi
if (( XAUT_BAL_RAW < COLLATERAL_XAUT_RAW )); then
echo "Insufficient XAUt balance" >&2
exit 1
fi
CWUSDC_APPROVE_NEEDED=0
XAUT_APPROVE_NEEDED=0
if (( CWUSDC_ALLOWANCE_RAW < TOTAL_CWUSDC_IN_RAW )); then
CWUSDC_APPROVE_NEEDED=1
fi
if (( XAUT_ALLOWANCE_RAW < COLLATERAL_XAUT_RAW )); then
XAUT_APPROVE_NEEDED=1
fi
mkdir -p "$(dirname "${OUT_JSON}")"
python3 - "${OUT_JSON}" "${OUT_MD}" "${LATEST_JSON}" "${LATEST_MD}" \
"${EXECUTE}" "${STAMP}" "${VAULT}" "${SIGNER}" "${RECIPIENT}" "${ROUNDING_RECEIVER}" \
"${LOOPS}" "${EXACT_OUTPUT_PER_LOOP_RAW}" "${DEBT_RAW}" "${PROOF_ID}" "${ISO_HASH}" "${AUDIT_HASH}" "${PEG_HASH}" \
"${COLLATERAL_XAUT_RAW}" "${CWUSDC_IN_PER_LOOP_RAW}" "${CWUSDC_OUT_PER_LOOP_RAW}" "${CWUSDC_LOSS_PER_LOOP_RAW}" \
"${TOTAL_CWUSDC_IN_RAW}" "${TOTAL_CWUSDC_OUT_RAW}" "${EXACT_OUTPUT_TOTAL_RAW}" "${OUTPUT_ROUNDING_RAW}" "${TOTAL_NEUTRALIZED_RAW}" \
"${CWUSDC_BAL_RAW}" "${XAUT_BAL_RAW}" "${CWUSDC_ALLOWANCE_RAW}" "${XAUT_ALLOWANCE_RAW}" "${CWUSDC_APPROVE_NEEDED}" "${XAUT_APPROVE_NEEDED}" <<'PY'
from decimal import Decimal
import json
from pathlib import Path
import sys
(
out_json, out_md, latest_json, latest_md, execute, stamp, vault, signer, recipient, rounding_receiver,
loops, exact_per_loop, debt, proof_id, iso_hash, audit_hash, peg_hash, collateral, cw_in, cw_out, loss,
total_in, total_out, exact_total, rounding, neutralized, cw_bal, xaut_bal, cw_allow, xaut_allow,
cw_approve, xaut_approve,
) = sys.argv[1:]
def units(raw):
return f"{Decimal(int(raw)) / Decimal(10**6):f}"
payload = {
"schema": "engine-x-loop-proof/v1",
"executed": execute == "1",
"stamp": stamp,
"vault": vault,
"signer": signer,
"recipient": recipient,
"roundingReceiver": rounding_receiver,
"loops": int(loops),
"debtUsdcPerLoopRaw": debt,
"debtUsdcPerLoop": units(debt),
"exactOutputPerLoopRaw": exact_per_loop,
"exactOutputPerLoop": units(exact_per_loop),
"proofId": proof_id,
"isoHash": iso_hash,
"auditHash": audit_hash,
"pegHash": peg_hash,
"preview": {
"collateralXautRaw": collateral,
"collateralXaut": units(collateral),
"cwusdcInPerLoopRaw": cw_in,
"cwusdcInPerLoop": units(cw_in),
"cwusdcOutPerLoopRaw": cw_out,
"cwusdcOutPerLoop": units(cw_out),
"cwusdcLossPerLoopRaw": loss,
"cwusdcLossPerLoop": units(loss),
"totalCwusdcInRaw": total_in,
"totalCwusdcIn": units(total_in),
"totalCwusdcOutRaw": total_out,
"totalCwusdcOut": units(total_out),
"exactOutputTotalRaw": exact_total,
"exactOutputTotal": units(exact_total),
"outputRoundingRaw": rounding,
"outputRounding": units(rounding),
"totalNeutralizedRaw": neutralized,
"totalNeutralized": units(neutralized),
},
"balances": {
"cwusdcRaw": cw_bal,
"cwusdc": units(cw_bal),
"xautRaw": xaut_bal,
"xaut": units(xaut_bal),
"cwusdcAllowanceRaw": cw_allow,
"xautAllowanceRaw": xaut_allow,
"cwusdcApproveNeeded": cw_approve == "1",
"xautApproveNeeded": xaut_approve == "1",
},
}
Path(out_json).write_text(json.dumps(payload, indent=2) + "\n")
Path(latest_json).write_text(json.dumps(payload, indent=2) + "\n")
lines = [
"# Engine X Loop Proof",
"",
f"- Executed: `{payload['executed']}`",
f"- Vault: `{vault}`",
f"- Loops: `{loops}`",
f"- Exact cWUSDC output per loop: `{payload['exactOutputPerLoop']}`",
f"- Debt USDC per loop: `{payload['debtUsdcPerLoop']}`",
f"- cWUSDC in/out per loop: `{payload['preview']['cwusdcInPerLoop']} / {payload['preview']['cwusdcOutPerLoop']}`",
f"- Neutralized per loop: `{payload['preview']['cwusdcLossPerLoop']}`",
f"- Total exact output: `{payload['preview']['exactOutputTotal']}`",
f"- Proof ID: `{proof_id}`",
f"- cWUSDC approval needed: `{payload['balances']['cwusdcApproveNeeded']}`",
f"- XAUt approval needed: `{payload['balances']['xautApproveNeeded']}`",
]
Path(out_md).write_text("\n".join(lines) + "\n")
Path(latest_md).write_text("\n".join(lines) + "\n")
PY
cat <<EOF
Engine X loop proof plan
mode: ${EXECUTE}
vault: ${VAULT}
signer: ${SIGNER}
recipient: ${RECIPIENT}
loops: ${LOOPS}
exact cWUSDC output per loop raw: ${EXACT_OUTPUT_PER_LOOP_RAW}
debt USDC per loop raw: ${DEBT_RAW}
cWUSDC in/out/loss per loop raw: ${CWUSDC_IN_PER_LOOP_RAW} / ${CWUSDC_OUT_PER_LOOP_RAW} / ${CWUSDC_LOSS_PER_LOOP_RAW}
total exact output raw: ${EXACT_OUTPUT_TOTAL_RAW}
total cWUSDC input raw: ${TOTAL_CWUSDC_IN_RAW}
total neutralized raw: ${TOTAL_NEUTRALIZED_RAW}
XAUt collateral raw: ${COLLATERAL_XAUT_RAW}
proof id: ${PROOF_ID}
cWUSDC approve needed: ${CWUSDC_APPROVE_NEEDED}
XAUt approve needed: ${XAUT_APPROVE_NEEDED}
report: ${OUT_JSON}
EOF
if [[ "${EXECUTE}" != "1" ]]; then
cat <<EOF
Dry-run only. To broadcast this exact loop proof:
EXECUTE=1 LOOPS=${LOOPS} EXACT_OUTPUT_PER_LOOP_RAW=${EXACT_OUTPUT_PER_LOOP_RAW} \\
PROOF_ID=${PROOF_ID} ISO_HASH=${ISO_HASH} AUDIT_HASH=${AUDIT_HASH} PEG_HASH=${PEG_HASH} \\
bash scripts/deployment/run-engine-x-loop-proof.sh
EOF
exit 0
fi
if [[ "${CWUSDC_APPROVE_NEEDED}" == "1" ]]; then
cast send "${CWUSDC}" 'approve(address,uint256)' "${VAULT}" "${TOTAL_CWUSDC_IN_RAW}" \
--rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
fi
if [[ "${XAUT_APPROVE_NEEDED}" == "1" ]]; then
cast send "${XAUT}" 'approve(address,uint256)' "${VAULT}" "${COLLATERAL_XAUT_RAW}" \
--rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
fi
cast send "${VAULT}" \
'runVirtualProofExactOutTo(bytes32,uint256,uint256,address,uint256,address,bytes32,bytes32,bytes32)' \
"${PROOF_ID}" "${DEBT_RAW}" "${LOOPS}" "${RECIPIENT}" "${EXACT_OUTPUT_TOTAL_RAW}" "${ROUNDING_RECEIVER}" \
"${ISO_HASH}" "${AUDIT_HASH}" "${PEG_HASH}" \
--rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"

View File

@@ -0,0 +1,113 @@
#!/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"
: "${ETHEREUM_MAINNET_RPC:?ETHEREUM_MAINNET_RPC is required}"
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
USDC="${USDC_MAINNET:-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48}"
FACTORY="${CHAIN_1_UNISWAP_V3_FACTORY:-0x1F98431c8aD98523631AE4a59f267346ea31F984}"
ROUTER="${CHAIN_1_UNISWAP_V3_ROUTER:-0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45}"
QUOTER="${CHAIN_1_UNISWAP_V3_QUOTER:-0x61fFE014bA17989E743c5F6cB21bF9697530B21e}"
FEE="${ENGINE_X_UNIV3_FEE:-100}"
DIRECTION="${DIRECTION:-USDC_TO_CWUSDC}"
AMOUNT_IN_RAW="${AMOUNT_IN_RAW:-10000}"
SLIPPAGE_BPS="${SLIPPAGE_BPS:-100}"
DEADLINE_SECONDS="${DEADLINE_SECONDS:-600}"
EXECUTE="${EXECUTE:-0}"
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
case "${DIRECTION}" in
USDC_TO_CWUSDC)
TOKEN_IN="${USDC}"
TOKEN_OUT="${CWUSDC}"
;;
CWUSDC_TO_USDC)
TOKEN_IN="${CWUSDC}"
TOKEN_OUT="${USDC}"
;;
*)
echo "Unsupported DIRECTION: ${DIRECTION}; use USDC_TO_CWUSDC or CWUSDC_TO_USDC" >&2
exit 1
;;
esac
TOKEN0="$(printf '%s\n%s\n' "${CWUSDC}" "${USDC}" | tr '[:upper:]' '[:lower:]' | sort | sed -n '1p')"
TOKEN1="$(printf '%s\n%s\n' "${CWUSDC}" "${USDC}" | tr '[:upper:]' '[:lower:]' | sort | sed -n '2p')"
POOL="$(cast call "${FACTORY}" 'getPool(address,address,uint24)(address)' "${TOKEN0}" "${TOKEN1}" "${FEE}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | grep -oE '0x[a-fA-F0-9]{40}' | head -1)"
if [[ "${POOL}" == "0x0000000000000000000000000000000000000000" ]]; then
cat <<EOF
Engine X UniV3 public swap proof blocked
pool: not deployed
fee: ${FEE}
required first: pnpm engine-x:indexed-lp-migration against an upgraded vault
EOF
exit 0
fi
SLOT0="$(cast call "${POOL}" 'slot0()(uint160,int24,uint16,uint16,uint16,uint8,bool)' --rpc-url "${ETHEREUM_MAINNET_RPC}")"
LIQUIDITY="$(cast call "${POOL}" 'liquidity()(uint128)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
QUOTE_OUT_RAW="$(
cast call "${QUOTER}" \
'quoteExactInputSingle((address,address,uint256,uint24,uint160))(uint256,uint160,uint32,uint256)' \
"(${TOKEN_IN},${TOKEN_OUT},${AMOUNT_IN_RAW},${FEE},0)" \
--rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null | awk '{print $1}' || true
)"
QUOTE_OUT_RAW="${QUOTE_OUT_RAW:-0}"
MIN_OUT_RAW="$((QUOTE_OUT_RAW * (10000 - SLIPPAGE_BPS) / 10000))"
DEADLINE="$(( $(date +%s) + DEADLINE_SECONDS ))"
cat <<EOF
Engine X UniV3 public swap proof plan
mode: ${EXECUTE}
signer: ${SIGNER}
direction: ${DIRECTION}
pool: ${POOL}
fee: ${FEE}
slot0: ${SLOT0}
liquidity: ${LIQUIDITY}
token in: ${TOKEN_IN}
token out: ${TOKEN_OUT}
amount in raw: ${AMOUNT_IN_RAW}
quote out raw: ${QUOTE_OUT_RAW}
min out raw: ${MIN_OUT_RAW}
EOF
if [[ "${QUOTE_OUT_RAW}" == "0" ]]; then
echo "Quote is zero or unavailable; no broadcast command emitted."
exit 0
fi
if [[ "${EXECUTE}" != "1" ]]; then
cat <<EOF
Dry-run only. Review commands:
cast send "${TOKEN_IN}" 'approve(address,uint256)' "${ROUTER}" "${AMOUNT_IN_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
cast send "${ROUTER}" 'exactInputSingle((address,address,uint24,address,uint256,uint256,uint256,uint160))(uint256)' "(${TOKEN_IN},${TOKEN_OUT},${FEE},${SIGNER},${DEADLINE},${AMOUNT_IN_RAW},${MIN_OUT_RAW},0)" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
EOF
exit 0
fi
cast send "${TOKEN_IN}" 'approve(address,uint256)' "${ROUTER}" "${AMOUNT_IN_RAW}" --rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
cast send "${ROUTER}" 'exactInputSingle((address,address,uint24,address,uint256,uint256,uint256,uint160))(uint256)' \
"(${TOKEN_IN},${TOKEN_OUT},${FEE},${SIGNER},${DEADLINE},${AMOUNT_IN_RAW},${MIN_OUT_RAW},0)" \
--rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"

View File

@@ -85,7 +85,7 @@ _lpr_export_from_private_key
# 4b. Strip trailing CR/LF from RPC URL vars (editor mistakes; breaks cast/curl)
for _lpr_k in RPC_URL_138 RPC_URL CHAIN138_RPC CHAIN138_RPC_URL CHAIN_138_RPC_URL \
TOKEN_AGG_CHAIN138_RPC_URL TOKEN_AGGREGATION_CHAIN138_RPC_URL TOKEN_AGGREGATION_PMM_RPC_URL \
ETHEREUM_MAINNET_RPC \
INFURA_PROJECT_ID INFURA_API_KEY INFURA_PROJECT_SECRET ETHEREUM_MAINNET_RPC ETH_MAINNET_RPC_URL \
XDC_PARENTNET_URL PARENTNET_URL SUBNET_URL XDC_ZERO_PEER_RPC_URL \
RPC_URL_138_PUBLIC GNOSIS_MAINNET_RPC GNOSIS_RPC CRONOS_RPC_URL CRONOS_RPC \
CELO_MAINNET_RPC CELO_RPC WEMIX_RPC WEMIX_MAINNET_RPC BSC_RPC_URL \
@@ -110,6 +110,27 @@ for _lpr_id in 1 10 25 56 100 137 138 1111 8453 42161 42220 43114 651940; do
done
unset _lpr_k _lpr_v _lpr_id 2>/dev/null || true
# 4d. Ethereum RPC alias (dotenv often sets ETH_MAINNET_RPC_URL only)
export ETHEREUM_MAINNET_RPC="${ETHEREUM_MAINNET_RPC:-${ETH_MAINNET_RPC_URL:-}}"
export RPC_URL_MAINNET="${RPC_URL_MAINNET:-${ETHEREUM_MAINNET_RPC:-}}"
# 4e. Optional Infura: when INFURA_PROJECT_ID or INFURA_API_KEY is set, fill unset public-chain RPCs
# (Infura dashboard labels this value "API Key"; JSON-RPC path is always .../v3/<that_value>.)
_lpr_inf="${INFURA_PROJECT_ID:-${INFURA_API_KEY:-}}"
if [[ -n "$_lpr_inf" ]]; then
[[ -z "${ETHEREUM_MAINNET_RPC:-}" ]] && export ETHEREUM_MAINNET_RPC="https://mainnet.infura.io/v3/${_lpr_inf}"
export RPC_URL_MAINNET="${RPC_URL_MAINNET:-${ETHEREUM_MAINNET_RPC:-}}"
[[ -z "${POLYGON_MAINNET_RPC:-}" ]] && [[ -z "${POLYGON_RPC_URL:-}" ]] && export POLYGON_MAINNET_RPC="https://polygon-mainnet.infura.io/v3/${_lpr_inf}"
[[ -z "${ARBITRUM_MAINNET_RPC:-}" ]] && [[ -z "${ARBITRUM_RPC_URL:-}" ]] && export ARBITRUM_MAINNET_RPC="https://arbitrum-mainnet.infura.io/v3/${_lpr_inf}"
[[ -z "${OPTIMISM_MAINNET_RPC:-}" ]] && [[ -z "${OPTIMISM_RPC_URL:-}" ]] && export OPTIMISM_MAINNET_RPC="https://optimism-mainnet.infura.io/v3/${_lpr_inf}"
[[ -z "${BASE_MAINNET_RPC:-}" ]] && [[ -z "${BASE_RPC_URL:-}" ]] && export BASE_MAINNET_RPC="https://base-mainnet.infura.io/v3/${_lpr_inf}"
[[ -z "${AVALANCHE_MAINNET_RPC:-}" ]] && [[ -z "${AVALANCHE_RPC_URL:-}" ]] && export AVALANCHE_MAINNET_RPC="https://avalanche-mainnet.infura.io/v3/${_lpr_inf}"
[[ -z "${BSC_RPC_URL:-}" ]] && [[ -z "${BSC_MAINNET_RPC:-}" ]] && export BSC_RPC_URL="https://bnb-mainnet.infura.io/v3/${_lpr_inf}"
[[ -z "${GNOSIS_MAINNET_RPC:-}" ]] && [[ -z "${GNOSIS_RPC_URL:-}" ]] && [[ -z "${GNOSIS_RPC:-}" ]] && export GNOSIS_MAINNET_RPC="https://gnosis-mainnet.infura.io/v3/${_lpr_inf}"
[[ -z "${CELO_MAINNET_RPC:-}" ]] && [[ -z "${CELO_RPC_URL:-}" ]] && [[ -z "${CELO_RPC:-}" ]] && export CELO_MAINNET_RPC="https://celo-mainnet.infura.io/v3/${_lpr_inf}"
fi
unset _lpr_inf
# 5. Contract addresses from master JSON (config/smart-contracts-master.json) when not set by .env
[[ -f "${PROJECT_ROOT}/scripts/lib/load-contract-addresses.sh" ]] && source "${PROJECT_ROOT}/scripts/lib/load-contract-addresses.sh" 2>/dev/null || true

View File

@@ -0,0 +1,128 @@
#!/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"
OUT_DIR="${OUT_DIR:-reports/status}"
MANIFEST_JSON="${MANIFEST_JSON:-${OUT_DIR}/engine-x-audit-manifest-latest.json}"
MANIFEST_MD="${MANIFEST_MD:-${OUT_DIR}/engine-x-audit-manifest-latest.md}"
mkdir -p "${PROJECT_ROOT}/${OUT_DIR}"
V2_ABI="${OUT_DIR}/engine-x-v2-vault-abi-latest.json"
INDEXED_ABI="${OUT_DIR}/engine-x-indexed-liquidity-vault-abi-latest.json"
BORROWER_ABI="${OUT_DIR}/engine-x-flash-proof-borrower-abi-latest.json"
pushd "${PROJECT_ROOT}/smom-dbis-138" >/dev/null
forge inspect contracts/flash/DBISEngineXVirtualBatchVault.sol:DBISEngineXVirtualBatchVault abi >"${PROJECT_ROOT}/${V2_ABI}"
forge inspect contracts/flash/DBISEngineXIndexedLiquidityVault.sol:DBISEngineXIndexedLiquidityVault abi >"${PROJECT_ROOT}/${INDEXED_ABI}"
forge inspect contracts/flash/DBISEngineXFlashProofBorrower.sol:DBISEngineXFlashProofBorrower abi >"${PROJECT_ROOT}/${BORROWER_ABI}"
popd >/dev/null
python3 - "${PROJECT_ROOT}" "${MANIFEST_JSON}" "${MANIFEST_MD}" "${V2_ABI}" "${INDEXED_ABI}" "${BORROWER_ABI}" <<'PY'
import hashlib
import json
from pathlib import Path
import sys
from datetime import datetime, timezone
root = Path(sys.argv[1])
manifest_json = root / sys.argv[2]
manifest_md = root / sys.argv[3]
abi_paths = [Path(p) for p in sys.argv[4:]]
def sha256(path: Path) -> str:
return "0x" + hashlib.sha256((root / path).read_bytes()).hexdigest()
contracts = [
{
"name": "DBISEngineXVirtualBatchVault",
"source": "smom-dbis-138/contracts/flash/DBISEngineXVirtualBatchVault.sol",
"abi": str(abi_paths[0]),
"abiSha256": sha256(abi_paths[0]),
"constructorArgs": [
"cWUSDC",
"USDC",
"XAUt",
"owner",
"surplusReceiver",
"xautUsdPrice6",
"ltvBps",
"maxRoundTripLossBps",
],
},
{
"name": "DBISEngineXIndexedLiquidityVault",
"source": "smom-dbis-138/contracts/flash/DBISEngineXIndexedLiquidityVault.sol",
"abi": str(abi_paths[1]),
"abiSha256": sha256(abi_paths[1]),
"constructorArgs": [
"cWUSDC",
"USDC",
"uniV3Pool",
"owner",
"maxAbsTick",
"minLiquidity",
"maxProofSwapAmount",
],
},
{
"name": "DBISEngineXFlashProofBorrower",
"source": "smom-dbis-138/contracts/flash/DBISEngineXFlashProofBorrower.sol",
"abi": str(abi_paths[2]),
"abiSha256": sha256(abi_paths[2]),
"constructorArgs": ["lender", "USDC", "owner"],
},
]
payload = {
"schema": "engine-x-audit-manifest/v1",
"generatedAt": datetime.now(timezone.utc).isoformat(),
"contracts": contracts,
"operatorScripts": [
"scripts/deployment/deploy-engine-x-v2-mainnet.sh",
"scripts/deployment/migrate-engine-x-vault-to-mainnet-cwusdc-usdc-univ3.sh",
"scripts/deployment/deploy-engine-x-indexed-liquidity-vault-mainnet.sh",
"scripts/deployment/run-engine-x-univ3-public-swap-proof.sh",
"scripts/deployment/record-engine-x-indexed-liquidity-proof.sh",
"scripts/deployment/retire-engine-x-legacy-vault.sh",
"scripts/verify/check-engine-x-public-indexed-readiness.sh",
],
"reports": [
"reports/status/mainnet-engine-x-indexed-liquidity-upgrade-plan-20260507.md",
"reports/status/mainnet-cwusdc-cross-protocol-public-lp-proof-plan-20260507.md",
"reports/status/engine-x-public-indexed-readiness-latest.json",
],
"proofRequirements": [
"verified deployed source",
"constructor args",
"public UniV3 liquidity tx hash",
"actual public cWUSDC/USDC swap tx hash",
"pre/post pool slot0 and liquidity",
"ISO 20022-style hash",
"audit envelope hash",
"peg proof hash",
],
}
manifest_json.write_text(json.dumps(payload, indent=2) + "\n")
lines = [
"# Engine X Audit Manifest",
"",
f"- Generated: `{payload['generatedAt']}`",
"",
"## Contracts",
]
for c in contracts:
lines.append(f"- `{c['name']}`: `{c['source']}` ABI `{c['abi']}` hash `{c['abiSha256']}`")
lines.extend(["", "## Operator Scripts"])
lines.extend(f"- `{s}`" for s in payload["operatorScripts"])
lines.extend(["", "## Proof Requirements"])
lines.extend(f"- {r}" for r in payload["proofRequirements"])
manifest_md.write_text("\n".join(lines) + "\n")
print(manifest_json)
print(manifest_md)
PY

View File

@@ -0,0 +1,169 @@
#!/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"
: "${ETHEREUM_MAINNET_RPC:?ETHEREUM_MAINNET_RPC is required}"
OUT_JSON="${OUT_JSON:-reports/status/engine-x-public-indexed-readiness-latest.json}"
OUT_MD="${OUT_MD:-reports/status/engine-x-public-indexed-readiness-latest.md}"
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
USDC="${USDC_MAINNET:-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48}"
V2_PAIR="${MAINNET_CWUSDC_USDC_UNIV2_PAIR:-0xC28706F899266b36BC43cc072b3a921BDf2C48D9}"
V3_FACTORY="${CHAIN_1_UNISWAP_V3_FACTORY:-0x1F98431c8aD98523631AE4a59f267346ea31F984}"
V3_FEE="${ENGINE_X_UNIV3_FEE:-100}"
VAULT="${DBIS_ENGINE_X_V2_VAULT:-${ENGINE_X_VAULT:-0x9a22a3e272A364D64240dE6bda796FcA421cA7E9}}"
INDEXED_VAULT="${ENGINE_X_INDEXED_LIQUIDITY_VAULT:-}"
if [[ -n "${PRIVATE_KEY:-}" ]]; then
DEPLOYER="$(cast wallet address --private-key "${PRIVATE_KEY}")"
else
DEPLOYER="${DEPLOYER_ADDRESS:-}"
fi
TOKEN0="$(printf '%s\n%s\n' "${CWUSDC}" "${USDC}" | tr '[:upper:]' '[:lower:]' | sort | sed -n '1p')"
TOKEN1="$(printf '%s\n%s\n' "${CWUSDC}" "${USDC}" | tr '[:upper:]' '[:lower:]' | sort | sed -n '2p')"
V3_POOL="$(cast call "${V3_FACTORY}" 'getPool(address,address,uint24)(address)' "${TOKEN0}" "${TOKEN1}" "${V3_FEE}" --rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null | grep -oE '0x[a-fA-F0-9]{40}' | head -1 || true)"
V3_POOL="${V3_POOL:-0x0000000000000000000000000000000000000000}"
ACCOUNTING_AWARE="0"
cast call "${VAULT}" 'maxFlashLoan(address)(uint256)' "${USDC}" --rpc-url "${ETHEREUM_MAINNET_RPC}" >/dev/null 2>&1 && ACCOUNTING_AWARE="1"
POOL_CWUSDC_RAW="$(cast call "${VAULT}" 'poolCwusdcReserve()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null | awk '{print $1}' || echo 0)"
POOL_USDC_RAW="$(cast call "${VAULT}" 'poolUsdcReserve()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null | awk '{print $1}' || echo 0)"
LENDER_USDC_RAW="$(cast call "${VAULT}" 'lenderUsdcAvailable()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null | awk '{print $1}' || echo 0)"
V2_RESERVES="$(cast call "${V2_PAIR}" 'getReserves()(uint112,uint112,uint32)' --rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null || true)"
V3_SLOT0=""
V3_LIQUIDITY="0"
V3_TOKEN0_BALANCE="0"
V3_TOKEN1_BALANCE="0"
if [[ "${V3_POOL}" != "0x0000000000000000000000000000000000000000" ]]; then
V3_SLOT0="$(cast call "${V3_POOL}" 'slot0()(uint160,int24,uint16,uint16,uint16,uint8,bool)' --rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null || true)"
V3_LIQUIDITY="$(cast call "${V3_POOL}" 'liquidity()(uint128)' --rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null | awk '{print $1}' || echo 0)"
V3_TOKEN0_BALANCE="$(cast call "${TOKEN0}" 'balanceOf(address)(uint256)' "${V3_POOL}" --rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null | awk '{print $1}' || echo 0)"
V3_TOKEN1_BALANCE="$(cast call "${TOKEN1}" 'balanceOf(address)(uint256)' "${V3_POOL}" --rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null | awk '{print $1}' || echo 0)"
fi
WALLET_CWUSDC_RAW="0"
WALLET_USDC_RAW="0"
if [[ -n "${DEPLOYER}" ]]; then
WALLET_CWUSDC_RAW="$(cast call "${CWUSDC}" 'balanceOf(address)(uint256)' "${DEPLOYER}" --rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null | awk '{print $1}' || echo 0)"
WALLET_USDC_RAW="$(cast call "${USDC}" 'balanceOf(address)(uint256)' "${DEPLOYER}" --rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null | awk '{print $1}' || echo 0)"
fi
mkdir -p "$(dirname "${OUT_JSON}")"
python3 - "${OUT_JSON}" "${OUT_MD}" \
"${VAULT}" "${ACCOUNTING_AWARE}" "${POOL_CWUSDC_RAW}" "${POOL_USDC_RAW}" "${LENDER_USDC_RAW}" \
"${INDEXED_VAULT}" "${V3_POOL}" "${V3_SLOT0}" "${V3_LIQUIDITY}" "${V3_TOKEN0_BALANCE}" "${V3_TOKEN1_BALANCE}" \
"${V2_PAIR}" "${V2_RESERVES}" "${DEPLOYER:-}" "${WALLET_CWUSDC_RAW}" "${WALLET_USDC_RAW}" <<'PY'
from decimal import Decimal
import json
from pathlib import Path
import re
import sys
from datetime import datetime, timezone
(
out_json,
out_md,
vault,
accounting_aware,
pool_cw,
pool_usdc,
lender_usdc,
indexed_vault,
v3_pool,
v3_slot0,
v3_liquidity,
v3_token0,
v3_token1,
v2_pair,
v2_reserves,
deployer,
wallet_cw,
wallet_usdc,
) = sys.argv[1:]
def units(raw):
return str(Decimal(int(raw or 0)) / Decimal(10**6))
v2_nums = [int(x) for x in re.findall(r"\b\d+\b", v2_reserves or "")]
blockers = []
if accounting_aware != "1":
blockers.append("configured Engine X vault is not accounting-aware")
if v3_pool.lower() == "0x0000000000000000000000000000000000000000":
blockers.append("UniV3 cWUSDC/USDC public pool is not deployed")
if int(v3_liquidity or 0) == 0:
blockers.append("UniV3 public pool has zero active liquidity")
if not indexed_vault:
blockers.append("Engine X indexed-liquidity proof vault is not configured")
if not deployer:
blockers.append("deployer address unavailable")
payload = {
"schema": "engine-x-public-indexed-readiness/v1",
"generatedAt": datetime.now(timezone.utc).isoformat(),
"summary": {
"readyForPublicIndexedProof": not blockers,
"blockers": blockers,
},
"engineXV2Vault": {
"address": vault,
"accountingAware": accounting_aware == "1",
"poolCwusdcRaw": pool_cw,
"poolCwusdc": units(pool_cw),
"poolUsdcRaw": pool_usdc,
"poolUsdc": units(pool_usdc),
"lenderUsdcRaw": lender_usdc,
"lenderUsdc": units(lender_usdc),
},
"indexedProofVault": {"address": indexed_vault or None},
"uniV3": {
"pool": v3_pool,
"slot0": v3_slot0 or None,
"liquidity": v3_liquidity,
"token0BalanceRaw": v3_token0,
"token1BalanceRaw": v3_token1,
"token0Balance": units(v3_token0),
"token1Balance": units(v3_token1),
},
"uniV2": {
"pair": v2_pair,
"rawReserves": v2_nums[:2],
},
"deployer": {
"address": deployer or None,
"cwusdcRaw": wallet_cw,
"cwusdc": units(wallet_cw),
"usdcRaw": wallet_usdc,
"usdc": units(wallet_usdc),
},
}
Path(out_json).write_text(json.dumps(payload, indent=2) + "\n")
lines = [
"# Engine X Public Indexed Readiness",
"",
f"- Generated: `{payload['generatedAt']}`",
f"- Ready: `{payload['summary']['readyForPublicIndexedProof']}`",
f"- Engine X v2 vault: `{vault}`",
f"- Accounting-aware: `{payload['engineXV2Vault']['accountingAware']}`",
f"- UniV3 pool: `{v3_pool}`",
f"- UniV3 liquidity: `{v3_liquidity}`",
f"- Indexed proof vault: `{indexed_vault or 'not configured'}`",
f"- Deployer USDC: `{payload['deployer']['usdc']}`",
f"- Deployer cWUSDC: `{payload['deployer']['cwusdc']}`",
"",
"## Blockers",
]
if blockers:
lines.extend(f"- {b}" for b in blockers)
else:
lines.append("- none")
Path(out_md).write_text("\n".join(lines) + "\n")
print(out_json)
print(out_md)
PY

View File

@@ -131,6 +131,23 @@ def funding_status(required_raw: int, available_raw: int, decimals: int = 6) ->
}
def public_reseed_status(
base_shortfall_raw: int,
quote_shortfall_raw: int,
base_funding: dict,
quote_funding: dict,
) -> str:
if base_shortfall_raw == 0 and quote_shortfall_raw == 0:
return "ready"
if quote_shortfall_raw > 0 and not quote_funding["covered"]:
return "needs_usdc"
if base_shortfall_raw > 0 and not base_funding["covered"]:
return "needs_cwusdc"
if quote_shortfall_raw > 0:
return "needs_quote_side_repair"
return "needs_base_side_reseed"
def build_plan(snapshot: dict, policy: dict, env_values: dict[str, str], holder_override: str) -> dict:
rpc_url = resolve_env_value("ETHEREUM_MAINNET_RPC", env_values)
if not rpc_url:
@@ -217,6 +234,11 @@ def build_plan(snapshot: dict, policy: dict, env_values: dict[str, str], holder_
if any("defended quote query failed" in warning for warning in warnings):
blockers.append("defended pool quote preview reverted; set MIN_BASE_OUT_RAW manually before any quote-in trade")
public_deviation_bps = Decimal(str(summary["publicPairDeviationBps"]))
public_price_distorted = public_deviation_bps >= Decimal(str(policy["thresholds"]["warnDeviationBps"]))
if public_price_distorted:
warnings.append("public pair is materially asymmetric; plain addLiquidity follows the current reserve ratio and will not repair price")
operator_commands = {
"rerunPreflight": "bash scripts/verify/snapshot-mainnet-cwusdc-usdc-preflight.sh",
"rerunPlan": "bash scripts/verify/plan-mainnet-cwusdc-usdc-repeg.sh",
@@ -272,7 +294,42 @@ def build_plan(snapshot: dict, policy: dict, env_values: dict[str, str], holder_
]
)
recommended_actions = [
if (
public_base_shortfall_raw > 0
or public_quote_shortfall_raw > 0
or public_price_distorted
):
operator_commands["publicPairRepairGuidance"] = command_block(
[
"# Public cWUSDC/USDC is one-sided or price-distorted.",
"# Do not use addLiquidity by itself as a price repair when only one reserve side is short.",
"# Use official Mainnet USDC for a quote-side repair swap first, then add balanced",
"# liquidity only after the reserve-implied price is back inside policy gates.",
"bash scripts/verify/snapshot-mainnet-cwusdc-usdc-preflight.sh",
"bash scripts/verify/plan-mainnet-cwusdc-usdc-repeg.sh",
]
)
public_action_status = public_reseed_status(
public_base_shortfall_raw,
public_quote_shortfall_raw,
public_base_funding,
public_quote_funding,
)
needs_external_funding = (
not defended_quote_funding["covered"]
or not public_base_funding["covered"]
or not public_quote_funding["covered"]
)
recommended_next_action = "execute_verified_repair"
if public_quote_shortfall_raw > 0 and not public_quote_funding["covered"]:
recommended_next_action = "acquire_official_mainnet_usdc"
elif public_quote_shortfall_raw > 0 or public_price_distorted:
recommended_next_action = "run_quote_side_public_pair_repair_before_balanced_liquidity"
elif add_quote_raw > 0 and not defended_quote_funding["covered"]:
recommended_next_action = "acquire_official_mainnet_usdc_for_defended_parity"
recommended_actions = [
{
"step": "fund_manager_for_one_max_cycle",
"quoteAmountRaw": str(max_automated_raw),
@@ -292,11 +349,11 @@ def build_plan(snapshot: dict, policy: dict, env_values: dict[str, str], holder_
"baseAmountUnits": str(normalize_units(public_base_shortfall_raw)),
"quoteAmountRaw": str(public_quote_shortfall_raw),
"quoteAmountUnits": str(normalize_units(public_quote_shortfall_raw)),
"status": (
"ready"
if public_base_shortfall_raw == 0
or (public_base_funding["covered"] and public_quote_funding["covered"])
else "needs_inventory"
"status": public_action_status,
"guidance": (
"Use quote-side repair before balanced liquidity; plain addLiquidity cannot repair an asymmetric public pair."
if public_quote_shortfall_raw > 0 or public_price_distorted
else "Use addLiquidity only after price and reserve gates pass."
),
},
]
@@ -304,6 +361,23 @@ def build_plan(snapshot: dict, policy: dict, env_values: dict[str, str], holder_
return {
"generatedAt": datetime.now(timezone.utc).isoformat(),
"mode": "read_only_repeg_plan",
"summary": {
"publicPairBaseReserveUnits": str(public_base_units),
"publicPairQuoteReserveUnits": str(public_quote_units),
"publicPairDeviationBps": str(summary["publicPairDeviationBps"]),
"publicPolicyFloorBaseShortfallUnits": str(normalize_units(public_base_shortfall_raw)),
"publicPolicyFloorQuoteShortfallUnits": str(normalize_units(public_quote_shortfall_raw)),
"publicPairRepairRequiresQuoteSideAction": public_quote_shortfall_raw > 0 or public_price_distorted,
"publicIndexedLpComplianceStatus": (
"blocked_missing_quote_side_public_lp_evidence"
if public_quote_shortfall_raw > 0 or public_price_distorted
else "ready_for_evidence_review"
),
"defendedAddQuoteUnits": str(normalize_units(add_quote_raw)),
"managerFundingShortfallUnits": manager_funding["shortfallUnits"],
"needsExternalFunding": needs_external_funding,
"recommendedNextAction": recommended_next_action,
},
"snapshotPath": str(LATEST_SNAPSHOT),
"policyPath": str(POLICY_PATH),
"inferenceNotes": [
@@ -370,11 +444,7 @@ def build_plan(snapshot: dict, policy: dict, env_values: dict[str, str], holder_
"blockers": holder_blockers + blockers,
"status": {
"canFullyReachSimple1To1WithCurrentHolder": len(holder_blockers + blockers) == 0,
"needsExternalFunding": (
not defended_quote_funding["covered"]
or not public_base_funding["covered"]
or not public_quote_funding["covered"]
),
"needsExternalFunding": needs_external_funding,
"canFundManagerFromCurrentHolder": holder_usdc_raw >= max_automated_raw if holder_state else None,
},
}