259 lines
8.8 KiB
Bash
Executable File
259 lines
8.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
# ============================================
|
|
# AAXE / Furuombe Bash CLI
|
|
# --------------------------------------------
|
|
# Builds and (optionally) submits a Furuombe plan
|
|
# matching the user's block sequence.
|
|
#
|
|
# USAGE:
|
|
# ./aaxe-cli.sh build-plan > plan.json
|
|
# ./aaxe-cli.sh show-plan
|
|
# ./aaxe-cli.sh send --rpc https://mainnet.infura.io/v3/KEY --router 0xRouterAddr
|
|
#
|
|
# ENV:
|
|
# PRIVATE_KEY # hex private key (no 0x), ONLY required for `send`
|
|
#
|
|
# NOTES:
|
|
# - The router ABI here assumes: function execute(bytes plan)
|
|
# where `plan` is arbitrary bytes (we pass JSON bytes).
|
|
# If your router expects a different ABI/format, adjust SEND section.
|
|
# ============================================
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PLAN_FILE="${PLAN_FILE:-$SCRIPT_DIR/plan.json}"
|
|
|
|
# ---------- Defaults (edit to your environment) ----------
|
|
CHAIN_ID_DEFAULT="${CHAIN_ID_DEFAULT:-1}"
|
|
RPC_URL_DEFAULT="${RPC_URL_DEFAULT:-https://mainnet.infura.io/v3/YOUR_KEY}"
|
|
AAXE_ROUTER_DEFAULT="${AAXE_ROUTER_DEFAULT:-0x0000000000000000000000000000000000000000}" # <- PUT REAL ROUTER
|
|
# Common tokens (placeholders — replace with real addresses for your chain)
|
|
ADDR_USDC="${ADDR_USDC:-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48}" # Mainnet USDC
|
|
ADDR_USDT="${ADDR_USDT:-0xdAC17F958D2ee523a2206206994597C13D831ec7}" # Mainnet USDT
|
|
# Aave V3 (example mainnet Pool; verify!)
|
|
ADDR_AAVE_V3_POOL="${ADDR_AAVE_V3_POOL:-0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2}"
|
|
# Paraswap v5 Augustus (placeholder — replace!)
|
|
ADDR_PARASWAP_V5="${ADDR_PARASWAP_V5:-0xDEF1ABE32c034e558Cdd535791643C58a13aCC10}"
|
|
# aToken placeholder (aEthUSDC-like) — replace with the correct aToken for your network
|
|
ADDR_aEthUSDC="${ADDR_aEthUSDC:-0x0000000000000000000000000000000000000001}"
|
|
|
|
# ---------- Helpers ----------
|
|
die() { echo "Error: $*" >&2; exit 1; }
|
|
|
|
require_jq() {
|
|
command -v jq >/dev/null 2>&1 || die "jq is required. Install: https://stedolan.github.io/jq/"
|
|
}
|
|
|
|
require_bc() {
|
|
command -v bc >/dev/null 2>&1 || die "bc is required. Install: sudo apt-get install bc (or your package manager)"
|
|
}
|
|
|
|
require_cast() {
|
|
command -v cast >/dev/null 2>&1 || die "Foundry's 'cast' is required for sending. Install: https://book.getfoundry.sh/"
|
|
}
|
|
|
|
to_wei_like() {
|
|
# Convert decimal string to 6-decimal fixed (USDC/USDT style) integer string
|
|
# e.g., "2001.033032" -> "2001033032"
|
|
local amount="$1"
|
|
# Use bc to multiply by 1000000 and truncate decimals (scale=0 truncates)
|
|
echo "scale=0; ($amount * 1000000) / 1" | bc | tr -d '\n'
|
|
}
|
|
|
|
# ---------- Plan builder ----------
|
|
build_plan() {
|
|
require_jq
|
|
require_bc
|
|
|
|
# Amounts as user provided (USDC/USDT both 6 decimals typical)
|
|
USDC_4600=$(to_wei_like "4600")
|
|
USDT_2500=$(to_wei_like "2500")
|
|
USDT_2000_9=$(to_wei_like "2000.9")
|
|
USDC_2001_033032=$(to_wei_like "2001.033032")
|
|
USDC_1000=$(to_wei_like "1000")
|
|
USDT_2300=$(to_wei_like "2300")
|
|
USDT_2100_9=$(to_wei_like "2100.9")
|
|
USDC_2100_628264=$(to_wei_like "2100.628264")
|
|
USDC_4500=$(to_wei_like "4500")
|
|
# Final flashloan repay is shown as -4600, we encode +4600 as repayment
|
|
USDC_4600_POS=$(to_wei_like "4600")
|
|
|
|
# The plan is a pure JSON array of steps, each step carries:
|
|
# - blockType / protocol / display / tokens / amounts / addresses
|
|
# - You can extend with slippage, deadline, referral, etc.
|
|
jq -n --arg usdc "$ADDR_USDC" \
|
|
--arg usdt "$ADDR_USDT" \
|
|
--arg aave "$ADDR_AAVE_V3_POOL" \
|
|
--arg pswap "$ADDR_PARASWAP_V5" \
|
|
--arg aethusdc "$ADDR_aEthUSDC" \
|
|
--argjson amt_usdc_4600 "$USDC_4600" \
|
|
--argjson amt_usdt_2500 "$USDT_2500" \
|
|
--argjson amt_usdt_2000_9 "$USDT_2000_9" \
|
|
--argjson amt_usdc_2001_033032 "$USDC_2001_033032" \
|
|
--argjson amt_usdc_1000 "$USDC_1000" \
|
|
--argjson amt_usdt_2300 "$USDT_2300" \
|
|
--argjson amt_usdt_2100_9 "$USDT_2100_9" \
|
|
--argjson amt_usdc_2100_628264 "$USDC_2100_628264" \
|
|
--argjson amt_usdc_4500 "$USDC_4500" \
|
|
--argjson amt_usdc_4600 "$USDC_4600_POS" \
|
|
'[
|
|
{
|
|
blockType:"Flashloan",
|
|
protocol:"utility",
|
|
display:"Utility flashloan",
|
|
tokenIn:{symbol:"USDC", address:$usdc, amount:$amt_usdc_4600}
|
|
},
|
|
{
|
|
blockType:"Supply",
|
|
protocol:"aavev3",
|
|
display:"Aave V3",
|
|
tokenIn:{symbol:"USDC", address:$usdc, amount:$amt_usdc_4600},
|
|
tokenOut:{symbol:"aEthUSDC", address:$aethusdc, amount:$amt_usdc_4600}
|
|
},
|
|
{
|
|
blockType:"Borrow",
|
|
protocol:"aavev3",
|
|
display:"Aave V3",
|
|
tokenOut:{symbol:"USDT", address:$usdt, amount:$amt_usdt_2500}
|
|
},
|
|
{
|
|
blockType:"Swap",
|
|
protocol:"paraswapv5",
|
|
display:"Paraswap V5",
|
|
tokenIn:{symbol:"USDT", address:$usdt, amount:$amt_usdt_2000_9},
|
|
tokenOut:{symbol:"USDC", address:$usdc, minAmount:$amt_usdc_2001_033032}
|
|
},
|
|
{
|
|
blockType:"Repay",
|
|
protocol:"aavev3",
|
|
display:"Aave V3",
|
|
tokenIn:{symbol:"USDC", address:$usdc, amount:$amt_usdc_1000}
|
|
},
|
|
{
|
|
blockType:"Supply",
|
|
protocol:"aavev3",
|
|
display:"Aave V3",
|
|
tokenIn:{symbol:"USDC", address:$usdc, amount:$amt_usdc_1000},
|
|
tokenOut:{symbol:"aEthUSDC", address:$aethusdc, amount:$amt_usdc_1000}
|
|
},
|
|
{
|
|
blockType:"Borrow",
|
|
protocol:"aavev3",
|
|
display:"Aave V3",
|
|
tokenOut:{symbol:"USDT", address:$usdt, amount:$amt_usdt_2300}
|
|
},
|
|
{
|
|
blockType:"Swap",
|
|
protocol:"paraswapv5",
|
|
display:"Paraswap V5",
|
|
tokenIn:{symbol:"USDT", address:$usdt, amount:$amt_usdt_2100_9},
|
|
tokenOut:{symbol:"USDC", address:$usdc, minAmount:$amt_usdc_2100_628264}
|
|
},
|
|
{
|
|
blockType:"Repay",
|
|
protocol:"aavev3",
|
|
display:"Aave V3",
|
|
tokenIn:{symbol:"USDC", address:$usdc, amount:$amt_usdc_1000}
|
|
},
|
|
{
|
|
blockType:"Supply",
|
|
protocol:"aavev3",
|
|
display:"Aave V3",
|
|
tokenIn:{symbol:"USDC", address:$usdc, amount:$amt_usdc_1000},
|
|
tokenOut:{symbol:"aEthUSDC", address:$aethusdc, amount:$amt_usdc_1000}
|
|
},
|
|
{
|
|
blockType:"Withdraw",
|
|
protocol:"aavev3",
|
|
display:"Aave V3",
|
|
tokenIn:{symbol:"aEthUSDC", address:$aethusdc, amount:$amt_usdc_4500},
|
|
tokenOut:{symbol:"USDC", address:$usdc, amount:$amt_usdc_4500}
|
|
},
|
|
{
|
|
blockType:"FlashloanRepay",
|
|
protocol:"utility",
|
|
display:"Utility flashloan",
|
|
tokenIn:{symbol:"USDC", address:$usdc, amount:$amt_usdc_4600}
|
|
}
|
|
]' | jq '.' > "$PLAN_FILE"
|
|
|
|
echo "Plan written to $PLAN_FILE" >&2
|
|
cat "$PLAN_FILE"
|
|
}
|
|
|
|
show_plan() {
|
|
require_jq
|
|
[[ -f "$PLAN_FILE" ]] || die "No plan file at $PLAN_FILE. Run: ./aaxe-cli.sh build-plan"
|
|
|
|
jq '.' "$PLAN_FILE"
|
|
}
|
|
|
|
send_plan() {
|
|
require_cast
|
|
require_jq
|
|
|
|
local RPC_URL="$RPC_URL_DEFAULT"
|
|
local ROUTER="$AAXE_ROUTER_DEFAULT"
|
|
local CHAIN_ID="$CHAIN_ID_DEFAULT"
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--rpc) RPC_URL="$2"; shift 2;;
|
|
--router) ROUTER="$2"; shift 2;;
|
|
--chain-id) CHAIN_ID="$2"; shift 2;;
|
|
*) die "Unknown arg: $1";;
|
|
esac
|
|
done
|
|
|
|
[[ -n "${PRIVATE_KEY:-}" ]] || die "PRIVATE_KEY not set"
|
|
[[ -f "$PLAN_FILE" ]] || die "No plan file at $PLAN_FILE. Run build-plan first."
|
|
|
|
# Encode plan.json as bytes (hex) for execute(bytes)
|
|
PLAN_JSON_MINIFIED="$(jq -c '.' "$PLAN_FILE")"
|
|
PLAN_HEX="0x$(printf '%s' "$PLAN_JSON_MINIFIED" | xxd -p -c 100000 | tr -d '\n')"
|
|
|
|
echo "Sending to router: $ROUTER"
|
|
echo "RPC: $RPC_URL"
|
|
echo "Chain ID: $CHAIN_ID"
|
|
echo "Method: execute(bytes)"
|
|
echo "Data bytes length: ${#PLAN_HEX}"
|
|
|
|
# NOTE: Adjust function signature if your router differs.
|
|
cast send \
|
|
--rpc-url "$RPC_URL" \
|
|
--private-key "$PRIVATE_KEY" \
|
|
--legacy \
|
|
"$ROUTER" \
|
|
"execute(bytes)" "$PLAN_HEX"
|
|
}
|
|
|
|
case "${1:-}" in
|
|
build-plan) build_plan ;;
|
|
show-plan) show_plan ;;
|
|
send) shift; send_plan "$@" ;;
|
|
""|-h|--help)
|
|
cat <<EOF
|
|
AAXE / Furuombe CLI
|
|
|
|
Commands:
|
|
build-plan Build the JSON plan from the specified block list and write to $PLAN_FILE
|
|
show-plan Pretty-print the current plan JSON
|
|
send [--rpc URL] [--router 0x...] [--chain-id N]
|
|
Send the plan to the router via cast (execute(bytes plan))
|
|
|
|
Examples:
|
|
./aaxe-cli.sh build-plan > plan.json
|
|
./aaxe-cli.sh show-plan
|
|
PRIVATE_KEY=... ./aaxe-cli.sh send --rpc $RPC_URL_DEFAULT --router $AAXE_ROUTER_DEFAULT
|
|
|
|
Edit addresses at the top of the script to match your network.
|
|
EOF
|
|
;;
|
|
*)
|
|
die "Unknown command: ${1:-}. Try --help"
|
|
;;
|
|
esac
|
|
|