Files
proxmox/scripts/deployment/deploy-mainnet-quote-push-treasury-manager.sh
2026-04-13 21:38:57 -07:00

196 lines
8.0 KiB
Bash

#!/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
}
resolved_chain_id() {
if [[ -n "${ETHEREUM_MAINNET_RPC:-}" ]] && command -v cast >/dev/null 2>&1; then
cast chain-id --rpc-url "$ETHEREUM_MAINNET_RPC" 2>/dev/null | awk '{print $1}'
return 0
fi
echo "1"
}
pick_latest_create_address() {
local script_name="$1"
local contract_name="$2"
local mode="${3:-apply}"
local chain_id
chain_id="$(resolved_chain_id)"
local latest_json="${SMOM}/broadcast/${script_name}/${chain_id}/run-latest.json"
if [[ "$mode" == "dry-run" ]]; then
latest_json="${SMOM}/broadcast/${script_name}/${chain_id}/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 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
DEPLOYER="$(cast wallet address --private-key "$PRIVATE_KEY")"
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
if [[ "${QUOTE_PUSH_TREASURY_TAKE_RECEIVER_OWNERSHIP:-0}" == "1" ]]; then
current_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 "$current_receiver_owner" ]]; then
echo "[fail] receiver does not expose owner(): $AAVE_QUOTE_PUSH_RECEIVER_MAINNET" >&2
exit 1
fi
if [[ "${current_receiver_owner,,}" != "${DEPLOYER,,}" ]]; then
cat >&2 <<EOF
[fail] receiver ownership transfer would fail because deployer is not the current owner
receiver=$AAVE_QUOTE_PUSH_RECEIVER_MAINNET
current_owner=$current_receiver_owner
deployer=$DEPLOYER
[hint] Either use the current owner key or omit QUOTE_PUSH_TREASURY_TAKE_RECEIVER_OWNERSHIP=1 and perform ownership rotation separately.
EOF
exit 1
fi
fi
echo "=== deploy-mainnet-quote-push-treasury-manager ($MODE) ==="
echo "deployer=$DEPLOYER"
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" == "apply" && -n "$manager_addr" && "$manager_addr" != "null" ]]; then
manager_receiver="$(cast call "$manager_addr" 'receiver()(address)' --rpc-url "$ETHEREUM_MAINNET_RPC" | awk '{print $1}')"
if [[ "${manager_receiver,,}" != "${AAVE_QUOTE_PUSH_RECEIVER_MAINNET,,}" ]]; then
cat >&2 <<EOF
[fail] deployed manager is wired to an unexpected receiver
manager=$manager_addr
expected_receiver=$AAVE_QUOTE_PUSH_RECEIVER_MAINNET
manager_receiver=$manager_receiver
EOF
exit 1
fi
if [[ "${QUOTE_PUSH_TREASURY_TAKE_RECEIVER_OWNERSHIP:-0}" == "1" ]]; then
owned_by_manager="$(cast call "$manager_addr" 'isReceiverOwnedByManager()(bool)' --rpc-url "$ETHEREUM_MAINNET_RPC" | awk '{print $1}')"
if [[ "$owned_by_manager" != "true" ]]; then
cat >&2 <<EOF
[fail] manager deployed but receiver ownership did not finalize correctly
manager=$manager_addr
receiver=$AAVE_QUOTE_PUSH_RECEIVER_MAINNET
[hint] If ownership already moved and you need to unwind it:
QUOTE_PUSH_TREASURY_MANAGER_MAINNET=$manager_addr QUOTE_PUSH_TREASURY_TRANSFER_RECEIVER_OWNER_TO=$DEPLOYER bash scripts/deployment/manage-mainnet-quote-push-treasury.sh --apply
EOF
exit 1
fi
fi
fi
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"