chore: sync submodule state (parent ref update)
Made-with: Cursor
This commit is contained in:
62
scripts/lib/deployment/README.md
Normal file
62
scripts/lib/deployment/README.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# Deployment script library
|
||||
|
||||
Reusable helpers for deployment scripts: **tag-based CLI** (no .env placeholders for one-off values), **interactive prompts** when run without args, and **callable modular linking** so scripts can invoke each other with arguments.
|
||||
|
||||
## Conventions
|
||||
|
||||
- **Secrets and chain config** stay in `.env` (e.g. `PRIVATE_KEY`, RPC URLs, contract addresses).
|
||||
- **One-off or per-run values** are passed via **script tags** (e.g. `--eth 1.5`, `--chain bsc polygon`, `--lockbox`), not .env.
|
||||
- Scripts that accept amounts **prompt interactively** when run with no args and stdin is a TTY.
|
||||
- Scripts are **callable** from other scripts by passing the same tags (e.g. `run-all-four-gaps.sh g4 --eth 1`).
|
||||
|
||||
## Modules
|
||||
|
||||
| File | Purpose |
|
||||
|------|--------|
|
||||
| `prompts.sh` | Tag parsers: `parse_fund_tags` (--eth, --weth, --dry-run), `prompt_fund_amounts`, `eth_to_wei`, `parse_phase_tags` (g1, g2g3, g4), `parse_chain_filter` (--chain bsc polygon ...), `parse_lockbox_tag` (--lockbox / --no-lockbox), `parse_link_tags` (--link, --dry-run), `parse_dry_run_tag`, `parse_deploy_tag` (--deploy), `parse_delay_tag` (--delay). `L2_CHAIN_NAMES`, `normalize_chain_name`. |
|
||||
| `dotenv.sh` | `load_deployment_env`, `require_fund_lp_env`. |
|
||||
| `costs.sh` | Gas and cost helpers (existing). |
|
||||
|
||||
## Validate syntax (one command)
|
||||
|
||||
- **From this repo** (`smom-dbis-138`):
|
||||
`./scripts/deployment/check-syntax.sh`
|
||||
- **From workspace root** (e.g. `proxmox`):
|
||||
`./smom-dbis-138/scripts/deployment/check-syntax.sh`
|
||||
|
||||
Checks all tag-based deployment scripts and the lib with `bash -n`.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# From any script in scripts/deployment:
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/../lib/deployment/dotenv.sh"
|
||||
source "$SCRIPT_DIR/../lib/deployment/prompts.sh"
|
||||
load_deployment_env
|
||||
|
||||
# Parse G4 amounts from args, then prompt if still empty (TTY)
|
||||
parse_fund_tags "$@"
|
||||
prompt_fund_amounts
|
||||
# Use FUND_ETH_AMOUNT_WEI, FUND_WETH_AMOUNT_WEI
|
||||
```
|
||||
|
||||
## Example: G4 fund mainnet LP
|
||||
|
||||
- **Standalone:** `./scripts/deployment/fund-mainnet-lp.sh --eth 1.5 --weth 0.5`
|
||||
- **Interactive:** `./scripts/deployment/fund-mainnet-lp.sh`
|
||||
- **From run-all:** `./scripts/deployment/run-all-four-gaps.sh g4 --eth 1`
|
||||
|
||||
No `FUND_ETH_AMOUNT_WEI` / `FUND_WETH_AMOUNT_WEI` in .env.
|
||||
|
||||
## Other scripts (tags)
|
||||
|
||||
| Script | Tags |
|
||||
|--------|------|
|
||||
| deploy-pmm-all-l2s.sh | --chain bsc polygon ... (or DEPLOY_PMM_L2S_FILTER in .env) |
|
||||
| live-test-trustless-bridge.sh | --check (optional: print LP stats and BondManager totalEthHeld); prints cast commands for lock → claim → finalize → release |
|
||||
| deploy-trustless-l2s.sh | --chain, --lockbox / --no-lockbox |
|
||||
| fund-ccip-bridges-with-link.sh | --link amount, --dry-run |
|
||||
| fix-nonce-and-retry.sh | --chain, --script (positional still supported) |
|
||||
| run-remaining-g2g3-with-nonce-fix.sh | --delay, --lockbox / --no-lockbox |
|
||||
| check-balances-gas-and-deploy.sh | --deploy |
|
||||
51
scripts/lib/deployment/dotenv.sh
Normal file
51
scripts/lib/deployment/dotenv.sh
Normal file
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
# Load deployment .env and require common vars.
|
||||
# Usage: source "$SCRIPT_DIR/lib/deployment/dotenv.sh"
|
||||
# Optional: load_deployment_env [--repo-root <path>]
|
||||
#
|
||||
# Correct dotenv file (in order):
|
||||
# 1. ENV_FILE if set and the file exists (e.g. export ENV_FILE=/path/to/.env)
|
||||
# 2. PROJECT_ROOT/.env (repo root; PROJECT_ROOT = scripts/lib/deployment/../.. when unset)
|
||||
# So: use repo-root .env by default; set ENV_FILE to use a different file.
|
||||
|
||||
_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
[[ -z "${PROJECT_ROOT:-}" ]] && PROJECT_ROOT="$(cd "$_LIB_DIR/../.." && pwd)"
|
||||
|
||||
# Preferred .env: ENV_FILE if set and readable; else PROJECT_ROOT/.env (repo root).
|
||||
load_deployment_env() {
|
||||
local root="${PROJECT_ROOT}"
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--repo-root) root="$2"; shift 2 ;;
|
||||
*) shift ;;
|
||||
esac
|
||||
done
|
||||
export PROJECT_ROOT="$root"
|
||||
local dotenv="${root}/.env"
|
||||
[[ -n "${ENV_FILE:-}" && -f "${ENV_FILE}" ]] && dotenv="${ENV_FILE}"
|
||||
if [[ -f "$dotenv" ]]; then
|
||||
set -a
|
||||
# shellcheck disable=SC1090
|
||||
source "$dotenv"
|
||||
set +a
|
||||
fi
|
||||
}
|
||||
|
||||
# Require vars for mainnet LP funding (G4). Fails with message if missing.
|
||||
require_fund_lp_env() {
|
||||
load_deployment_env
|
||||
: "${LIQUIDITY_POOL_ETH_MAINNET:=${LIQUIDITY_POOL:-}}"
|
||||
if [[ -z "${LIQUIDITY_POOL_ETH_MAINNET:-}" ]]; then
|
||||
echo "Set LIQUIDITY_POOL_ETH_MAINNET (or LIQUIDITY_POOL) in .env" >&2
|
||||
return 1
|
||||
fi
|
||||
if [[ -z "${ETHEREUM_MAINNET_RPC:-}" ]]; then
|
||||
echo "Set ETHEREUM_MAINNET_RPC in .env" >&2
|
||||
return 1
|
||||
fi
|
||||
if [[ -z "${PRIVATE_KEY:-}" ]]; then
|
||||
echo "Set PRIVATE_KEY in .env" >&2
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
247
scripts/lib/deployment/prompts.sh
Normal file
247
scripts/lib/deployment/prompts.sh
Normal file
@@ -0,0 +1,247 @@
|
||||
#!/usr/bin/env bash
|
||||
# Deployment tag parsing and interactive prompts.
|
||||
# Usage: source "$SCRIPT_DIR/lib/deployment/prompts.sh"
|
||||
# Provides: parse_fund_tags, prompt_fund_amounts, eth_to_wei, parse_phase_tags
|
||||
|
||||
# Resolve lib and project paths when sourced
|
||||
_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
[[ -z "${PROJECT_ROOT:-}" ]] && PROJECT_ROOT="$(cd "$_LIB_DIR/../.." && pwd)"
|
||||
|
||||
# Convert ETH string to wei (supports "1.5", "1.5eth", "1000000000000000000" or "1000000000000000000wei")
|
||||
eth_to_wei() {
|
||||
local val="${1:-0}"
|
||||
if [[ -z "$val" || "$val" == "0" ]]; then
|
||||
echo "0"
|
||||
return 0
|
||||
fi
|
||||
if [[ "$val" == *wei ]]; then
|
||||
echo "${val%wei}"
|
||||
return 0
|
||||
fi
|
||||
if [[ "$val" == *eth ]]; then
|
||||
val="${val%eth}"
|
||||
fi
|
||||
if command -v cast &>/dev/null; then
|
||||
cast to-wei "$val" ether 2>/dev/null || echo "0"
|
||||
else
|
||||
# Fallback: 1 eth = 1e18 (bash can't do float well; use bc/python if available)
|
||||
if command -v python3 &>/dev/null; then
|
||||
python3 -c "import math; print(int(float('$val') * 10**18))" 2>/dev/null || echo "0"
|
||||
else
|
||||
echo "0"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Parse --eth, --weth, --eth-wei, --weth-wei, --dry-run from "$@".
|
||||
# Sets: FUND_ETH_AMOUNT_WEI, FUND_WETH_AMOUNT_WEI (exported), DRY_RUN=1 if --dry-run.
|
||||
# Consumed args are removed from the array; use parse_fund_tags "${@}" before other parsers.
|
||||
parse_fund_tags() {
|
||||
export FUND_ETH_AMOUNT_WEI="${FUND_ETH_AMOUNT_WEI:-0}"
|
||||
export FUND_WETH_AMOUNT_WEI="${FUND_WETH_AMOUNT_WEI:-0}"
|
||||
export DRY_RUN="${DRY_RUN:-0}"
|
||||
local args=()
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--eth)
|
||||
FUND_ETH_AMOUNT_WEI="$(eth_to_wei "${2:-0}")"
|
||||
shift 2
|
||||
;;
|
||||
--weth)
|
||||
FUND_WETH_AMOUNT_WEI="$(eth_to_wei "${2:-0}")"
|
||||
shift 2
|
||||
;;
|
||||
--eth-wei)
|
||||
FUND_ETH_AMOUNT_WEI="${2:-0}"
|
||||
shift 2
|
||||
;;
|
||||
--weth-wei)
|
||||
FUND_WETH_AMOUNT_WEI="${2:-0}"
|
||||
shift 2
|
||||
;;
|
||||
--dry-run)
|
||||
DRY_RUN=1
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
args+=("$1")
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
# Return unconsumed args (caller can set PARSE_FUND_TAGS_REMAINING=( "${args[@]}" ) or use as needed)
|
||||
PARSE_FUND_TAGS_REMAINING=("${args[@]}")
|
||||
}
|
||||
|
||||
# Interactive prompt for ETH/WETH amounts (only if both are 0 and stdin is a TTY).
|
||||
# Sets FUND_ETH_AMOUNT_WEI and FUND_WETH_AMOUNT_WEI (exported).
|
||||
prompt_fund_amounts() {
|
||||
local eth_wei="${FUND_ETH_AMOUNT_WEI:-0}"
|
||||
local weth_wei="${FUND_WETH_AMOUNT_WEI:-0}"
|
||||
if [[ -n "$eth_wei" && "$eth_wei" != "0" ]] || [[ -n "$weth_wei" && "$weth_wei" != "0" ]]; then
|
||||
return 0
|
||||
fi
|
||||
if [[ ! -t 0 ]]; then
|
||||
return 0
|
||||
fi
|
||||
echo "G4: Fund mainnet Liquidity Pool (ETH and/or WETH)."
|
||||
read -r -p "ETH amount (e.g. 1.5 or 0 to skip): " eth_input
|
||||
read -r -p "WETH amount (e.g. 0.5 or 0 to skip): " weth_input
|
||||
export FUND_ETH_AMOUNT_WEI="$(eth_to_wei "${eth_input:-0}")"
|
||||
export FUND_WETH_AMOUNT_WEI="$(eth_to_wei "${weth_input:-0}")"
|
||||
}
|
||||
|
||||
# Parse phase tags: g1, g2, g3, g2g3, g4 from "$@".
|
||||
# Sets: RUN_G1, RUN_G2G3, RUN_G4 (0 or 1). Unconsumed args left in PARSE_PHASE_TAGS_REMAINING.
|
||||
parse_phase_tags() {
|
||||
RUN_G1=0
|
||||
RUN_G2G3=0
|
||||
RUN_G4=0
|
||||
local args=()
|
||||
for arg in "$@"; do
|
||||
case "${arg,,}" in
|
||||
g1) RUN_G1=1 ;;
|
||||
g2|g3|g2g3) RUN_G2G3=1 ;;
|
||||
g4) RUN_G4=1 ;;
|
||||
*) args+=("$arg") ;;
|
||||
esac
|
||||
done
|
||||
# If no phase given, run all
|
||||
if [[ "$RUN_G1" -eq 0 && "$RUN_G2G3" -eq 0 && "$RUN_G4" -eq 0 ]]; then
|
||||
RUN_G1=1
|
||||
RUN_G2G3=1
|
||||
RUN_G4=1
|
||||
fi
|
||||
PARSE_PHASE_TAGS_REMAINING=("${args[@]}")
|
||||
}
|
||||
|
||||
# Canonical L2 list for deploy-pmm, deploy-trustless, fund-ccip, etc.
|
||||
L2_CHAIN_NAMES=( BSC POLYGON BASE OPTIMISM ARBITRUM AVALANCHE CRONOS GNOSIS )
|
||||
|
||||
# Parse --chain <name> [<name> ...] from "$@". Names case-insensitive (bsc, BSC, Polygon, etc.).
|
||||
# Sets CHAIN_FILTER=() (empty = all) or CHAIN_FILTER=( BSC POLYGON ... ). Unconsumed in PARSE_CHAIN_FILTER_REMAINING.
|
||||
normalize_chain_name() {
|
||||
case "${1^^}" in
|
||||
BSC) echo BSC ;;
|
||||
POLYGON) echo POLYGON ;;
|
||||
BASE) echo BASE ;;
|
||||
OPTIMISM) echo OPTIMISM ;;
|
||||
ARBITRUM) echo ARBITRUM ;;
|
||||
AVALANCHE) echo AVALANCHE ;;
|
||||
CRONOS) echo CRONOS ;;
|
||||
GNOSIS) echo GNOSIS ;;
|
||||
*) echo "" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
parse_chain_filter() {
|
||||
CHAIN_FILTER=()
|
||||
local args=()
|
||||
local collecting=0
|
||||
for arg in "$@"; do
|
||||
if [[ "$arg" == "--chain" ]]; then
|
||||
collecting=1
|
||||
elif [[ "$collecting" -eq 1 ]]; then
|
||||
local n; n="$(normalize_chain_name "$arg")"
|
||||
if [[ -n "$n" ]]; then
|
||||
CHAIN_FILTER+=("$n")
|
||||
else
|
||||
args+=("$arg")
|
||||
collecting=0
|
||||
fi
|
||||
else
|
||||
args+=("$arg")
|
||||
fi
|
||||
done
|
||||
PARSE_CHAIN_FILTER_REMAINING=("${args[@]}")
|
||||
}
|
||||
|
||||
# Parse --lockbox / --no-lockbox. Sets TRUSTLESS_DEPLOY_LOCKBOX=1 or 0. Default from env or 0.
|
||||
# Unconsumed in PARSE_LOCKBOX_REMAINING.
|
||||
parse_lockbox_tag() {
|
||||
TRUSTLESS_DEPLOY_LOCKBOX="${TRUSTLESS_DEPLOY_LOCKBOX:-0}"
|
||||
local args=()
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--lockbox) TRUSTLESS_DEPLOY_LOCKBOX=1; ;;
|
||||
--no-lockbox) TRUSTLESS_DEPLOY_LOCKBOX=0; ;;
|
||||
*) args+=("$arg") ;;
|
||||
esac
|
||||
done
|
||||
PARSE_LOCKBOX_REMAINING=("${args[@]}")
|
||||
}
|
||||
|
||||
# Parse --link <amount> (ETH or wei if --link-wei), --dry-run. Sets LINK_AMOUNT_WEI, DRY_RUN.
|
||||
# Default LINK_AMOUNT_WEI 10e18 (10 LINK) when unset. Unconsumed in PARSE_LINK_TAGS_REMAINING.
|
||||
link_to_wei() {
|
||||
local val="${1:-0}"
|
||||
if [[ -z "$val" || "$val" == "0" ]]; then echo "0"; return; fi
|
||||
if [[ "$val" == *wei ]]; then echo "${val%wei}"; return; fi
|
||||
if command -v cast &>/dev/null; then
|
||||
cast to-wei "$val" ether 2>/dev/null || echo "0"
|
||||
elif command -v python3 &>/dev/null; then
|
||||
python3 -c "import math; print(int(float('$val') * 10**18))" 2>/dev/null || echo "0"
|
||||
else
|
||||
echo "0"
|
||||
fi
|
||||
}
|
||||
|
||||
parse_link_tags() {
|
||||
export LINK_AMOUNT_WEI="${LINK_AMOUNT_WEI:-10000000000000000000}"
|
||||
export DRY_RUN="${DRY_RUN:-0}"
|
||||
local args=()
|
||||
local i=0
|
||||
local argv=("$@")
|
||||
while [[ $i -lt ${#argv[@]} ]]; do
|
||||
local a="${argv[$i]}"
|
||||
case "$a" in
|
||||
--link)
|
||||
[[ $((i+1)) -lt ${#argv[@]} ]] && LINK_AMOUNT_WEI="$(link_to_wei "${argv[$((i+1))]}")"
|
||||
i=$((i+2)); ;;
|
||||
--link-wei)
|
||||
[[ $((i+1)) -lt ${#argv[@]} ]] && LINK_AMOUNT_WEI="${argv[$((i+1))]}"
|
||||
i=$((i+2)); ;;
|
||||
--dry-run) DRY_RUN=1; i=$((i+1)); ;;
|
||||
*) args+=("$a"); i=$((i+1)); ;;
|
||||
esac
|
||||
done
|
||||
PARSE_LINK_TAGS_REMAINING=("${args[@]}")
|
||||
}
|
||||
|
||||
# Parse --dry-run only. Sets DRY_RUN=1. Unconsumed in PARSE_DRY_RUN_REMAINING.
|
||||
parse_dry_run_tag() {
|
||||
DRY_RUN="${DRY_RUN:-0}"
|
||||
local args=()
|
||||
for arg in "$@"; do
|
||||
if [[ "$arg" == "--dry-run" ]]; then DRY_RUN=1; else args+=("$arg"); fi
|
||||
done
|
||||
PARSE_DRY_RUN_REMAINING=("${args[@]}")
|
||||
}
|
||||
|
||||
# Parse --deploy. Sets DO_DEPLOY=1. Unconsumed in PARSE_DEPLOY_REMAINING.
|
||||
parse_deploy_tag() {
|
||||
DO_DEPLOY="${DO_DEPLOY:-0}"
|
||||
local args=()
|
||||
for arg in "$@"; do
|
||||
if [[ "$arg" == "--deploy" ]]; then DO_DEPLOY=1; else args+=("$arg"); fi
|
||||
done
|
||||
PARSE_DEPLOY_REMAINING=("${args[@]}")
|
||||
}
|
||||
|
||||
# Parse --delay <seconds>. Sets DELAY_BETWEEN_CHAINS. Unconsumed in PARSE_DELAY_REMAINING.
|
||||
parse_delay_tag() {
|
||||
DELAY_BETWEEN_CHAINS="${DELAY_BETWEEN_CHAINS:-45}"
|
||||
local args=()
|
||||
local i=0
|
||||
local argv=("$@")
|
||||
while [[ $i -lt ${#argv[@]} ]]; do
|
||||
if [[ "${argv[$i]}" == "--delay" && $((i+1)) -lt ${#argv[@]} ]]; then
|
||||
DELAY_BETWEEN_CHAINS="${argv[$((i+1))]}"
|
||||
i=$((i+2))
|
||||
else
|
||||
args+=("${argv[$i]}")
|
||||
i=$((i+1))
|
||||
fi
|
||||
done
|
||||
PARSE_DELAY_REMAINING=("${args[@]}")
|
||||
}
|
||||
Reference in New Issue
Block a user