chore: update .env.master.example with new deployment scripts and treasury manager parameters; enhance AGENTS.md with GRU reference primacy details

- Added new deployment script references for Aave quote-push and treasury manager in .env.master.example.
- Updated AGENTS.md to include information on GRU reference primacy versus public PMM mesh execution model.
- Minor updates to various documentation files to reflect changes in policy and operational guidelines.

Made-with: Cursor
This commit is contained in:
defiQUG
2026-04-12 18:20:41 -07:00
parent 6945f69d7d
commit 0d29343941
133 changed files with 7017 additions and 539 deletions

View File

@@ -0,0 +1,107 @@
#!/usr/bin/env bash
set -euo pipefail
# Deploy only the Mainnet Aave quote-push receiver.
# Default: simulation only. Use --apply to broadcast.
#
# Env:
# PRIVATE_KEY, ETHEREUM_MAINNET_RPC required
# AAVE_POOL_ADDRESS optional; defaults inside the Forge script
# QUOTE_PUSH_RECEIVER_OWNER optional; defaults to deployer derived from PRIVATE_KEY
#
# Usage:
# bash scripts/deployment/deploy-mainnet-aave-quote-push-receiver.sh --dry-run
# bash scripts/deployment/deploy-mainnet-aave-quote-push-receiver.sh --apply
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROXMOX_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
SMOM="${PROXMOX_ROOT}/smom-dbis-138"
_qp_private_key="${PRIVATE_KEY-}"
_qp_rpc="${ETHEREUM_MAINNET_RPC-}"
_qp_pool="${AAVE_POOL_ADDRESS-}"
_qp_owner="${QUOTE_PUSH_RECEIVER_OWNER-}"
# shellcheck disable=SC1091
source "${PROXMOX_ROOT}/scripts/lib/load-project-env.sh" 2>/dev/null || true
# shellcheck disable=SC1091
source "${SMOM}/scripts/load-env.sh" >/dev/null 2>&1 || true
[[ -n "$_qp_private_key" ]] && export PRIVATE_KEY="$_qp_private_key"
[[ -n "$_qp_rpc" ]] && export ETHEREUM_MAINNET_RPC="$_qp_rpc"
[[ -n "$_qp_pool" ]] && export AAVE_POOL_ADDRESS="$_qp_pool"
[[ -n "$_qp_owner" ]] && export QUOTE_PUSH_RECEIVER_OWNER="$_qp_owner"
unset _qp_private_key _qp_rpc _qp_pool _qp_owner
require_cmd() {
command -v "$1" >/dev/null 2>&1 || {
echo "[fail] missing required command: $1" >&2
exit 1
}
}
require_env() {
local name="$1"
if [[ -z "${!name:-}" ]]; then
echo "[fail] missing required env: $name" >&2
exit 1
fi
}
pick_latest_receiver() {
local mode="$1"
local latest_json="${SMOM}/broadcast/DeployAaveQuotePushFlashReceiver.s.sol/1/run-latest.json"
if [[ "$mode" == "dry-run" ]]; then
latest_json="${SMOM}/broadcast/DeployAaveQuotePushFlashReceiver.s.sol/1/dry-run/run-latest.json"
fi
if [[ ! -f "$latest_json" ]] || ! command -v jq >/dev/null 2>&1; then
return 1
fi
jq -r '.transactions[]? | select(.transactionType == "CREATE" and .contractName == "AaveQuotePushFlashReceiver") | .contractAddress' \
"$latest_json" | tail -n1
}
require_cmd forge
MODE="dry-run"
BROADCAST=()
for arg in "$@"; do
case "$arg" in
--dry-run) MODE="dry-run"; BROADCAST=() ;;
--apply) MODE="apply"; BROADCAST=(--broadcast) ;;
*)
echo "[fail] unknown arg: $arg (use --dry-run or --apply)" >&2
exit 2
;;
esac
done
require_env PRIVATE_KEY
require_env ETHEREUM_MAINNET_RPC
echo "=== deploy-mainnet-aave-quote-push-receiver ($MODE) ==="
if [[ -n "${QUOTE_PUSH_RECEIVER_OWNER:-}" ]]; then
echo "receiver_owner=$QUOTE_PUSH_RECEIVER_OWNER"
fi
(
cd "$SMOM"
forge script script/deploy/DeployAaveQuotePushFlashReceiver.s.sol:DeployAaveQuotePushFlashReceiver \
--rpc-url "$ETHEREUM_MAINNET_RPC" \
"${BROADCAST[@]}" \
-vvvv
)
receiver_addr="$(pick_latest_receiver "$MODE" || true)"
echo
if [[ "$MODE" == "dry-run" ]]; then
echo "Projected receiver address from this dry-run:"
else
echo "After --apply: copy deployed address into .env:"
fi
echo " AAVE_QUOTE_PUSH_RECEIVER_MAINNET=${receiver_addr:-...}"
echo "Shortest manager handoff:"
echo " AAVE_QUOTE_PUSH_RECEIVER_MAINNET=${receiver_addr:-...} QUOTE_PUSH_TREASURY_TAKE_RECEIVER_OWNERSHIP=1 bash scripts/deployment/deploy-mainnet-quote-push-treasury-manager.sh --apply"
echo "Full stack alternative:"
echo " bash scripts/deployment/deploy-mainnet-aave-quote-push-stack.sh --apply"

View File

@@ -3,6 +3,7 @@ set -euo pipefail
# Deploy Mainnet flash quote-push stack (Aave receiver + external unwinder).
# Default: simulation only (no --broadcast). Use --apply to broadcast.
# For receiver-only migrations, use deploy-mainnet-aave-quote-push-receiver.sh.
#
# Env:
# PRIVATE_KEY, ETHEREUM_MAINNET_RPC
@@ -165,6 +166,8 @@ unwinder_addr="$(pick_latest_create_address "$unwinder_script" "$unwinder_contra
echo "After --apply: copy deployed addresses into .env:"
echo " AAVE_QUOTE_PUSH_RECEIVER_MAINNET=${receiver_addr:-...}"
echo " QUOTE_PUSH_EXTERNAL_UNWINDER_MAINNET=${unwinder_addr:-...}"
echo "Optional retained-surplus manager:"
echo " QUOTE_PUSH_TREASURY_TAKE_RECEIVER_OWNERSHIP=1 bash scripts/deployment/deploy-mainnet-quote-push-treasury-manager.sh --apply"
echo "Or rerun immediately with QUOTE_PUSH_UNWINDER_TYPE=${UNW} so run-mainnet-aave-cwusdc-quote-push-once.sh can auto-pick the latest broadcast unwinder."
echo "Then set FLASH_QUOTE_AMOUNT_RAW, UNWIND_MODE, UNWIND_V3_FEE_U24 (or UNWIND_DODO_POOL / two-hop vars) and run:"
echo " bash scripts/deployment/run-mainnet-aave-cwusdc-quote-push-once.sh --dry-run"

View File

@@ -0,0 +1,137 @@
#!/usr/bin/env bash
set -euo pipefail
# Deploy the Mainnet quote-push treasury manager and optionally transfer the
# receiver ownership to it. Default: simulation only. Use --apply to broadcast.
#
# Env:
# PRIVATE_KEY, ETHEREUM_MAINNET_RPC required
# AAVE_QUOTE_PUSH_RECEIVER_MAINNET optional; auto-picks latest receiver broadcast
# QUOTE_PUSH_SURPLUS_TOKEN_MAINNET optional; defaults to mainnet USDC
# QUOTE_PUSH_TREASURY_OWNER optional; defaults to deployer
# QUOTE_PUSH_TREASURY_OPERATOR optional; defaults to owner
# QUOTE_PUSH_TREASURY_GAS_RECIPIENT optional; defaults to owner
# QUOTE_PUSH_TREASURY_RECYCLE_RECIPIENT optional; defaults to owner
# QUOTE_PUSH_RECEIVER_RESERVE_RAW optional; defaults to 0
# QUOTE_PUSH_TREASURY_RESERVE_RAW optional; defaults to 0
# QUOTE_PUSH_TREASURY_TAKE_RECEIVER_OWNERSHIP optional; 1 transfers receiver ownership to manager
#
# Usage:
# bash scripts/deployment/deploy-mainnet-quote-push-treasury-manager.sh --dry-run
# QUOTE_PUSH_TREASURY_TAKE_RECEIVER_OWNERSHIP=1 \
# bash scripts/deployment/deploy-mainnet-quote-push-treasury-manager.sh --apply
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROXMOX_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
SMOM="${PROXMOX_ROOT}/smom-dbis-138"
_qp_private_key="${PRIVATE_KEY-}"
_qp_rpc="${ETHEREUM_MAINNET_RPC-}"
_qp_receiver="${AAVE_QUOTE_PUSH_RECEIVER_MAINNET-}"
_qp_token="${QUOTE_PUSH_SURPLUS_TOKEN_MAINNET-}"
_qp_owner="${QUOTE_PUSH_TREASURY_OWNER-}"
_qp_operator="${QUOTE_PUSH_TREASURY_OPERATOR-}"
_qp_gas_recipient="${QUOTE_PUSH_TREASURY_GAS_RECIPIENT-}"
_qp_recycle_recipient="${QUOTE_PUSH_TREASURY_RECYCLE_RECIPIENT-}"
_qp_receiver_reserve="${QUOTE_PUSH_RECEIVER_RESERVE_RAW-}"
_qp_manager_reserve="${QUOTE_PUSH_TREASURY_RESERVE_RAW-}"
_qp_take_receiver="${QUOTE_PUSH_TREASURY_TAKE_RECEIVER_OWNERSHIP-}"
# shellcheck disable=SC1091
source "${PROXMOX_ROOT}/scripts/lib/load-project-env.sh" 2>/dev/null || true
# shellcheck disable=SC1091
source "${SMOM}/scripts/load-env.sh" >/dev/null 2>&1 || true
[[ -n "$_qp_private_key" ]] && export PRIVATE_KEY="$_qp_private_key"
[[ -n "$_qp_rpc" ]] && export ETHEREUM_MAINNET_RPC="$_qp_rpc"
[[ -n "$_qp_receiver" ]] && export AAVE_QUOTE_PUSH_RECEIVER_MAINNET="$_qp_receiver"
[[ -n "$_qp_token" ]] && export QUOTE_PUSH_SURPLUS_TOKEN_MAINNET="$_qp_token"
[[ -n "$_qp_owner" ]] && export QUOTE_PUSH_TREASURY_OWNER="$_qp_owner"
[[ -n "$_qp_operator" ]] && export QUOTE_PUSH_TREASURY_OPERATOR="$_qp_operator"
[[ -n "$_qp_gas_recipient" ]] && export QUOTE_PUSH_TREASURY_GAS_RECIPIENT="$_qp_gas_recipient"
[[ -n "$_qp_recycle_recipient" ]] && export QUOTE_PUSH_TREASURY_RECYCLE_RECIPIENT="$_qp_recycle_recipient"
[[ -n "$_qp_receiver_reserve" ]] && export QUOTE_PUSH_RECEIVER_RESERVE_RAW="$_qp_receiver_reserve"
[[ -n "$_qp_manager_reserve" ]] && export QUOTE_PUSH_TREASURY_RESERVE_RAW="$_qp_manager_reserve"
[[ -n "$_qp_take_receiver" ]] && export QUOTE_PUSH_TREASURY_TAKE_RECEIVER_OWNERSHIP="$_qp_take_receiver"
unset _qp_private_key _qp_rpc _qp_receiver _qp_token _qp_owner _qp_operator _qp_gas_recipient
unset _qp_recycle_recipient _qp_receiver_reserve _qp_manager_reserve _qp_take_receiver
require_cmd() {
command -v "$1" >/dev/null 2>&1 || {
echo "[fail] missing required command: $1" >&2
exit 1
}
}
require_env() {
local name="$1"
if [[ -z "${!name:-}" ]]; then
echo "[fail] missing required env: $name" >&2
exit 1
fi
}
pick_latest_create_address() {
local script_name="$1"
local contract_name="$2"
local mode="${3:-apply}"
local latest_json="${SMOM}/broadcast/${script_name}/1/run-latest.json"
if [[ "$mode" == "dry-run" ]]; then
latest_json="${SMOM}/broadcast/${script_name}/1/dry-run/run-latest.json"
fi
if [[ ! -f "$latest_json" ]] || ! command -v jq >/dev/null 2>&1; then
return 1
fi
jq -r --arg contract "$contract_name" \
'.transactions[]? | select(.transactionType == "CREATE" and .contractName == $contract) | .contractAddress' \
"$latest_json" | tail -n1
}
require_cmd forge
MODE="dry-run"
BROADCAST=()
for arg in "$@"; do
case "$arg" in
--dry-run) MODE="dry-run"; BROADCAST=() ;;
--apply) MODE="apply"; BROADCAST=(--broadcast) ;;
*)
echo "[fail] unknown arg: $arg (use --dry-run or --apply)" >&2
exit 2
;;
esac
done
require_env PRIVATE_KEY
require_env ETHEREUM_MAINNET_RPC
if [[ -z "${AAVE_QUOTE_PUSH_RECEIVER_MAINNET:-}" ]]; then
inferred_receiver="$(pick_latest_create_address "DeployAaveQuotePushFlashReceiver.s.sol" "AaveQuotePushFlashReceiver" "apply" || true)"
if [[ -n "$inferred_receiver" && "$inferred_receiver" != "null" ]]; then
export AAVE_QUOTE_PUSH_RECEIVER_MAINNET="$inferred_receiver"
fi
fi
require_env AAVE_QUOTE_PUSH_RECEIVER_MAINNET
echo "=== deploy-mainnet-quote-push-treasury-manager ($MODE) ==="
echo "receiver=$AAVE_QUOTE_PUSH_RECEIVER_MAINNET"
echo "take_receiver_ownership=${QUOTE_PUSH_TREASURY_TAKE_RECEIVER_OWNERSHIP:-0}"
(
cd "$SMOM"
forge script script/deploy/DeployQuotePushTreasuryManager.s.sol:DeployQuotePushTreasuryManager \
--rpc-url "$ETHEREUM_MAINNET_RPC" \
"${BROADCAST[@]}" \
-vvvv
)
manager_addr="$(pick_latest_create_address "DeployQuotePushTreasuryManager.s.sol" "QuotePushTreasuryManager" "$MODE" || true)"
echo
if [[ "$MODE" == "dry-run" ]]; then
echo "Projected treasury manager address from this dry-run:"
else
echo "After --apply: copy deployed addresses into .env:"
fi
echo " QUOTE_PUSH_TREASURY_MANAGER_MAINNET=${manager_addr:-...}"
echo "Optional keeper entrypoint:"
echo " bash scripts/deployment/run-mainnet-aave-quote-push-keeper.sh --dry-run"

View File

@@ -0,0 +1,124 @@
#!/usr/bin/env bash
set -euo pipefail
# Harvest receiver surplus into the treasury manager and/or distribute quote to
# the configured gas and recycle recipients. Default: simulation only.
#
# Env:
# PRIVATE_KEY, ETHEREUM_MAINNET_RPC required
# QUOTE_PUSH_TREASURY_MANAGER_MAINNET optional; auto-picks latest manager broadcast
# QUOTE_PUSH_TREASURY_HARVEST optional; defaults to 1
# QUOTE_PUSH_TREASURY_GAS_DISTRIBUTION_RAW optional; defaults to 0
# QUOTE_PUSH_TREASURY_RECYCLE_DISTRIBUTION_RAW optional; defaults to 0
#
# Usage:
# bash scripts/deployment/manage-mainnet-quote-push-treasury.sh --dry-run
# QUOTE_PUSH_TREASURY_GAS_DISTRIBUTION_RAW=1000 \
# QUOTE_PUSH_TREASURY_RECYCLE_DISTRIBUTION_RAW=2000 \
# bash scripts/deployment/manage-mainnet-quote-push-treasury.sh --apply
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROXMOX_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
SMOM="${PROXMOX_ROOT}/smom-dbis-138"
_qp_private_key="${PRIVATE_KEY-}"
_qp_rpc="${ETHEREUM_MAINNET_RPC-}"
_qp_manager="${QUOTE_PUSH_TREASURY_MANAGER_MAINNET-}"
_qp_harvest="${QUOTE_PUSH_TREASURY_HARVEST-}"
_qp_gas_raw="${QUOTE_PUSH_TREASURY_GAS_DISTRIBUTION_RAW-}"
_qp_recycle_raw="${QUOTE_PUSH_TREASURY_RECYCLE_DISTRIBUTION_RAW-}"
# shellcheck disable=SC1091
source "${PROXMOX_ROOT}/scripts/lib/load-project-env.sh" 2>/dev/null || true
# shellcheck disable=SC1091
source "${SMOM}/scripts/load-env.sh" >/dev/null 2>&1 || true
[[ -n "$_qp_private_key" ]] && export PRIVATE_KEY="$_qp_private_key"
[[ -n "$_qp_rpc" ]] && export ETHEREUM_MAINNET_RPC="$_qp_rpc"
[[ -n "$_qp_manager" ]] && export QUOTE_PUSH_TREASURY_MANAGER_MAINNET="$_qp_manager"
[[ -n "$_qp_harvest" ]] && export QUOTE_PUSH_TREASURY_HARVEST="$_qp_harvest"
[[ -n "$_qp_gas_raw" ]] && export QUOTE_PUSH_TREASURY_GAS_DISTRIBUTION_RAW="$_qp_gas_raw"
[[ -n "$_qp_recycle_raw" ]] && export QUOTE_PUSH_TREASURY_RECYCLE_DISTRIBUTION_RAW="$_qp_recycle_raw"
unset _qp_private_key _qp_rpc _qp_manager _qp_harvest _qp_gas_raw _qp_recycle_raw
require_cmd() {
command -v "$1" >/dev/null 2>&1 || {
echo "[fail] missing required command: $1" >&2
exit 1
}
}
require_env() {
local name="$1"
if [[ -z "${!name:-}" ]]; then
echo "[fail] missing required env: $name" >&2
exit 1
fi
}
pick_latest_manager() {
local latest_json="${SMOM}/broadcast/DeployQuotePushTreasuryManager.s.sol/1/run-latest.json"
if [[ ! -f "$latest_json" ]] || ! command -v jq >/dev/null 2>&1; then
return 1
fi
jq -r '.transactions[]? | select(.transactionType == "CREATE" and .contractName == "QuotePushTreasuryManager") | .contractAddress' \
"$latest_json" | tail -n1
}
require_cmd cast
require_cmd forge
MODE="dry-run"
BROADCAST=()
for arg in "$@"; do
case "$arg" in
--dry-run) MODE="dry-run"; BROADCAST=() ;;
--apply) MODE="apply"; BROADCAST=(--broadcast) ;;
*)
echo "[fail] unknown arg: $arg (use --dry-run or --apply)" >&2
exit 2
;;
esac
done
require_env PRIVATE_KEY
require_env ETHEREUM_MAINNET_RPC
if [[ -z "${QUOTE_PUSH_TREASURY_MANAGER_MAINNET:-}" ]]; then
inferred_manager="$(pick_latest_manager || true)"
if [[ -n "$inferred_manager" && "$inferred_manager" != "null" ]]; then
export QUOTE_PUSH_TREASURY_MANAGER_MAINNET="$inferred_manager"
fi
fi
require_env QUOTE_PUSH_TREASURY_MANAGER_MAINNET
DEPLOYER="$(cast wallet address --private-key "$PRIVATE_KEY")"
manager_owner="$(cast call "$QUOTE_PUSH_TREASURY_MANAGER_MAINNET" 'owner()(address)' --rpc-url "$ETHEREUM_MAINNET_RPC" | awk '{print $1}')"
manager_operator="$(cast call "$QUOTE_PUSH_TREASURY_MANAGER_MAINNET" 'operator()(address)' --rpc-url "$ETHEREUM_MAINNET_RPC" | awk '{print $1}')"
if [[ "${manager_owner,,}" != "${DEPLOYER,,}" && "${manager_operator,,}" != "${DEPLOYER,,}" ]]; then
echo "[fail] deployer $DEPLOYER is neither manager owner ($manager_owner) nor operator ($manager_operator)" >&2
exit 1
fi
quote_balance="$(cast call "$QUOTE_PUSH_TREASURY_MANAGER_MAINNET" 'quoteBalance()(uint256)' --rpc-url "$ETHEREUM_MAINNET_RPC" | awk '{print $1}')"
available_quote="$(cast call "$QUOTE_PUSH_TREASURY_MANAGER_MAINNET" 'availableQuote()(uint256)' --rpc-url "$ETHEREUM_MAINNET_RPC" | awk '{print $1}')"
receiver_sweepable="$(cast call "$QUOTE_PUSH_TREASURY_MANAGER_MAINNET" 'receiverSweepableQuote()(uint256)' --rpc-url "$ETHEREUM_MAINNET_RPC" | awk '{print $1}')"
echo "=== manage-mainnet-quote-push-treasury ($MODE) ==="
echo "manager=$QUOTE_PUSH_TREASURY_MANAGER_MAINNET"
echo "manager_owner=$manager_owner"
echo "manager_operator=$manager_operator"
echo "harvest=${QUOTE_PUSH_TREASURY_HARVEST:-1}"
echo "gas_distribution_raw=${QUOTE_PUSH_TREASURY_GAS_DISTRIBUTION_RAW:-0}"
echo "recycle_distribution_raw=${QUOTE_PUSH_TREASURY_RECYCLE_DISTRIBUTION_RAW:-0}"
echo "quote_balance_raw=$quote_balance"
echo "available_quote_raw=$available_quote"
echo "receiver_sweepable_raw=$receiver_sweepable"
(
cd "$SMOM"
forge script script/flash/ManageQuotePushTreasuryManager.s.sol:ManageQuotePushTreasuryManager \
--rpc-url "$ETHEREUM_MAINNET_RPC" \
"${BROADCAST[@]}" \
-vvvv
)

View File

@@ -10,6 +10,8 @@ set -euo pipefail
# (Aave flashLoan USDC → PMM swap USDC→cWUSDC → external unwind cWUSDC→USDC
# → repay Aave + premium). Each successful round **raises PMM quote reserves** and
# **draws base** from the pool, moving base-heavy / quote-thin books toward peg.
# Retained quote surplus stays on the receiver until swept by the owner and can
# then be recycled into wallet-funded pool growth.
#
# This script is read-only + local modeling:
# - reads live pool reserves (cast)
@@ -102,7 +104,12 @@ echo
echo "4) Reserve peg monitor after any live work:"
echo " bash scripts/verify/check-mainnet-cwusdc-usdc-reserve-peg.sh"
echo
echo "5) Pick a valid Uniswap V3 unwind (no guessing fee tiers):"
echo "5) Receiver surplus accounting and recycle path:"
echo " bash scripts/verify/report-mainnet-aave-quote-push-surplus-accounting.sh"
echo " bash scripts/deployment/sweep-mainnet-aave-quote-push-receiver-surplus.sh --dry-run"
echo " bash scripts/deployment/recycle-mainnet-aave-quote-push-surplus.sh --dry-run"
echo
echo "6) Pick a valid Uniswap V3 unwind (no guessing fee tiers):"
echo " bash scripts/verify/probe-uniswap-v3-cwusdc-usdc-mainnet.sh"
echo " If no pool: UNWIND_MODE=2 — build path: bash scripts/verify/build-uniswap-v3-exact-input-path-hex.sh ... (VERIFY_POOLS=1 optional)"
echo " Calculations report (dry-run snapshots): reports/status/mainnet_cwusdc_usdc_quote_push_calculations_2026-04-12.md"

View File

@@ -185,8 +185,11 @@ _pmm_fund_grid_err() {
trap '_pmm_fund_grid_err' ERR
_chunk_wall_start="$SECONDS"
_prog_every="${PMM_SOAK_FUND_PROGRESS_EVERY:-50}"
[[ "$_prog_every" =~ ^[0-9]+$ ]] || _prog_every=50
# Avoid names starting with "_" inside (( )) under set -u (some shells/envs treat expansion oddly).
fund_progress_every=50
if [[ -n "${PMM_SOAK_FUND_PROGRESS_EVERY:-}" && "${PMM_SOAK_FUND_PROGRESS_EVERY}" =~ ^[0-9]+$ ]]; then
fund_progress_every="${PMM_SOAK_FUND_PROGRESS_EVERY}"
fi
n=0
for r in "${RECIPIENTS[@]}"; do
n=$((n + 1))
@@ -197,10 +200,12 @@ for r in "${RECIPIENTS[@]}"; do
cast send "$TOKEN_ADDR" 'transfer(address,uint256)(bool)' "$r" "$AMOUNT" \
--rpc-url "$RPC" --private-key "$PK" --legacy --gas-price "$GAS_WEI"
fi
if [[ "$_prog_every" -gt 0 ]] && (( n % _prog_every == 0 || n == total )); then
_el=$((SECONDS - _chunk_wall_start))
python3 -c "n=$n;total=$total;el=$_el;avg=el/n if n else 0.0;rem=total-n;eta=int(rem*avg) if rem>0 else 0;print(f'[fund-grid] progress {n}/{total} chunk_elapsed_s={el} avg_s_per_tx={avg:.2f} est_remaining_this_chunk_s={eta}')" 2>/dev/null || true
elif [[ "$_prog_every" -eq 0 ]] && [[ "$n" -eq "$total" ]]; then
if [[ "${fund_progress_every}" -gt 0 ]]; then
if (( n % fund_progress_every == 0 )) || (( n == total )); then
_el=$((SECONDS - _chunk_wall_start))
python3 -c "n=$n;total=$total;el=$_el;avg=el/n if n else 0.0;rem=total-n;eta=int(rem*avg) if rem>0 else 0;print(f'[fund-grid] progress {n}/{total} chunk_elapsed_s={el} avg_s_per_tx={avg:.2f} est_remaining_this_chunk_s={eta}')" 2>/dev/null || true
fi
elif [[ "$n" -eq "$total" ]]; then
echo "[fund-grid] progress ${n}/${total} chunk_elapsed_s=$((SECONDS - _chunk_wall_start)) (final)"
fi
done

View File

@@ -0,0 +1,155 @@
#!/usr/bin/env bash
set -euo pipefail
# Sweep retained quote surplus from the receiver to the deployer and, when the
# deployer gas reserve is healthy, immediately recycle that quote into the
# wallet-funded cWUSDC/USDC peg tranche helper.
#
# Default: simulation only. Use --apply to broadcast / execute.
#
# Env:
# ETHEREUM_MAINNET_RPC required
# PRIVATE_KEY required
# AAVE_QUOTE_PUSH_RECEIVER_MAINNET required
# QUOTE_PUSH_SURPLUS_TOKEN_MAINNET optional; defaults to mainnet USDC
# QUOTE_PUSH_RECEIVER_RESERVE_RAW optional; amount to keep on receiver after sweep
# QUOTE_PUSH_DEPLOYER_GAS_FLOOR_ETH optional; default 0.003
# QUOTE_PUSH_OPERATION_BUFFER_ETH optional; default 0.0005
# QUOTE_PUSH_NATIVE_TOKEN_PRICE optional; default 3200
#
# Usage:
# source scripts/lib/load-project-env.sh
# bash scripts/deployment/recycle-mainnet-aave-quote-push-surplus.sh --dry-run
# bash scripts/deployment/recycle-mainnet-aave-quote-push-surplus.sh --apply
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROXMOX_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
SMOM="${PROXMOX_ROOT}/smom-dbis-138"
DEFAULT_USDC_MAINNET="0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
# shellcheck disable=SC1091
source "${PROXMOX_ROOT}/scripts/lib/load-project-env.sh" 2>/dev/null || true
# shellcheck disable=SC1091
source "${SMOM}/scripts/load-env.sh" >/dev/null 2>&1 || true
require_cmd() {
command -v "$1" >/dev/null 2>&1 || {
echo "[fail] missing required command: $1" >&2
exit 1
}
}
require_env() {
local name="$1"
if [[ -z "${!name:-}" ]]; then
echo "[fail] missing required env: $name" >&2
exit 1
fi
}
pick_latest_receiver() {
local latest_json="${SMOM}/broadcast/DeployAaveQuotePushFlashReceiver.s.sol/1/run-latest.json"
if [[ ! -f "$latest_json" ]] || ! command -v jq >/dev/null 2>&1; then
return 1
fi
jq -r '.transactions[]? | select(.transactionType == "CREATE" and .contractName == "AaveQuotePushFlashReceiver") | .contractAddress' \
"$latest_json" | tail -n1
}
require_cmd cast
require_cmd python3
MODE="dry-run"
for arg in "$@"; do
case "$arg" in
--dry-run) MODE="dry-run" ;;
--apply) MODE="apply" ;;
*)
echo "[fail] unknown arg: $arg (use --dry-run or --apply)" >&2
exit 2
;;
esac
done
require_env ETHEREUM_MAINNET_RPC
require_env PRIVATE_KEY
if [[ -z "${AAVE_QUOTE_PUSH_RECEIVER_MAINNET:-}" ]]; then
inferred_receiver="$(pick_latest_receiver || true)"
if [[ -n "$inferred_receiver" && "$inferred_receiver" != "null" ]]; then
export AAVE_QUOTE_PUSH_RECEIVER_MAINNET="$inferred_receiver"
fi
fi
require_env AAVE_QUOTE_PUSH_RECEIVER_MAINNET
DEPLOYER="$(cast wallet address --private-key "$PRIVATE_KEY")"
TOKEN="${QUOTE_PUSH_SURPLUS_TOKEN_MAINNET:-$DEFAULT_USDC_MAINNET}"
RECEIVER_RESERVE_RAW="${QUOTE_PUSH_RECEIVER_RESERVE_RAW:-0}"
GAS_FLOOR_ETH="${QUOTE_PUSH_DEPLOYER_GAS_FLOOR_ETH:-0.003}"
OP_BUFFER_ETH="${QUOTE_PUSH_OPERATION_BUFFER_ETH:-0.0005}"
NATIVE_TOKEN_PRICE="${QUOTE_PUSH_NATIVE_TOKEN_PRICE:-3200}"
deployer_eth="$(cast balance "$DEPLOYER" --ether --rpc-url "$ETHEREUM_MAINNET_RPC")"
receiver_quote_raw="$(cast call "$TOKEN" 'balanceOf(address)(uint256)' "$AAVE_QUOTE_PUSH_RECEIVER_MAINNET" --rpc-url "$ETHEREUM_MAINNET_RPC" | awk '{print $1}')"
read -r sweepable_raw gas_shortfall_eth <<EOF
$(python3 - "$deployer_eth" "$receiver_quote_raw" "$RECEIVER_RESERVE_RAW" "$GAS_FLOOR_ETH" "$OP_BUFFER_ETH" <<'PY'
import sys
deployer_eth = float(sys.argv[1])
receiver_quote_raw = int(sys.argv[2])
receiver_reserve_raw = int(sys.argv[3])
gas_floor_eth = float(sys.argv[4])
op_buffer_eth = float(sys.argv[5])
sweepable_raw = max(0, receiver_quote_raw - receiver_reserve_raw)
gas_shortfall_eth = max(0.0, gas_floor_eth + op_buffer_eth - deployer_eth)
print(sweepable_raw, gas_shortfall_eth)
PY
)
EOF
gas_floor_breached="$(
python3 - "$gas_shortfall_eth" <<'PY'
import sys
print("yes" if float(sys.argv[1]) > 0 else "no")
PY
)"
echo "=== recycle-mainnet-aave-quote-push-surplus ($MODE) ==="
echo "deployer=$DEPLOYER"
echo "receiver=$AAVE_QUOTE_PUSH_RECEIVER_MAINNET"
echo "token=$TOKEN"
echo "receiver_quote_raw=$receiver_quote_raw"
echo "receiver_reserve_raw=$RECEIVER_RESERVE_RAW"
echo "sweepable_raw=$sweepable_raw"
echo "deployer_eth=$deployer_eth"
echo "gas_floor_eth=$GAS_FLOOR_ETH"
echo "operation_buffer_eth=$OP_BUFFER_ETH"
echo "native_token_price=$NATIVE_TOKEN_PRICE"
bash "${PROXMOX_ROOT}/scripts/verify/report-mainnet-aave-quote-push-surplus-accounting.sh"
if (( sweepable_raw == 0 )); then
echo "[stop] no sweepable receiver surplus is available" >&2
exit 3
fi
if [[ "$MODE" == "dry-run" ]]; then
bash "${PROXMOX_ROOT}/scripts/deployment/sweep-mainnet-aave-quote-push-receiver-surplus.sh" --dry-run
if [[ "$gas_floor_breached" == "yes" ]]; then
echo "[stop] deployer gas reserve is below recycle floor; sweep can proceed, but pool recycle is intentionally skipped"
exit 0
fi
bash "${PROXMOX_ROOT}/scripts/deployment/apply-mainnet-cwusdc-usdc-peg-tranche-from-wallet.sh" --dry-run
exit 0
fi
bash "${PROXMOX_ROOT}/scripts/deployment/sweep-mainnet-aave-quote-push-receiver-surplus.sh" --apply
if [[ "$gas_floor_breached" == "yes" ]]; then
echo "[stop] swept surplus to deployer, but deployer ETH is still below recycle floor; skipping pool-growth tranche"
exit 0
fi
bash "${PROXMOX_ROOT}/scripts/deployment/apply-mainnet-cwusdc-usdc-peg-tranche-from-wallet.sh" --apply

View File

@@ -285,3 +285,4 @@ echo "flash_quote_amount_raw=$FLASH_QUOTE_AMOUNT_RAW unwind_mode=$UM"
)
echo "Done. Re-check: bash scripts/verify/check-mainnet-cwusdc-usdc-reserve-peg.sh"
echo "Receiver surplus accounting: bash scripts/verify/report-mainnet-aave-quote-push-surplus-accounting.sh"

View File

@@ -0,0 +1,356 @@
#!/usr/bin/env bash
set -euo pipefail
# Single entrypoint for the quote-push maintenance loop:
# 1. plan current accounting / gas policy
# 2. execute one flash quote-push
# 3. recycle retained quote via treasury manager or direct sweep fallback
#
# Default: simulation only. Use --apply to broadcast / execute.
#
# Env:
# PRIVATE_KEY, ETHEREUM_MAINNET_RPC required
# DODO_PMM_INTEGRATION_MAINNET required unless QUOTE_PUSH_KEEPER_SKIP_FLASH=1
# QUOTE_PUSH_TREASURY_MANAGER_MAINNET optional; when set, manager path is preferred
# QUOTE_PUSH_SURPLUS_TOKEN_MAINNET optional; defaults to mainnet USDC
# QUOTE_PUSH_RECEIVER_RESERVE_RAW optional; defaults to 0
# QUOTE_PUSH_DEPLOYER_GAS_FLOOR_ETH optional; defaults to 0.003
# QUOTE_PUSH_OPERATION_BUFFER_ETH optional; defaults to 0.0005
# QUOTE_PUSH_NATIVE_TOKEN_PRICE optional; defaults to 3200
# QUOTE_PUSH_KEEPER_SKIP_FLASH optional; default 0
# QUOTE_PUSH_KEEPER_SKIP_RECYCLE optional; default 0
#
# Usage:
# bash scripts/deployment/run-mainnet-aave-quote-push-keeper.sh --dry-run
# bash scripts/deployment/run-mainnet-aave-quote-push-keeper.sh --apply
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROXMOX_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
SMOM="${PROXMOX_ROOT}/smom-dbis-138"
DEFAULT_USDC_MAINNET="0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
_qp_private_key="${PRIVATE_KEY-}"
_qp_rpc="${ETHEREUM_MAINNET_RPC-}"
_qp_manager="${QUOTE_PUSH_TREASURY_MANAGER_MAINNET-}"
_qp_token="${QUOTE_PUSH_SURPLUS_TOKEN_MAINNET-}"
_qp_receiver_reserve="${QUOTE_PUSH_RECEIVER_RESERVE_RAW-}"
_qp_gas_floor="${QUOTE_PUSH_DEPLOYER_GAS_FLOOR_ETH-}"
_qp_gas_buffer="${QUOTE_PUSH_OPERATION_BUFFER_ETH-}"
_qp_native_price="${QUOTE_PUSH_NATIVE_TOKEN_PRICE-}"
_qp_skip_flash="${QUOTE_PUSH_KEEPER_SKIP_FLASH-}"
_qp_skip_recycle="${QUOTE_PUSH_KEEPER_SKIP_RECYCLE-}"
# shellcheck disable=SC1091
source "${PROXMOX_ROOT}/scripts/lib/load-project-env.sh" 2>/dev/null || true
# shellcheck disable=SC1091
source "${SMOM}/scripts/load-env.sh" >/dev/null 2>&1 || true
[[ -n "$_qp_private_key" ]] && export PRIVATE_KEY="$_qp_private_key"
[[ -n "$_qp_rpc" ]] && export ETHEREUM_MAINNET_RPC="$_qp_rpc"
[[ -n "$_qp_manager" ]] && export QUOTE_PUSH_TREASURY_MANAGER_MAINNET="$_qp_manager"
[[ -n "$_qp_token" ]] && export QUOTE_PUSH_SURPLUS_TOKEN_MAINNET="$_qp_token"
[[ -n "$_qp_receiver_reserve" ]] && export QUOTE_PUSH_RECEIVER_RESERVE_RAW="$_qp_receiver_reserve"
[[ -n "$_qp_gas_floor" ]] && export QUOTE_PUSH_DEPLOYER_GAS_FLOOR_ETH="$_qp_gas_floor"
[[ -n "$_qp_gas_buffer" ]] && export QUOTE_PUSH_OPERATION_BUFFER_ETH="$_qp_gas_buffer"
[[ -n "$_qp_native_price" ]] && export QUOTE_PUSH_NATIVE_TOKEN_PRICE="$_qp_native_price"
[[ -n "$_qp_skip_flash" ]] && export QUOTE_PUSH_KEEPER_SKIP_FLASH="$_qp_skip_flash"
[[ -n "$_qp_skip_recycle" ]] && export QUOTE_PUSH_KEEPER_SKIP_RECYCLE="$_qp_skip_recycle"
unset _qp_private_key _qp_rpc _qp_manager _qp_token _qp_receiver_reserve _qp_gas_floor
unset _qp_gas_buffer _qp_native_price _qp_skip_flash _qp_skip_recycle
require_cmd() {
command -v "$1" >/dev/null 2>&1 || {
echo "[fail] missing required command: $1" >&2
exit 1
}
}
pick_latest_manager() {
local latest_json="${SMOM}/broadcast/DeployQuotePushTreasuryManager.s.sol/1/run-latest.json"
if [[ ! -f "$latest_json" ]] || ! command -v jq >/dev/null 2>&1; then
return 1
fi
jq -r '.transactions[]? | select(.transactionType == "CREATE" and .contractName == "QuotePushTreasuryManager") | .contractAddress' \
"$latest_json" | tail -n1
}
pick_latest_receiver() {
local latest_json="${SMOM}/broadcast/DeployAaveQuotePushFlashReceiver.s.sol/1/run-latest.json"
if [[ ! -f "$latest_json" ]] || ! command -v jq >/dev/null 2>&1; then
return 1
fi
jq -r '.transactions[]? | select(.transactionType == "CREATE" and .contractName == "AaveQuotePushFlashReceiver") | .contractAddress' \
"$latest_json" | tail -n1
}
to_human() {
python3 - "$1" <<'PY'
import sys
print(f"{int(sys.argv[1]) / 1_000_000:.6f}")
PY
}
compute_keeper_plan() {
local manager_addr="${1:-}"
local deployer_eth="$2"
local token_addr="$3"
local receiver_addr="$4"
local receiver_reserve_raw="$5"
local gas_floor_eth="$6"
local gas_buffer_eth="$7"
local native_price="$8"
local receiver_quote_raw=0
local manager_quote_raw=0
local manager_available_raw=0
local receiver_sweepable_raw=0
local total_controlled_raw=0
local gas_distribution_raw=0
local recycle_distribution_raw=0
local gas_shortfall_eth=0
local gas_shortfall_quote_raw=0
local gas_recipient=""
local recycle_recipient=""
if [[ -n "$manager_addr" ]]; then
manager_quote_raw="$(cast call "$manager_addr" 'quoteBalance()(uint256)' --rpc-url "$ETHEREUM_MAINNET_RPC" | awk '{print $1}')"
manager_available_raw="$(cast call "$manager_addr" 'availableQuote()(uint256)' --rpc-url "$ETHEREUM_MAINNET_RPC" | awk '{print $1}')"
receiver_sweepable_raw="$(cast call "$manager_addr" 'receiverSweepableQuote()(uint256)' --rpc-url "$ETHEREUM_MAINNET_RPC" | awk '{print $1}')"
gas_recipient="$(cast call "$manager_addr" 'gasRecipient()(address)' --rpc-url "$ETHEREUM_MAINNET_RPC" | awk '{print $1}')"
recycle_recipient="$(cast call "$manager_addr" 'recycleRecipient()(address)' --rpc-url "$ETHEREUM_MAINNET_RPC" | awk '{print $1}')"
else
receiver_quote_raw="$(cast call "$token_addr" 'balanceOf(address)(uint256)' "$receiver_addr" --rpc-url "$ETHEREUM_MAINNET_RPC" | awk '{print $1}')"
receiver_sweepable_raw="$(
python3 - "$receiver_quote_raw" "$receiver_reserve_raw" <<'PY'
import sys
receiver_quote_raw = int(sys.argv[1])
receiver_reserve_raw = int(sys.argv[2])
print(max(0, receiver_quote_raw - receiver_reserve_raw))
PY
)"
fi
eval "$(
python3 - "$deployer_eth" "$gas_floor_eth" "$gas_buffer_eth" "$native_price" \
"${manager_available_raw:-0}" "${receiver_sweepable_raw:-0}" <<'PY'
import math
import sys
deployer_eth = float(sys.argv[1])
gas_floor_eth = float(sys.argv[2])
gas_buffer_eth = float(sys.argv[3])
native_price = float(sys.argv[4])
manager_available_raw = int(sys.argv[5])
receiver_sweepable_raw = int(sys.argv[6])
gas_shortfall_eth = max(0.0, gas_floor_eth + gas_buffer_eth - deployer_eth)
gas_shortfall_quote_raw = math.ceil(gas_shortfall_eth * native_price * 1_000_000)
total_controlled_raw = manager_available_raw + receiver_sweepable_raw
gas_distribution_raw = min(total_controlled_raw, gas_shortfall_quote_raw)
recycle_distribution_raw = max(0, total_controlled_raw - gas_distribution_raw)
print(f"GAS_SHORTFALL_ETH={gas_shortfall_eth}")
print(f"GAS_SHORTFALL_QUOTE_RAW={gas_shortfall_quote_raw}")
print(f"TOTAL_CONTROLLED_RAW={total_controlled_raw}")
print(f"GAS_DISTRIBUTION_RAW={gas_distribution_raw}")
print(f"RECYCLE_DISTRIBUTION_RAW={recycle_distribution_raw}")
PY
)"
KEEPER_MANAGER_QUOTE_RAW="${manager_quote_raw:-0}"
KEEPER_MANAGER_AVAILABLE_RAW="${manager_available_raw:-0}"
KEEPER_RECEIVER_QUOTE_RAW="${receiver_quote_raw:-0}"
KEEPER_RECEIVER_SWEEPABLE_RAW="${receiver_sweepable_raw:-0}"
KEEPER_TOTAL_CONTROLLED_RAW="${TOTAL_CONTROLLED_RAW:-0}"
KEEPER_GAS_SHORTFALL_ETH="${GAS_SHORTFALL_ETH:-0}"
KEEPER_GAS_SHORTFALL_QUOTE_RAW="${GAS_SHORTFALL_QUOTE_RAW:-0}"
KEEPER_GAS_DISTRIBUTION_RAW="${GAS_DISTRIBUTION_RAW:-0}"
KEEPER_RECYCLE_DISTRIBUTION_RAW="${RECYCLE_DISTRIBUTION_RAW:-0}"
KEEPER_GAS_RECIPIENT="${gas_recipient:-}"
KEEPER_RECYCLE_RECIPIENT="${recycle_recipient:-}"
}
require_cmd cast
require_cmd python3
require_cmd forge
MODE="dry-run"
for arg in "$@"; do
case "$arg" in
--dry-run) MODE="dry-run" ;;
--apply) MODE="apply" ;;
*)
echo "[fail] unknown arg: $arg (use --dry-run or --apply)" >&2
exit 2
;;
esac
done
if [[ -z "${PRIVATE_KEY:-}" || -z "${ETHEREUM_MAINNET_RPC:-}" ]]; then
echo "[fail] PRIVATE_KEY and ETHEREUM_MAINNET_RPC are required" >&2
exit 1
fi
if [[ -z "${QUOTE_PUSH_TREASURY_MANAGER_MAINNET:-}" ]]; then
inferred_manager="$(pick_latest_manager || true)"
if [[ -n "$inferred_manager" && "$inferred_manager" != "null" ]]; then
export QUOTE_PUSH_TREASURY_MANAGER_MAINNET="$inferred_manager"
fi
fi
if [[ -z "${AAVE_QUOTE_PUSH_RECEIVER_MAINNET:-}" ]]; then
inferred_receiver="$(pick_latest_receiver || true)"
if [[ -n "$inferred_receiver" && "$inferred_receiver" != "null" ]]; then
export AAVE_QUOTE_PUSH_RECEIVER_MAINNET="$inferred_receiver"
fi
fi
SKIP_FLASH="${QUOTE_PUSH_KEEPER_SKIP_FLASH:-0}"
SKIP_RECYCLE="${QUOTE_PUSH_KEEPER_SKIP_RECYCLE:-0}"
TOKEN="${QUOTE_PUSH_SURPLUS_TOKEN_MAINNET:-$DEFAULT_USDC_MAINNET}"
RECEIVER="${AAVE_QUOTE_PUSH_RECEIVER_MAINNET:-}"
RECEIVER_RESERVE_RAW="${QUOTE_PUSH_RECEIVER_RESERVE_RAW:-0}"
GAS_FLOOR_ETH="${QUOTE_PUSH_DEPLOYER_GAS_FLOOR_ETH:-0.003}"
OP_BUFFER_ETH="${QUOTE_PUSH_OPERATION_BUFFER_ETH:-0.0005}"
NATIVE_TOKEN_PRICE="${QUOTE_PUSH_NATIVE_TOKEN_PRICE:-3200}"
DEPLOYER="$(cast wallet address --private-key "$PRIVATE_KEY")"
MANAGER="${QUOTE_PUSH_TREASURY_MANAGER_MAINNET:-}"
echo "=== run-mainnet-aave-quote-push-keeper ($MODE) ==="
echo "deployer=$DEPLOYER"
echo "manager=${MANAGER:-<direct-receiver-path>}"
echo "skip_flash=$SKIP_FLASH"
echo "skip_recycle=$SKIP_RECYCLE"
bash "${PROXMOX_ROOT}/scripts/verify/report-mainnet-aave-quote-push-surplus-accounting.sh"
deployer_eth="$(cast balance "$DEPLOYER" --ether --rpc-url "$ETHEREUM_MAINNET_RPC")"
compute_keeper_plan "$MANAGER" "$deployer_eth" "$TOKEN" "$RECEIVER" "$RECEIVER_RESERVE_RAW" "$GAS_FLOOR_ETH" "$OP_BUFFER_ETH" "$NATIVE_TOKEN_PRICE"
echo
echo "=== Keeper policy plan ==="
echo "deployer_eth=$deployer_eth"
echo "gas_shortfall_eth=$KEEPER_GAS_SHORTFALL_ETH"
echo "gas_shortfall_quote_raw=$KEEPER_GAS_SHORTFALL_QUOTE_RAW human=$(to_human "$KEEPER_GAS_SHORTFALL_QUOTE_RAW")"
if [[ -n "$MANAGER" ]]; then
echo "manager_quote_raw=$KEEPER_MANAGER_QUOTE_RAW human=$(to_human "$KEEPER_MANAGER_QUOTE_RAW")"
echo "manager_available_raw=$KEEPER_MANAGER_AVAILABLE_RAW human=$(to_human "$KEEPER_MANAGER_AVAILABLE_RAW")"
echo "receiver_sweepable_raw=$KEEPER_RECEIVER_SWEEPABLE_RAW human=$(to_human "$KEEPER_RECEIVER_SWEEPABLE_RAW")"
echo "gas_recipient=${KEEPER_GAS_RECIPIENT:-<unset>}"
echo "recycle_recipient=${KEEPER_RECYCLE_RECIPIENT:-<unset>}"
else
echo "receiver_quote_raw=$KEEPER_RECEIVER_QUOTE_RAW human=$(to_human "$KEEPER_RECEIVER_QUOTE_RAW")"
echo "receiver_sweepable_raw=$KEEPER_RECEIVER_SWEEPABLE_RAW human=$(to_human "$KEEPER_RECEIVER_SWEEPABLE_RAW")"
fi
echo "total_controlled_raw=$KEEPER_TOTAL_CONTROLLED_RAW human=$(to_human "$KEEPER_TOTAL_CONTROLLED_RAW")"
echo "planned_gas_distribution_raw=$KEEPER_GAS_DISTRIBUTION_RAW human=$(to_human "$KEEPER_GAS_DISTRIBUTION_RAW")"
echo "planned_recycle_distribution_raw=$KEEPER_RECYCLE_DISTRIBUTION_RAW human=$(to_human "$KEEPER_RECYCLE_DISTRIBUTION_RAW")"
if [[ "$SKIP_RECYCLE" != "1" ]]; then
if [[ -n "$MANAGER" ]]; then
manager_receiver_owned="$(cast call "$MANAGER" 'isReceiverOwnedByManager()(bool)' --rpc-url "$ETHEREUM_MAINNET_RPC" | awk '{print $1}')"
if [[ "$manager_receiver_owned" != "true" ]]; then
cat >&2 <<EOF
[fail] treasury manager is not the receiver owner, so it cannot harvest retained quote yet
[hint] Deploy or transfer ownership with:
bash scripts/deployment/deploy-mainnet-aave-quote-push-receiver.sh --apply
AAVE_QUOTE_PUSH_RECEIVER_MAINNET=<new_receiver> QUOTE_PUSH_TREASURY_TAKE_RECEIVER_OWNERSHIP=1 bash scripts/deployment/deploy-mainnet-quote-push-treasury-manager.sh --apply
EOF
exit 1
fi
else
receiver_owner="$(cast call "$RECEIVER" 'owner()(address)' --rpc-url "$ETHEREUM_MAINNET_RPC" 2>/dev/null | awk '{print $1}' || true)"
if [[ -z "$receiver_owner" ]]; then
cat >&2 <<EOF
[fail] receiver does not expose owner()/sweep support: ${RECEIVER:-<unset>}
[hint] Redeploy the updated receiver, then hand it to the treasury manager:
bash scripts/deployment/deploy-mainnet-aave-quote-push-receiver.sh --apply
AAVE_QUOTE_PUSH_RECEIVER_MAINNET=<new_receiver> QUOTE_PUSH_TREASURY_TAKE_RECEIVER_OWNERSHIP=1 bash scripts/deployment/deploy-mainnet-quote-push-treasury-manager.sh --apply
EOF
exit 1
fi
fi
fi
if [[ "$MODE" == "dry-run" && -n "$MANAGER" ]]; then
export QUOTE_PUSH_TREASURY_HARVEST=1
export QUOTE_PUSH_TREASURY_GAS_HOLDBACK_TARGET_RAW="$KEEPER_GAS_SHORTFALL_QUOTE_RAW"
bash "${PROXMOX_ROOT}/scripts/deployment/run-mainnet-aave-quote-push-managed-cycle.sh" --dry-run
if [[ "${KEEPER_RECYCLE_RECIPIENT,,}" == "${DEPLOYER,,}" ]]; then
echo "[plan] A live managed cycle would route recycle quote back to the deployer, after which the wallet LP helper can be attempted."
fi
exit 0
fi
if [[ "$SKIP_FLASH" != "1" ]]; then
bash "${PROXMOX_ROOT}/scripts/deployment/run-mainnet-aave-cwusdc-quote-push-once.sh" "--${MODE}"
fi
echo
echo "=== Post-execution accounting ==="
bash "${PROXMOX_ROOT}/scripts/verify/report-mainnet-aave-quote-push-surplus-accounting.sh"
if [[ "$SKIP_RECYCLE" == "1" ]]; then
echo "[stop] recycle phase skipped by QUOTE_PUSH_KEEPER_SKIP_RECYCLE=1"
exit 0
fi
deployer_eth="$(cast balance "$DEPLOYER" --ether --rpc-url "$ETHEREUM_MAINNET_RPC")"
compute_keeper_plan "$MANAGER" "$deployer_eth" "$TOKEN" "$RECEIVER" "$RECEIVER_RESERVE_RAW" "$GAS_FLOOR_ETH" "$OP_BUFFER_ETH" "$NATIVE_TOKEN_PRICE"
if (( KEEPER_TOTAL_CONTROLLED_RAW == 0 )); then
echo "[stop] no controllable quote is available for recycle"
exit 0
fi
if [[ -n "$MANAGER" ]]; then
export QUOTE_PUSH_TREASURY_HARVEST="$(
python3 - "$KEEPER_RECEIVER_SWEEPABLE_RAW" <<'PY'
import sys
print("1" if int(sys.argv[1]) > 0 else "0")
PY
)"
export QUOTE_PUSH_TREASURY_GAS_DISTRIBUTION_RAW="$KEEPER_GAS_DISTRIBUTION_RAW"
export QUOTE_PUSH_TREASURY_RECYCLE_DISTRIBUTION_RAW="$KEEPER_RECYCLE_DISTRIBUTION_RAW"
bash "${PROXMOX_ROOT}/scripts/deployment/manage-mainnet-quote-push-treasury.sh" "--${MODE}"
if [[ "$MODE" == "dry-run" ]]; then
if [[ "${KEEPER_RECYCLE_RECIPIENT,,}" == "${DEPLOYER,,}" && "$KEEPER_RECYCLE_DISTRIBUTION_RAW" != "0" ]]; then
echo "[plan] After a live manager distribution to the deployer, the wallet tranche helper will be attempted."
fi
exit 0
fi
if python3 - "$KEEPER_GAS_SHORTFALL_ETH" <<'PY'
import sys
sys.exit(0 if float(sys.argv[1]) > 0 else 1)
PY
then
echo "[stop] quote was distributed, but deployer ETH is still below the recycle floor; skipping wallet LP tranche"
exit 0
fi
if (( KEEPER_RECYCLE_DISTRIBUTION_RAW == 0 )); then
echo "[stop] no recycle allocation remains after gas holdback"
exit 0
fi
if [[ -z "${KEEPER_RECYCLE_RECIPIENT:-}" || "${KEEPER_RECYCLE_RECIPIENT,,}" != "${DEPLOYER,,}" ]]; then
echo "[stop] recycle recipient is not the deployer wallet, so the wallet LP helper is intentionally skipped"
exit 0
fi
if ! bash "${PROXMOX_ROOT}/scripts/deployment/apply-mainnet-cwusdc-usdc-peg-tranche-from-wallet.sh" --apply; then
status=$?
if [[ "$status" == "3" ]]; then
echo "[stop] recycle distribution completed, but no wallet-funded LP tranche is currently affordable"
exit 0
fi
exit "$status"
fi
else
bash "${PROXMOX_ROOT}/scripts/deployment/recycle-mainnet-aave-quote-push-surplus.sh" "--${MODE}"
fi

View File

@@ -0,0 +1,278 @@
#!/usr/bin/env bash
set -euo pipefail
# Run one manager-backed Mainnet quote-push cycle:
# flash quote-push -> harvest retained quote into manager -> distribute to configured recipients.
#
# Default: simulation only. Use --apply to broadcast.
#
# Required env:
# PRIVATE_KEY, ETHEREUM_MAINNET_RPC
# DODO_PMM_INTEGRATION_MAINNET
# QUOTE_PUSH_TREASURY_MANAGER_MAINNET
# AAVE_QUOTE_PUSH_RECEIVER_MAINNET optional; defaults to latest broadcast or canonical receiver
# QUOTE_PUSH_EXTERNAL_UNWINDER_MAINNET optional; can be auto-picked from latest broadcast
# FLASH_QUOTE_AMOUNT_RAW optional; defaults to 200000
#
# Optional treasury env:
# QUOTE_PUSH_TREASURY_HARVEST optional; defaults to 1
# QUOTE_PUSH_TREASURY_GAS_HOLDBACK_TARGET_RAW optional; defaults to 0
#
# Usage:
# bash scripts/deployment/run-mainnet-aave-quote-push-managed-cycle.sh --dry-run
# QUOTE_PUSH_TREASURY_GAS_HOLDBACK_TARGET_RAW=0 bash scripts/deployment/run-mainnet-aave-quote-push-managed-cycle.sh --apply
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROXMOX_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
SMOM="${PROXMOX_ROOT}/smom-dbis-138"
DEFAULT_AAVE_QUOTE_PUSH_RECEIVER_MAINNET="0x241cb416aaFC2654078b7E2376adED2bDeFbCBa2"
DEFAULT_POOL_CWUSDC_USDC_MAINNET="0x69776fc607e9edA8042e320e7e43f54d06c68f0E"
_qp_private_key="${PRIVATE_KEY-}"
_qp_rpc="${ETHEREUM_MAINNET_RPC-}"
_qp_receiver="${AAVE_QUOTE_PUSH_RECEIVER_MAINNET-}"
_qp_manager="${QUOTE_PUSH_TREASURY_MANAGER_MAINNET-}"
_qp_unwinder="${QUOTE_PUSH_EXTERNAL_UNWINDER_MAINNET-}"
_qp_amount="${FLASH_QUOTE_AMOUNT_RAW-}"
_qp_unwind_type="${QUOTE_PUSH_UNWINDER_TYPE-}"
_qp_unwind_mode="${UNWIND_MODE-}"
_qp_pool="${POOL_CWUSDC_USDC_MAINNET-}"
_qp_integration="${DODO_PMM_INTEGRATION_MAINNET-}"
_qp_pool_a="${UNWIND_TWO_HOP_POOL_A-}"
_qp_pool_b="${UNWIND_TWO_HOP_POOL_B-}"
_qp_mid_token="${UNWIND_TWO_HOP_MID_TOKEN-}"
_qp_min_mid_out="${UNWIND_MIN_MID_OUT_RAW-}"
_qp_min_out_pmm="${MIN_OUT_PMM-}"
_qp_min_out_unwind="${MIN_OUT_UNWIND-}"
_qp_fee_u24="${UNWIND_V3_FEE_U24-}"
_qp_dodo_pool="${UNWIND_DODO_POOL-}"
_qp_v3_path="${UNWIND_V3_PATH_HEX-}"
_qp_intermediate_token="${UNWIND_INTERMEDIATE_TOKEN-}"
_qp_min_intermediate_out="${UNWIND_MIN_INTERMEDIATE_OUT_RAW-}"
_qp_treasury_harvest="${QUOTE_PUSH_TREASURY_HARVEST-}"
_qp_treasury_holdback="${QUOTE_PUSH_TREASURY_GAS_HOLDBACK_TARGET_RAW-}"
# shellcheck disable=SC1091
source "${PROXMOX_ROOT}/scripts/lib/load-project-env.sh" 2>/dev/null || true
# shellcheck disable=SC1091
source "${SMOM}/scripts/load-env.sh" >/dev/null 2>&1 || true
[[ -n "$_qp_private_key" ]] && export PRIVATE_KEY="$_qp_private_key"
[[ -n "$_qp_rpc" ]] && export ETHEREUM_MAINNET_RPC="$_qp_rpc"
[[ -n "$_qp_receiver" ]] && export AAVE_QUOTE_PUSH_RECEIVER_MAINNET="$_qp_receiver"
[[ -n "$_qp_manager" ]] && export QUOTE_PUSH_TREASURY_MANAGER_MAINNET="$_qp_manager"
[[ -n "$_qp_unwinder" ]] && export QUOTE_PUSH_EXTERNAL_UNWINDER_MAINNET="$_qp_unwinder"
[[ -n "$_qp_amount" ]] && export FLASH_QUOTE_AMOUNT_RAW="$_qp_amount"
[[ -n "$_qp_unwind_type" ]] && export QUOTE_PUSH_UNWINDER_TYPE="$_qp_unwind_type"
[[ -n "$_qp_unwind_mode" ]] && export UNWIND_MODE="$_qp_unwind_mode"
[[ -n "$_qp_pool" ]] && export POOL_CWUSDC_USDC_MAINNET="$_qp_pool"
[[ -n "$_qp_integration" ]] && export DODO_PMM_INTEGRATION_MAINNET="$_qp_integration"
[[ -n "$_qp_pool_a" ]] && export UNWIND_TWO_HOP_POOL_A="$_qp_pool_a"
[[ -n "$_qp_pool_b" ]] && export UNWIND_TWO_HOP_POOL_B="$_qp_pool_b"
[[ -n "$_qp_mid_token" ]] && export UNWIND_TWO_HOP_MID_TOKEN="$_qp_mid_token"
[[ -n "$_qp_min_mid_out" ]] && export UNWIND_MIN_MID_OUT_RAW="$_qp_min_mid_out"
[[ -n "$_qp_min_out_pmm" ]] && export MIN_OUT_PMM="$_qp_min_out_pmm"
[[ -n "$_qp_min_out_unwind" ]] && export MIN_OUT_UNWIND="$_qp_min_out_unwind"
[[ -n "$_qp_fee_u24" ]] && export UNWIND_V3_FEE_U24="$_qp_fee_u24"
[[ -n "$_qp_dodo_pool" ]] && export UNWIND_DODO_POOL="$_qp_dodo_pool"
[[ -n "$_qp_v3_path" ]] && export UNWIND_V3_PATH_HEX="$_qp_v3_path"
[[ -n "$_qp_intermediate_token" ]] && export UNWIND_INTERMEDIATE_TOKEN="$_qp_intermediate_token"
[[ -n "$_qp_min_intermediate_out" ]] && export UNWIND_MIN_INTERMEDIATE_OUT_RAW="$_qp_min_intermediate_out"
[[ -n "$_qp_treasury_harvest" ]] && export QUOTE_PUSH_TREASURY_HARVEST="$_qp_treasury_harvest"
[[ -n "$_qp_treasury_holdback" ]] && export QUOTE_PUSH_TREASURY_GAS_HOLDBACK_TARGET_RAW="$_qp_treasury_holdback"
unset _qp_private_key _qp_rpc _qp_receiver _qp_manager _qp_unwinder _qp_amount _qp_unwind_type _qp_unwind_mode
unset _qp_pool _qp_integration _qp_pool_a _qp_pool_b _qp_mid_token _qp_min_mid_out _qp_min_out_pmm
unset _qp_min_out_unwind _qp_fee_u24 _qp_dodo_pool _qp_v3_path _qp_intermediate_token _qp_min_intermediate_out
unset _qp_treasury_harvest _qp_treasury_holdback
BROADCAST=()
if (($# == 0)); then
:
else
for a in "$@"; do
case "$a" in
--apply) BROADCAST=(--broadcast) ;;
--dry-run) BROADCAST=() ;;
*)
echo "[fail] unknown arg: $a" >&2
exit 2
;;
esac
done
fi
require() {
local n="$1"
if [[ -z "${!n:-}" ]]; then
echo "[fail] missing required env: $n" >&2
exit 1
fi
}
pick_latest_create_address() {
local script_name="$1"
local contract_name="$2"
local latest_json="${SMOM}/broadcast/${script_name}/1/run-latest.json"
if [[ ! -f "$latest_json" ]]; then
return 1
fi
if ! command -v jq >/dev/null 2>&1; then
return 1
fi
jq -r --arg contract "$contract_name" \
'.transactions[]? | select(.transactionType == "CREATE" and .contractName == $contract) | .contractAddress' \
"$latest_json" | tail -n1
}
pick_default_unwinder() {
local addr=""
PICK_DEFAULT_UNWINDER_ADDR=""
PICK_DEFAULT_UNWINDER_MODE=""
addr="$(pick_latest_create_address "DeployTwoHopDodoIntegrationUnwinder.s.sol" "TwoHopDodoIntegrationUnwinder" || true)"
if [[ -n "$addr" && "$addr" != "null" ]]; then
PICK_DEFAULT_UNWINDER_ADDR="$addr"
PICK_DEFAULT_UNWINDER_MODE="4"
return 0
fi
addr="$(pick_latest_create_address "DeployDODOIntegrationExternalUnwinder.s.sol" "DODOIntegrationExternalUnwinder" || true)"
if [[ -n "$addr" && "$addr" != "null" ]]; then
PICK_DEFAULT_UNWINDER_ADDR="$addr"
PICK_DEFAULT_UNWINDER_MODE="1"
return 0
fi
addr="$(pick_latest_create_address "DeployUniswapV3ExternalUnwinder.s.sol" "UniswapV3ExternalUnwinder" || true)"
if [[ -n "$addr" && "$addr" != "null" ]]; then
PICK_DEFAULT_UNWINDER_ADDR="$addr"
PICK_DEFAULT_UNWINDER_MODE="0"
return 0
fi
addr="$(pick_latest_create_address "DeployDODOToUniswapV3MultiHopExternalUnwinder.s.sol" "DODOToUniswapV3MultiHopExternalUnwinder" || true)"
if [[ -n "$addr" && "$addr" != "null" ]]; then
PICK_DEFAULT_UNWINDER_ADDR="$addr"
PICK_DEFAULT_UNWINDER_MODE="5"
return 0
fi
return 1
}
UNW="${QUOTE_PUSH_UNWINDER_TYPE:-}"
if [[ -z "${AAVE_QUOTE_PUSH_RECEIVER_MAINNET:-}" ]]; then
inferred_receiver="$(pick_latest_create_address "DeployAaveQuotePushFlashReceiver.s.sol" "AaveQuotePushFlashReceiver" || true)"
export AAVE_QUOTE_PUSH_RECEIVER_MAINNET="${inferred_receiver:-$DEFAULT_AAVE_QUOTE_PUSH_RECEIVER_MAINNET}"
fi
if [[ -z "${POOL_CWUSDC_USDC_MAINNET:-}" || "${_qp_pool:-}" == "" ]]; then
export POOL_CWUSDC_USDC_MAINNET="$DEFAULT_POOL_CWUSDC_USDC_MAINNET"
fi
if [[ -z "${FLASH_QUOTE_AMOUNT_RAW:-}" ]]; then
export FLASH_QUOTE_AMOUNT_RAW=200000
fi
if [[ -z "${MIN_OUT_PMM:-}" ]]; then
export MIN_OUT_PMM=1
fi
if [[ -z "${QUOTE_PUSH_EXTERNAL_UNWINDER_MAINNET:-}" && -n "$UNW" ]]; then
unwind_script=""
unwind_contract=""
case "$UNW" in
univ3)
unwind_script="DeployUniswapV3ExternalUnwinder.s.sol"
unwind_contract="UniswapV3ExternalUnwinder"
export UNWIND_MODE="${UNWIND_MODE:-0}"
;;
dodo)
unwind_script="DeployDODOIntegrationExternalUnwinder.s.sol"
unwind_contract="DODOIntegrationExternalUnwinder"
export UNWIND_MODE="${UNWIND_MODE:-1}"
;;
two_hop_dodo)
unwind_script="DeployTwoHopDodoIntegrationUnwinder.s.sol"
unwind_contract="TwoHopDodoIntegrationUnwinder"
export UNWIND_MODE="${UNWIND_MODE:-4}"
;;
dodo_univ3)
unwind_script="DeployDODOToUniswapV3MultiHopExternalUnwinder.s.sol"
unwind_contract="DODOToUniswapV3MultiHopExternalUnwinder"
export UNWIND_MODE="${UNWIND_MODE:-5}"
;;
*)
echo "[fail] QUOTE_PUSH_UNWINDER_TYPE must be univ3, dodo, two_hop_dodo, or dodo_univ3 when set" >&2
exit 1
;;
esac
inferred_unwinder="$(pick_latest_create_address "$unwind_script" "$unwind_contract" || true)"
if [[ -n "$inferred_unwinder" && "$inferred_unwinder" != "null" ]]; then
export QUOTE_PUSH_EXTERNAL_UNWINDER_MAINNET="$inferred_unwinder"
fi
fi
if [[ -z "${QUOTE_PUSH_EXTERNAL_UNWINDER_MAINNET:-}" ]]; then
if pick_default_unwinder; then
if [[ -n "$PICK_DEFAULT_UNWINDER_ADDR" && "$PICK_DEFAULT_UNWINDER_ADDR" != "null" ]]; then
export QUOTE_PUSH_EXTERNAL_UNWINDER_MAINNET="$PICK_DEFAULT_UNWINDER_ADDR"
export UNWIND_MODE="$PICK_DEFAULT_UNWINDER_MODE"
fi
fi
fi
if [[ "${UNWIND_MODE:-}" == "4" ]]; then
export UNWIND_TWO_HOP_POOL_A="${UNWIND_TWO_HOP_POOL_A:-0xe944b7Cb012A0820c07f54D51e92f0e1C74168DB}"
export UNWIND_TWO_HOP_POOL_B="${UNWIND_TWO_HOP_POOL_B:-0x27f3aE7EE71Be3d77bAf17d4435cF8B895DD25D2}"
export UNWIND_TWO_HOP_MID_TOKEN="${UNWIND_TWO_HOP_MID_TOKEN:-0xaF5017d0163ecb99d9B5D94e3b4D7b09Af44D8AE}"
export UNWIND_MIN_MID_OUT_RAW="${UNWIND_MIN_MID_OUT_RAW:-1}"
elif [[ "${UNWIND_MODE:-}" == "5" ]]; then
export UNWIND_DODO_POOL="${UNWIND_DODO_POOL:-0xCC0fd27A40775c9AfcD2BBd3f7c902b0192c247A}"
export UNWIND_INTERMEDIATE_TOKEN="${UNWIND_INTERMEDIATE_TOKEN:-0xdAC17F958D2ee523a2206206994597C13D831ec7}"
export UNWIND_MIN_INTERMEDIATE_OUT_RAW="${UNWIND_MIN_INTERMEDIATE_OUT_RAW:-1}"
fi
require ETHEREUM_MAINNET_RPC
require PRIVATE_KEY
require QUOTE_PUSH_TREASURY_MANAGER_MAINNET
require AAVE_QUOTE_PUSH_RECEIVER_MAINNET
require QUOTE_PUSH_EXTERNAL_UNWINDER_MAINNET
require DODO_PMM_INTEGRATION_MAINNET
require FLASH_QUOTE_AMOUNT_RAW
UM="${UNWIND_MODE:-0}"
if [[ "$UM" == "0" ]]; then
require UNWIND_V3_FEE_U24
elif [[ "$UM" == "1" ]]; then
require UNWIND_DODO_POOL
elif [[ "$UM" == "2" ]]; then
require UNWIND_V3_PATH_HEX
elif [[ "$UM" == "4" ]]; then
require UNWIND_TWO_HOP_POOL_A
require UNWIND_TWO_HOP_POOL_B
require UNWIND_TWO_HOP_MID_TOKEN
elif [[ "$UM" == "5" ]]; then
require UNWIND_DODO_POOL
require UNWIND_INTERMEDIATE_TOKEN
require UNWIND_V3_PATH_HEX
else
echo "[fail] UNWIND_MODE must be 0, 1, 2, 4, or 5" >&2
exit 1
fi
echo "receiver=$AAVE_QUOTE_PUSH_RECEIVER_MAINNET"
echo "manager=$QUOTE_PUSH_TREASURY_MANAGER_MAINNET"
echo "unwinder=$QUOTE_PUSH_EXTERNAL_UNWINDER_MAINNET"
echo "flash_quote_amount_raw=$FLASH_QUOTE_AMOUNT_RAW unwind_mode=$UM"
echo "gas_holdback_target_raw=${QUOTE_PUSH_TREASURY_GAS_HOLDBACK_TARGET_RAW:-0}"
(
cd "$SMOM"
forge script script/flash/RunManagedMainnetAaveCwusdcUsdcQuotePushCycle.s.sol:RunManagedMainnetAaveCwusdcUsdcQuotePushCycle \
--rpc-url "$ETHEREUM_MAINNET_RPC" \
"${BROADCAST[@]}" \
-vvvv
)

View File

@@ -9,6 +9,7 @@ set -euo pipefail
# FLASH_MODEL_SCAN_SIZES — comma-separated gross flash quote sizes in raw units (default 5e6,1e7,2e7)
# PMM_FLASH_EXIT_PRICE_CMD — passed to node --external-exit-price-cmd (default: printf 1.02)
# GAS_GWEI, NATIVE_PRICE — optional overrides for the economics model
# If GAS_GWEI is unset, the script reads the live mainnet gas price and converts it to gwei.
# FLASH_MODEL_GAS_TX_COUNT, FLASH_MODEL_GAS_PER_TX — gas row (defaults 3 / 250000)
# FLASH_MODEL_MAX_POST_TRADE_DEV_BPS — deviation guard (default 500; raise only for stress math, not production)
#
@@ -40,7 +41,7 @@ INTEGRATION="${DODO_PMM_INTEGRATION_MAINNET:-}"
POOL="${POOL_CWUSDC_USDC_MAINNET:-0x69776fc607e9edA8042e320e7e43f54d06c68f0E}"
SCAN="${FLASH_MODEL_SCAN_SIZES:-5000000,10000000,25000000}"
EXIT_CMD="${PMM_FLASH_EXIT_PRICE_CMD:-printf 1.02}"
GAS_GWEI="${GAS_GWEI:-40}"
GAS_GWEI="${GAS_GWEI:-}"
NATIVE_PRICE="${NATIVE_PRICE:-3200}"
GAS_TXN="${FLASH_MODEL_GAS_TX_COUNT:-3}"
GAS_PER="${FLASH_MODEL_GAS_PER_TX:-250000}"
@@ -62,6 +63,15 @@ out="$(cast call "$POOL" 'getVaultReserve()(uint256,uint256)' --rpc-url "$RPC_UR
B="$(printf '%s\n' "$out" | sed -n '1p' | awk '{print $1}')"
Q="$(printf '%s\n' "$out" | sed -n '2p' | awk '{print $1}')"
if [[ -z "$GAS_GWEI" ]]; then
gas_price_wei="$(cast gas-price --rpc-url "$RPC_URL" | awk '{print $1}')"
GAS_GWEI="$(python3 - "$gas_price_wei" <<'PY'
import sys
print(f"{int(sys.argv[1]) / 1_000_000_000:.9f}")
PY
)"
fi
PMM_JS="${PROXMOX_ROOT}/scripts/analytics/pmm-flash-push-break-even.mjs"
echo "=== Flash quote-push model sweep (dry-run only) ==="
@@ -92,3 +102,4 @@ for x in "${sizes[@]}"; do
done
echo "Live execution: deploy-mainnet-aave-quote-push-stack.sh then run-mainnet-aave-cwusdc-quote-push-once.sh (see plan-mainnet-cwusdc-flash-quote-push-rebalance.sh)"
echo "Receiver surplus accounting: bash scripts/verify/report-mainnet-aave-quote-push-surplus-accounting.sh"

View File

@@ -0,0 +1,166 @@
#!/usr/bin/env bash
set -euo pipefail
# Sweep retained surplus from a deployed Mainnet Aave quote-push receiver.
# Default: simulation only. Use --apply to broadcast.
#
# Env:
# PRIVATE_KEY, ETHEREUM_MAINNET_RPC, AAVE_QUOTE_PUSH_RECEIVER_MAINNET
# QUOTE_PUSH_SURPLUS_TOKEN_MAINNET optional; defaults to mainnet USDC
# QUOTE_PUSH_SURPLUS_RECIPIENT optional; defaults to deployer derived from PRIVATE_KEY
# QUOTE_PUSH_SURPLUS_RESERVE_RAW optional; keep this much on the receiver when sweeping surplus mode
# QUOTE_PUSH_SURPLUS_EXACT_AMOUNT_RAW optional; if > 0, sweep this exact amount instead of balance - reserve
#
# Usage:
# source scripts/lib/load-project-env.sh
# bash scripts/deployment/sweep-mainnet-aave-quote-push-receiver-surplus.sh --dry-run
# QUOTE_PUSH_SURPLUS_RESERVE_RAW=50000 bash scripts/deployment/sweep-mainnet-aave-quote-push-receiver-surplus.sh --apply
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROXMOX_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
SMOM="${PROXMOX_ROOT}/smom-dbis-138"
DEFAULT_USDC_MAINNET="0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
_qp_private_key="${PRIVATE_KEY-}"
_qp_rpc="${ETHEREUM_MAINNET_RPC-}"
_qp_receiver="${AAVE_QUOTE_PUSH_RECEIVER_MAINNET-}"
_qp_token="${QUOTE_PUSH_SURPLUS_TOKEN_MAINNET-}"
_qp_recipient="${QUOTE_PUSH_SURPLUS_RECIPIENT-}"
_qp_reserve="${QUOTE_PUSH_SURPLUS_RESERVE_RAW-}"
_qp_exact="${QUOTE_PUSH_SURPLUS_EXACT_AMOUNT_RAW-}"
# shellcheck disable=SC1091
source "${PROXMOX_ROOT}/scripts/lib/load-project-env.sh" 2>/dev/null || true
# shellcheck disable=SC1091
source "${SMOM}/scripts/load-env.sh" >/dev/null 2>&1 || true
[[ -n "$_qp_private_key" ]] && export PRIVATE_KEY="$_qp_private_key"
[[ -n "$_qp_rpc" ]] && export ETHEREUM_MAINNET_RPC="$_qp_rpc"
[[ -n "$_qp_receiver" ]] && export AAVE_QUOTE_PUSH_RECEIVER_MAINNET="$_qp_receiver"
[[ -n "$_qp_token" ]] && export QUOTE_PUSH_SURPLUS_TOKEN_MAINNET="$_qp_token"
[[ -n "$_qp_recipient" ]] && export QUOTE_PUSH_SURPLUS_RECIPIENT="$_qp_recipient"
[[ -n "$_qp_reserve" ]] && export QUOTE_PUSH_SURPLUS_RESERVE_RAW="$_qp_reserve"
[[ -n "$_qp_exact" ]] && export QUOTE_PUSH_SURPLUS_EXACT_AMOUNT_RAW="$_qp_exact"
unset _qp_private_key _qp_rpc _qp_receiver _qp_token _qp_recipient _qp_reserve _qp_exact
require_cmd() {
command -v "$1" >/dev/null 2>&1 || {
echo "[fail] missing required command: $1" >&2
exit 1
}
}
require_cmd cast
require_cmd forge
require_env() {
local name="$1"
if [[ -z "${!name:-}" ]]; then
echo "[fail] missing required env: $name" >&2
exit 1
fi
}
pick_latest_receiver() {
local latest_json="${SMOM}/broadcast/DeployAaveQuotePushFlashReceiver.s.sol/1/run-latest.json"
if [[ ! -f "$latest_json" ]] || ! command -v jq >/dev/null 2>&1; then
return 1
fi
jq -r '.transactions[]? | select(.transactionType == "CREATE" and .contractName == "AaveQuotePushFlashReceiver") | .contractAddress' \
"$latest_json" | tail -n1
}
MODE="dry-run"
BROADCAST=()
for arg in "$@"; do
case "$arg" in
--dry-run) MODE="dry-run"; BROADCAST=() ;;
--apply) MODE="apply"; BROADCAST=(--broadcast) ;;
*)
echo "[fail] unknown arg: $arg (use --dry-run or --apply)" >&2
exit 2
;;
esac
done
require_env PRIVATE_KEY
require_env ETHEREUM_MAINNET_RPC
if [[ -z "${AAVE_QUOTE_PUSH_RECEIVER_MAINNET:-}" ]]; then
inferred_receiver="$(pick_latest_receiver || true)"
if [[ -n "$inferred_receiver" && "$inferred_receiver" != "null" ]]; then
export AAVE_QUOTE_PUSH_RECEIVER_MAINNET="$inferred_receiver"
fi
fi
require_env AAVE_QUOTE_PUSH_RECEIVER_MAINNET
TOKEN="${QUOTE_PUSH_SURPLUS_TOKEN_MAINNET:-$DEFAULT_USDC_MAINNET}"
DEPLOYER="$(cast wallet address --private-key "$PRIVATE_KEY")"
RECIPIENT="${QUOTE_PUSH_SURPLUS_RECIPIENT:-$DEPLOYER}"
RESERVE_RAW="${QUOTE_PUSH_SURPLUS_RESERVE_RAW:-0}"
EXACT_RAW="${QUOTE_PUSH_SURPLUS_EXACT_AMOUNT_RAW:-0}"
receiver_owner="$(cast call "$AAVE_QUOTE_PUSH_RECEIVER_MAINNET" 'owner()(address)' --rpc-url "$ETHEREUM_MAINNET_RPC" 2>/dev/null | awk '{print $1}' || true)"
if [[ -z "$receiver_owner" ]]; then
cat >&2 <<EOF
[fail] receiver does not expose owner()/sweep support: $AAVE_QUOTE_PUSH_RECEIVER_MAINNET
[hint] Redeploy the updated receiver, then point AAVE_QUOTE_PUSH_RECEIVER_MAINNET at the new address:
bash scripts/deployment/deploy-mainnet-aave-quote-push-receiver.sh --apply
EOF
exit 1
fi
if [[ "${receiver_owner,,}" != "${DEPLOYER,,}" ]]; then
echo "[fail] deployer $DEPLOYER is not the receiver owner ($receiver_owner)" >&2
exit 1
fi
receiver_balance_raw="$(
cast call "$TOKEN" 'balanceOf(address)(uint256)' "$AAVE_QUOTE_PUSH_RECEIVER_MAINNET" --rpc-url "$ETHEREUM_MAINNET_RPC" \
| awk '{print $1}'
)"
if (( EXACT_RAW > 0 )); then
if (( receiver_balance_raw < EXACT_RAW )); then
echo "[fail] receiver balance too small for exact sweep: have=$receiver_balance_raw need=$EXACT_RAW" >&2
exit 1
fi
sweep_raw="$EXACT_RAW"
else
if (( receiver_balance_raw <= RESERVE_RAW )); then
echo "[stop] nothing to sweep: receiver_balance_raw=$receiver_balance_raw reserve_raw=$RESERVE_RAW" >&2
exit 3
fi
sweep_raw=$((receiver_balance_raw - RESERVE_RAW))
fi
echo "=== sweep-mainnet-aave-quote-push-receiver-surplus ($MODE) ==="
echo "receiver=$AAVE_QUOTE_PUSH_RECEIVER_MAINNET"
echo "receiver_owner=$receiver_owner"
echo "token=$TOKEN"
echo "recipient=$RECIPIENT"
echo "receiver_balance_raw=$receiver_balance_raw"
echo "reserve_raw=$RESERVE_RAW"
echo "exact_raw=$EXACT_RAW"
echo "sweep_raw=$sweep_raw"
(
cd "$SMOM"
forge script script/flash/SweepAaveQuotePushFlashReceiverSurplus.s.sol:SweepAaveQuotePushFlashReceiverSurplus \
--rpc-url "$ETHEREUM_MAINNET_RPC" \
"${BROADCAST[@]}" \
-vvvv
)
if [[ "$MODE" == "apply" ]]; then
receiver_after="$(
cast call "$TOKEN" 'balanceOf(address)(uint256)' "$AAVE_QUOTE_PUSH_RECEIVER_MAINNET" --rpc-url "$ETHEREUM_MAINNET_RPC" \
| awk '{print $1}'
)"
recipient_after="$(
cast call "$TOKEN" 'balanceOf(address)(uint256)' "$RECIPIENT" --rpc-url "$ETHEREUM_MAINNET_RPC" \
| awk '{print $1}'
)"
echo "receiver_balance_after_raw=$receiver_after"
echo "recipient_balance_after_raw=$recipient_after"
fi