501 lines
21 KiB
Bash
501 lines
21 KiB
Bash
#!/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_ALLOW_NET_NEGATIVE optional; default 0; set to 1 to bypass modeled net gate
|
|
# 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_allow_net_negative="${QUOTE_PUSH_KEEPER_ALLOW_NET_NEGATIVE-}"
|
|
_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_allow_net_negative" ]] && export QUOTE_PUSH_KEEPER_ALLOW_NET_NEGATIVE="$_qp_allow_net_negative"
|
|
[[ -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_allow_net_negative _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:-}"
|
|
}
|
|
|
|
parse_managed_cycle_summary() {
|
|
local summary_line="$1"
|
|
local native_price="$2"
|
|
|
|
eval "$(
|
|
python3 - "$summary_line" "$native_price" <<'PY'
|
|
import math
|
|
import sys
|
|
|
|
line = sys.argv[1]
|
|
native_price = float(sys.argv[2])
|
|
parts = {}
|
|
for token in line.split():
|
|
if "=" not in token:
|
|
continue
|
|
key, value = token.split("=", 1)
|
|
parts[key] = value
|
|
|
|
harvested_raw = int(parts.get("harvested_raw", "0"))
|
|
gas_distribution_raw = int(parts.get("gas_distribution_raw", "0"))
|
|
recycle_distribution_raw = int(parts.get("recycle_distribution_raw", "0"))
|
|
estimated_eth_required = float(parts.get("estimated_eth_required", "0") or 0)
|
|
estimated_total_gas = int(parts.get("estimated_total_gas", "0") or 0)
|
|
modeled_gas_cost_quote_raw = math.ceil(estimated_eth_required * native_price * 1_000_000)
|
|
modeled_net_quote_raw = recycle_distribution_raw - modeled_gas_cost_quote_raw
|
|
|
|
print(f"KEEPER_MANAGED_HARVESTED_RAW={harvested_raw}")
|
|
print(f"KEEPER_MANAGED_GAS_DISTRIBUTION_RAW={gas_distribution_raw}")
|
|
print(f"KEEPER_MANAGED_RECYCLE_DISTRIBUTION_RAW={recycle_distribution_raw}")
|
|
print(f"KEEPER_MANAGED_ESTIMATED_ETH_REQUIRED={estimated_eth_required}")
|
|
print(f"KEEPER_MANAGED_ESTIMATED_TOTAL_GAS={estimated_total_gas}")
|
|
print(f"KEEPER_MANAGED_GAS_COST_QUOTE_RAW={modeled_gas_cost_quote_raw}")
|
|
print(f"KEEPER_MANAGED_NET_QUOTE_RAW={modeled_net_quote_raw}")
|
|
PY
|
|
)"
|
|
}
|
|
|
|
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
|
|
if [[ -n "${QUOTE_PUSH_TREASURY_MANAGER_MAINNET:-}" ]]; then
|
|
manager_receiver="$(cast call "$QUOTE_PUSH_TREASURY_MANAGER_MAINNET" 'receiver()(address)' --rpc-url "$ETHEREUM_MAINNET_RPC" 2>/dev/null | awk '{print $1}' || true)"
|
|
if [[ -n "$manager_receiver" && "$manager_receiver" != "0x0000000000000000000000000000000000000000" ]]; then
|
|
export AAVE_QUOTE_PUSH_RECEIVER_MAINNET="$manager_receiver"
|
|
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
|
|
fi
|
|
|
|
SKIP_FLASH="${QUOTE_PUSH_KEEPER_SKIP_FLASH:-0}"
|
|
SKIP_RECYCLE="${QUOTE_PUSH_KEEPER_SKIP_RECYCLE:-0}"
|
|
ALLOW_NET_NEGATIVE="${QUOTE_PUSH_KEEPER_ALLOW_NET_NEGATIVE:-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:-}"
|
|
if [[ -n "$MANAGER" ]]; then
|
|
manager_receiver="$(cast call "$MANAGER" 'receiver()(address)' --rpc-url "$ETHEREUM_MAINNET_RPC" 2>/dev/null | awk '{print $1}' || true)"
|
|
if [[ -z "$manager_receiver" ]]; then
|
|
echo "[fail] could not resolve receiver() from manager $MANAGER" >&2
|
|
exit 1
|
|
fi
|
|
if [[ -z "$RECEIVER" ]]; then
|
|
RECEIVER="$manager_receiver"
|
|
export AAVE_QUOTE_PUSH_RECEIVER_MAINNET="$RECEIVER"
|
|
elif [[ "${manager_receiver,,}" != "${RECEIVER,,}" ]]; then
|
|
cat >&2 <<EOF
|
|
[fail] receiver/manager mismatch in keeper
|
|
manager=$MANAGER
|
|
manager_receiver=$manager_receiver
|
|
receiver_env=$RECEIVER
|
|
EOF
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
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"
|
|
echo "allow_net_negative=$ALLOW_NET_NEGATIVE"
|
|
|
|
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 [[ -n "$MANAGER" && "$SKIP_FLASH" != "1" && "$SKIP_RECYCLE" != "1" ]]; then
|
|
export QUOTE_PUSH_TREASURY_HARVEST=1
|
|
export QUOTE_PUSH_TREASURY_GAS_HOLDBACK_TARGET_RAW="$KEEPER_GAS_SHORTFALL_QUOTE_RAW"
|
|
set +e
|
|
managed_cycle_output="$(
|
|
bash "${PROXMOX_ROOT}/scripts/deployment/run-mainnet-aave-quote-push-managed-cycle.sh" --dry-run 2>&1
|
|
)"
|
|
managed_cycle_status=$?
|
|
set -e
|
|
printf '%s\n' "$managed_cycle_output"
|
|
if [[ "$managed_cycle_status" -ne 0 ]]; then
|
|
exit "$managed_cycle_status"
|
|
fi
|
|
|
|
managed_summary_line="$(printf '%s\n' "$managed_cycle_output" | awk '/MANAGED_CYCLE_SUMMARY / {line=$0} END {print line}')"
|
|
if [[ -z "$managed_summary_line" ]]; then
|
|
echo "[fail] managed cycle precheck did not emit MANAGED_CYCLE_SUMMARY" >&2
|
|
exit 1
|
|
fi
|
|
|
|
parse_managed_cycle_summary "$managed_summary_line" "$NATIVE_TOKEN_PRICE"
|
|
|
|
echo
|
|
echo "=== Managed cycle economics ==="
|
|
echo "modeled_harvested_raw=$KEEPER_MANAGED_HARVESTED_RAW human=$(to_human "$KEEPER_MANAGED_HARVESTED_RAW")"
|
|
echo "modeled_gas_distribution_raw=$KEEPER_MANAGED_GAS_DISTRIBUTION_RAW human=$(to_human "$KEEPER_MANAGED_GAS_DISTRIBUTION_RAW")"
|
|
echo "modeled_recycle_distribution_raw=$KEEPER_MANAGED_RECYCLE_DISTRIBUTION_RAW human=$(to_human "$KEEPER_MANAGED_RECYCLE_DISTRIBUTION_RAW")"
|
|
echo "modeled_estimated_eth_required=$KEEPER_MANAGED_ESTIMATED_ETH_REQUIRED"
|
|
echo "modeled_estimated_total_gas=$KEEPER_MANAGED_ESTIMATED_TOTAL_GAS"
|
|
echo "modeled_gas_cost_quote_raw=$KEEPER_MANAGED_GAS_COST_QUOTE_RAW human=$(to_human "$KEEPER_MANAGED_GAS_COST_QUOTE_RAW")"
|
|
echo "modeled_net_quote_raw=$KEEPER_MANAGED_NET_QUOTE_RAW human=$(to_human "$KEEPER_MANAGED_NET_QUOTE_RAW")"
|
|
|
|
if (( KEEPER_MANAGED_NET_QUOTE_RAW <= 0 )) && [[ "$ALLOW_NET_NEGATIVE" != "1" ]]; then
|
|
echo "[stop] managed cycle is net negative after modeled gas; refusing to execute without QUOTE_PUSH_KEEPER_ALLOW_NET_NEGATIVE=1"
|
|
if [[ "$MODE" == "dry-run" ]]; then
|
|
exit 0
|
|
fi
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "$MODE" == "dry-run" ]]; then
|
|
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
|
|
|
|
bash "${PROXMOX_ROOT}/scripts/deployment/run-mainnet-aave-quote-push-managed-cycle.sh" --apply
|
|
|
|
echo
|
|
echo "=== Post-execution accounting ==="
|
|
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"
|
|
|
|
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
|
|
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
|