fix(pmm-soak): shellcheck-clean bots/tick/bootstrap; expand CI ShellCheck
- bootstrap: split mnemonic export (SC2155), PMM_SOAK_RPC_URL_OVERRIDE, noprofile fund-grid, ASCII echoes, help header only - chain138-tick: document POOLS global for SC2153 - random/grid bots: log line references INTEGRATION, USD bounds, gold, gas, log_tag (SC2034) - validate-config: ShellCheck all 11 PMM soak + chain138-pmm shell scripts incl. smoke + bootstrap Made-with: Cursor
This commit is contained in:
21
.github/workflows/validate-config.yml
vendored
21
.github/workflows/validate-config.yml
vendored
@@ -117,18 +117,25 @@ jobs:
|
||||
bash explorer-monorepo/scripts/generate-topology-graph.sh
|
||||
git diff --exit-code explorer-monorepo/frontend/public/config/topology-graph.json
|
||||
|
||||
- name: ShellCheck (PMM soak grid operator scripts)
|
||||
- name: ShellCheck (PMM soak grid scripts)
|
||||
run: |
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y shellcheck
|
||||
set -euo pipefail
|
||||
shellcheck -x \
|
||||
scripts/deployment/pmm-soak-operator-fund-grid.sh \
|
||||
scripts/deployment/pmm-soak-complete-grid-funding-operator.sh \
|
||||
scripts/deployment/pmm-soak-operator-fund-full-grid-tranches.sh \
|
||||
scripts/deployment/pmm-soak-mint-mirror-usdc-deployer-shortfall.sh \
|
||||
scripts/lib/pmm-soak-dotenv-override.sh \
|
||||
shells=(
|
||||
scripts/deployment/pmm-soak-operator-fund-grid.sh
|
||||
scripts/deployment/pmm-soak-complete-grid-funding-operator.sh
|
||||
scripts/deployment/pmm-soak-operator-fund-full-grid-tranches.sh
|
||||
scripts/deployment/pmm-soak-mint-mirror-usdc-deployer-shortfall.sh
|
||||
scripts/deployment/pmm-soak-complete-operator-bootstrap.sh
|
||||
scripts/deployment/pmm-soak-grid-smoke-check.sh
|
||||
scripts/lib/pmm-soak-dotenv-override.sh
|
||||
scripts/lib/pmm-soak-pools.sh
|
||||
scripts/lib/pmm-soak-chain138-tick.sh
|
||||
scripts/deployment/chain138-pmm-random-soak-swaps.sh
|
||||
scripts/deployment/chain138-pmm-soak-grid-bot.sh
|
||||
)
|
||||
shellcheck -x "${shells[@]}"
|
||||
|
||||
- name: Shellcheck (optional)
|
||||
run: bash scripts/verify/run-shellcheck.sh --optional
|
||||
|
||||
153
scripts/deployment/chain138-pmm-random-soak-swaps.sh
Executable file
153
scripts/deployment/chain138-pmm-random-soak-swaps.sh
Executable file
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env bash
|
||||
# Chain 138 — continuous random PMM swaps across funded pools (single deployer wallet).
|
||||
#
|
||||
# Each interval (default 6s): pick a random live pool, random direction (base/quote in),
|
||||
# random notional between USD_MIN and USD_MAX (for USD-pegged stables), then execute swap
|
||||
# (default CHAIN138_PMM_SOAK_SWAP_VIA=pool: transfer + sellBase/sellQuote; optional integration).
|
||||
#
|
||||
# For 33x33x6 grid wallets + operator funding, use chain138-pmm-soak-grid-bot.sh
|
||||
#
|
||||
# Safety: default is dry-run (no chain writes). Live swaps require: --apply and PRIVATE_KEY.
|
||||
#
|
||||
# Usage:
|
||||
# bash scripts/deployment/chain138-pmm-random-soak-swaps.sh --dry-run --max-ticks 5
|
||||
# PMM_SOAK_INTERVAL_SEC=6 bash scripts/deployment/chain138-pmm-random-soak-swaps.sh --apply
|
||||
#
|
||||
# Env: (see scripts/lib/pmm-soak-chain138-tick.sh) + PMM_SOAK_MAX_ITER / --max-ticks
|
||||
# Pools: PMM_SOAK_POOLS | PMM_SOAK_POOLS_FILE | PMM_SOAK_POOL_PRESET (see scripts/lib/pmm-soak-pools.sh)
|
||||
# CLI: --pool-preset <name> | --swap-via pool|integration
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
|
||||
APPLY=0
|
||||
CLI_MAX_ITER=""
|
||||
CLI_POOL_PRESET=""
|
||||
CLI_SWAP_VIA=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--apply) APPLY=1 ;;
|
||||
--dry-run) APPLY=0 ;;
|
||||
--max-ticks)
|
||||
CLI_MAX_ITER="$2"
|
||||
shift
|
||||
;;
|
||||
--pool-preset)
|
||||
CLI_POOL_PRESET="$2"
|
||||
shift
|
||||
;;
|
||||
--swap-via)
|
||||
CLI_SWAP_VIA="$2"
|
||||
shift
|
||||
;;
|
||||
-h | --help)
|
||||
echo "chain138-pmm-random-soak-swaps.sh — single-wallet PMM soak (deployer)"
|
||||
echo ""
|
||||
echo "Usage: $0 [--dry-run|--apply] [--max-ticks N] [--pool-preset NAME] [--swap-via pool|integration]"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "[pmm-soak] unknown arg: $1" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
source "${PROJECT_ROOT}/scripts/lib/pmm-soak-dotenv-override.sh"
|
||||
pmm_soak_snapshot_pool_env_for_restore
|
||||
# shellcheck source=/dev/null
|
||||
[[ -f "${PROJECT_ROOT}/scripts/lib/load-project-env.sh" ]] && source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh"
|
||||
pmm_soak_restore_pool_env_after_dotenv
|
||||
|
||||
if [[ -n "$CLI_SWAP_VIA" ]]; then
|
||||
export CHAIN138_PMM_SOAK_SWAP_VIA="$CLI_SWAP_VIA"
|
||||
fi
|
||||
if [[ -n "$CLI_POOL_PRESET" ]]; then
|
||||
export PMM_SOAK_POOL_PRESET="$CLI_POOL_PRESET"
|
||||
unset PMM_SOAK_POOLS PMM_SOAK_POOLS_FILE 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
source "${PROJECT_ROOT}/scripts/lib/pmm-soak-chain138-tick.sh"
|
||||
# shellcheck source=/dev/null
|
||||
source "${PROJECT_ROOT}/scripts/lib/pmm-soak-pools.sh"
|
||||
|
||||
require_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || {
|
||||
echo "[pmm-soak] missing: $1" >&2
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
require_cmd cast
|
||||
require_cmd python3
|
||||
require_cmd bc
|
||||
|
||||
PK="${DEPLOYER_PRIVATE_KEY:-${PRIVATE_KEY:-}}"
|
||||
RPC="${RPC_URL_138:-http://192.168.11.211:8545}"
|
||||
INTEGRATION="${DODO_PMM_INTEGRATION_ADDRESS:-${CHAIN_138_DODO_PMM_INTEGRATION:-0x86ADA6Ef91A3B450F89f2b751e93B1b7A3218895}}"
|
||||
INTERVAL="${PMM_SOAK_INTERVAL_SEC:-6}"
|
||||
USD_MIN="${PMM_SOAK_USD_MIN:-10}"
|
||||
USD_MAX="${PMM_SOAK_USD_MAX:-5000}"
|
||||
SLIP_BPS="${PMM_SOAK_SLIPPAGE_BPS:-100}"
|
||||
GOLD_USD="${GOLD_USD_PRICE:-3300}"
|
||||
GAS_WEI="${CHAIN138_DEPLOY_GAS_PRICE_WEI:-1000}"
|
||||
SOAK_MAX_ITER="${CLI_MAX_ITER:-${PMM_SOAK_MAX_ITER:-}}"
|
||||
|
||||
pmm_soak_load_pools || exit 1
|
||||
|
||||
PMM_SOAK_LOG_TAG="pmm-soak"
|
||||
log() { pmm_soak_log "$@"; }
|
||||
|
||||
deployer_addr() {
|
||||
if [[ -z "$PK" ]]; then
|
||||
echo ""
|
||||
return
|
||||
fi
|
||||
cast wallet address --private-key "$PK" 2>/dev/null || true
|
||||
}
|
||||
|
||||
DEPLOYER="$(deployer_addr)"
|
||||
|
||||
if [[ "$APPLY" -eq 1 ]]; then
|
||||
if [[ -z "$PK" ]]; then
|
||||
log "FATAL: --apply requires PRIVATE_KEY or DEPLOYER_PRIVATE_KEY"
|
||||
exit 1
|
||||
fi
|
||||
if [[ -z "$DEPLOYER" ]]; then
|
||||
log "FATAL: could not derive address from private key"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
DEPLOYER="${DEPLOYER_ADDRESS:-0x4A666F96fC8764181194447A7dFdb7d471b301C8}"
|
||||
log "Dry-run mode (no txs). Use --apply for live swaps."
|
||||
fi
|
||||
|
||||
LOCK="/tmp/chain138-pmm-random-soak.${USER}.lock"
|
||||
if [[ "$APPLY" -eq 1 ]]; then
|
||||
if ! mkdir "$LOCK" 2>/dev/null; then
|
||||
log "FATAL: lock exists $LOCK — another soak bot may be running"
|
||||
exit 1
|
||||
fi
|
||||
trap 'rmdir "$LOCK" 2>/dev/null || true' EXIT
|
||||
fi
|
||||
|
||||
SWAP_VIA_LOG="${CHAIN138_PMM_SOAK_SWAP_VIA:-pool}"
|
||||
log "RPC=$RPC integration=$INTEGRATION swap_via=$SWAP_VIA_LOG interval=${INTERVAL}s deployer=$DEPLOYER pools=${#POOLS[@]} USD=${USD_MIN}-${USD_MAX} slip_bps=$SLIP_BPS gold_usd=$GOLD_USD gas_wei=$GAS_WEI log_tag=$PMM_SOAK_LOG_TAG apply=$APPLY"
|
||||
|
||||
tick=0
|
||||
while true; do
|
||||
tick=$((tick + 1))
|
||||
pmm_soak_chain138_run_tick_iteration "$tick" "$DEPLOYER" "$PK" "$APPLY"
|
||||
|
||||
if [[ -n "$SOAK_MAX_ITER" && "$tick" -ge "$SOAK_MAX_ITER" ]]; then
|
||||
log "SOAK_MAX_ITER=$SOAK_MAX_ITER done"
|
||||
break
|
||||
fi
|
||||
sleep "$INTERVAL"
|
||||
done
|
||||
253
scripts/deployment/chain138-pmm-soak-grid-bot.sh
Executable file
253
scripts/deployment/chain138-pmm-soak-grid-bot.sh
Executable file
@@ -0,0 +1,253 @@
|
||||
#!/usr/bin/env bash
|
||||
# Chain 138 PMM soak — 33x33x6 grid wallets (6534) rotate swaps; deployer is operator (fund + tune via env).
|
||||
#
|
||||
# Wallets: BIP44 path m/44'/60'/0'/0/{linearIndex} for linearIndex = lpbca*198 + branch*6 + class
|
||||
# (lpbca, branch in 0..32; class in 0..5).
|
||||
#
|
||||
# Optional inter-wallet ERC-20 transfers: set PMM_SOAK_TRANSFER_PROBABILITY and PMM_SOAK_TRANSFER_TOKEN
|
||||
#
|
||||
# Usage:
|
||||
# PMM_SOAK_GRID_MNEMONIC='twelve words...' bash scripts/deployment/chain138-pmm-soak-grid-bot.sh --dry-run --max-ticks 5
|
||||
# PMM_SOAK_GRID_JSON=config/pmm-soak-wallet-grid.json bash scripts/deployment/chain138-pmm-soak-grid-bot.sh --dry-run --max-ticks 5
|
||||
# ... --apply
|
||||
#
|
||||
# Export addresses (no keys in file): pmm-soak-export-wallet-grid.py
|
||||
# Fund from operator: pmm-soak-operator-fund-grid.sh
|
||||
#
|
||||
# Env (tuning):
|
||||
# PMM_SOAK_GRID_MNEMONIC — required for --apply; for address lookup without exposing mnemonic in process use PMM_SOAK_GRID_JSON
|
||||
# PMM_SOAK_GRID_JSON — optional exported manifest (faster address resolve)
|
||||
# PMM_SOAK_INTERVAL_SEC — default 6
|
||||
# PMM_SOAK_TRANSFER_PROBABILITY — 0..1, default 0
|
||||
# PMM_SOAK_TRANSFER_TOKEN / PMM_SOAK_TRANSFER_USD_MIN / PMM_SOAK_TRANSFER_USD_MAX
|
||||
# PMM_SOAK_LINEAR_MIN / PMM_SOAK_LINEAR_MAX — default 0..6533
|
||||
# PMM_SOAK_MAX_ITER / --max-ticks
|
||||
# PMM_SOAK_POOLS | PMM_SOAK_POOLS_FILE | PMM_SOAK_POOL_PRESET (scripts/lib/pmm-soak-pools.sh)
|
||||
# CHAIN138_PMM_SOAK_SWAP_VIA — pool (default) | integration (see scripts/lib/pmm-soak-chain138-tick.sh)
|
||||
# Caller exports for pool/swap-via override values from root .env after load-project-env (see pmm-soak-dotenv-override.sh).
|
||||
# CLI: --pool-preset <name> | --swap-via pool|integration
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
|
||||
APPLY=0
|
||||
CLI_MAX_ITER=""
|
||||
CLI_POOL_PRESET=""
|
||||
CLI_SWAP_VIA=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--apply) APPLY=1 ;;
|
||||
--dry-run) APPLY=0 ;;
|
||||
--max-ticks)
|
||||
CLI_MAX_ITER="$2"
|
||||
shift
|
||||
;;
|
||||
--pool-preset)
|
||||
CLI_POOL_PRESET="$2"
|
||||
shift
|
||||
;;
|
||||
--swap-via)
|
||||
CLI_SWAP_VIA="$2"
|
||||
shift
|
||||
;;
|
||||
-h | --help)
|
||||
echo "chain138-pmm-soak-grid-bot.sh — PMM soak across 6,534 grid wallets"
|
||||
echo ""
|
||||
echo "Usage: $0 [--dry-run|--apply] [--max-ticks N] [--pool-preset NAME] [--swap-via pool|integration]"
|
||||
echo "Env: PMM_SOAK_GRID_MNEMONIC, PMM_SOAK_GRID_JSON, PMM_SOAK_LINEAR_MIN/MAX, PMM_SOAK_POOL_PRESET, ..."
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "[pmm-grid] unknown arg: $1" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
source "${PROJECT_ROOT}/scripts/lib/pmm-soak-dotenv-override.sh"
|
||||
pmm_soak_snapshot_pool_env_for_restore
|
||||
# shellcheck source=/dev/null
|
||||
[[ -f "${PROJECT_ROOT}/scripts/lib/load-project-env.sh" ]] && source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh"
|
||||
pmm_soak_restore_pool_env_after_dotenv
|
||||
|
||||
if [[ -n "$CLI_SWAP_VIA" ]]; then
|
||||
export CHAIN138_PMM_SOAK_SWAP_VIA="$CLI_SWAP_VIA"
|
||||
fi
|
||||
if [[ -n "$CLI_POOL_PRESET" ]]; then
|
||||
export PMM_SOAK_POOL_PRESET="$CLI_POOL_PRESET"
|
||||
unset PMM_SOAK_POOLS PMM_SOAK_POOLS_FILE 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
source "${PROJECT_ROOT}/scripts/lib/pmm-soak-chain138-tick.sh"
|
||||
# shellcheck source=/dev/null
|
||||
source "${PROJECT_ROOT}/scripts/lib/pmm-soak-pools.sh"
|
||||
|
||||
require_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || {
|
||||
echo "[pmm-grid] missing: $1" >&2
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
require_cmd cast
|
||||
require_cmd python3
|
||||
require_cmd bc
|
||||
|
||||
MN="${PMM_SOAK_GRID_MNEMONIC:-}"
|
||||
RPC="${RPC_URL_138:-http://192.168.11.211:8545}"
|
||||
INTEGRATION="${DODO_PMM_INTEGRATION_ADDRESS:-${CHAIN_138_DODO_PMM_INTEGRATION:-0x86ADA6Ef91A3B450F89f2b751e93B1b7A3218895}}"
|
||||
INTERVAL="${PMM_SOAK_INTERVAL_SEC:-6}"
|
||||
# For 6-decimal stables, amount = random(usd_min..usd_max) * 10^6 (face value in token units, not wei of ETH).
|
||||
USD_MIN="${PMM_SOAK_USD_MIN:-10}"
|
||||
USD_MAX="${PMM_SOAK_USD_MAX:-5000}"
|
||||
SLIP_BPS="${PMM_SOAK_SLIPPAGE_BPS:-100}"
|
||||
GOLD_USD="${GOLD_USD_PRICE:-3300}"
|
||||
GAS_WEI="${CHAIN138_DEPLOY_GAS_PRICE_WEI:-1000}"
|
||||
SOAK_MAX_ITER="${CLI_MAX_ITER:-${PMM_SOAK_MAX_ITER:-}}"
|
||||
LINEAR_MIN="${PMM_SOAK_LINEAR_MIN:-0}"
|
||||
LINEAR_MAX="${PMM_SOAK_LINEAR_MAX:-6533}"
|
||||
TRANSFER_P="${PMM_SOAK_TRANSFER_PROBABILITY:-0}"
|
||||
TRANSFER_TOKEN="${PMM_SOAK_TRANSFER_TOKEN:-}"
|
||||
TRANSFER_USD_MIN="${PMM_SOAK_TRANSFER_USD_MIN:-100}"
|
||||
TRANSFER_USD_MAX="${PMM_SOAK_TRANSFER_USD_MAX:-10000}"
|
||||
GRID_JSON="${PMM_SOAK_GRID_JSON:-}"
|
||||
|
||||
PMM_SOAK_LOG_TAG="pmm-grid"
|
||||
log() { pmm_soak_log "$@"; }
|
||||
|
||||
pmm_soak_load_pools || exit 1
|
||||
|
||||
grid_address_for_linear() {
|
||||
local li="$1"
|
||||
local path="m/44'/60'/0'/0/${li}"
|
||||
if [[ -n "$GRID_JSON" && -f "$GRID_JSON" ]]; then
|
||||
python3 - "$GRID_JSON" "$li" <<'PY' || return 1
|
||||
import json, sys
|
||||
path, li = sys.argv[1], int(sys.argv[2])
|
||||
with open(path, encoding="utf-8") as f:
|
||||
doc = json.load(f)
|
||||
for w in doc["wallets"]:
|
||||
if int(w["linearIndex"]) == li:
|
||||
print(w["address"])
|
||||
raise SystemExit(0)
|
||||
raise SystemExit(1)
|
||||
PY
|
||||
return 0
|
||||
fi
|
||||
if [[ -z "$MN" ]]; then
|
||||
return 1
|
||||
fi
|
||||
cast wallet address --mnemonic "$MN" --mnemonic-derivation-path "$path" 2>/dev/null
|
||||
}
|
||||
|
||||
grid_private_key_for_linear() {
|
||||
local li="$1"
|
||||
local path="m/44'/60'/0'/0/${li}"
|
||||
[[ -n "$MN" ]] || return 1
|
||||
cast wallet private-key --mnemonic "$MN" --mnemonic-derivation-path "$path" 2>/dev/null
|
||||
}
|
||||
|
||||
pick_linear_index() {
|
||||
local span=$((LINEAR_MAX - LINEAR_MIN + 1))
|
||||
echo $((LINEAR_MIN + RANDOM % span))
|
||||
}
|
||||
|
||||
maybe_inter_wallet_transfer() {
|
||||
local tick="$1"
|
||||
[[ -n "$TRANSFER_TOKEN" ]] || return 0
|
||||
python3 -c "import random,sys; sys.exit(0 if random.random() < float('$TRANSFER_P') else 1)" || return 0
|
||||
|
||||
local li_a li_b addr_a addr_b pk_a amt bal_out
|
||||
li_a="$(pick_linear_index)"
|
||||
li_b="$(pick_linear_index)"
|
||||
[[ "$li_a" != "$li_b" ]] || return 0
|
||||
|
||||
addr_a="$(grid_address_for_linear "$li_a")" || return 0
|
||||
addr_b="$(grid_address_for_linear "$li_b")" || return 0
|
||||
[[ -n "$addr_a" && -n "$addr_b" ]] || return 0
|
||||
|
||||
amt="$(python3 -c "import random; print(random.randint(int('$TRANSFER_USD_MIN'), int('$TRANSFER_USD_MAX')) * 10**6)")"
|
||||
|
||||
log "tick $tick transfer prep linear $li_a -> $li_b amt_raw=$amt token=$TRANSFER_TOKEN"
|
||||
|
||||
if [[ "$APPLY" -eq 0 ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! pk_a="$(grid_private_key_for_linear "$li_a")"; then
|
||||
log "WARN: could not derive sender key"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! bal_out="$(cast call "$TRANSFER_TOKEN" 'balanceOf(address)(uint256)' "$addr_a" --rpc-url "$RPC" 2>/dev/null | awk '{print $1}')"; then
|
||||
return 0
|
||||
fi
|
||||
if (( $(echo "$bal_out < $amt" | bc -l) )); then
|
||||
log "tick $tick skip transfer (low balance sender $li_a)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! cast send "$TRANSFER_TOKEN" 'transfer(address,uint256)(bool)' "$addr_b" "$amt" \
|
||||
--rpc-url "$RPC" --private-key "$pk_a" --legacy --gas-price "$GAS_WEI"; then
|
||||
log "WARN: transfer failed $li_a -> $li_b"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
if [[ "$APPLY" -eq 1 ]]; then
|
||||
if [[ -z "$MN" ]]; then
|
||||
log "FATAL: --apply requires PMM_SOAK_GRID_MNEMONIC"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
log "Dry-run (no chain writes). Use --apply for live grid txs."
|
||||
fi
|
||||
|
||||
LOCK="/tmp/chain138-pmm-soak-grid.${USER}.lock"
|
||||
if [[ "$APPLY" -eq 1 ]]; then
|
||||
if ! mkdir "$LOCK" 2>/dev/null; then
|
||||
log "FATAL: lock $LOCK — another grid bot running?"
|
||||
exit 1
|
||||
fi
|
||||
trap 'rmdir "$LOCK" 2>/dev/null || true' EXIT
|
||||
fi
|
||||
|
||||
SWAP_VIA_LOG="${CHAIN138_PMM_SOAK_SWAP_VIA:-pool}"
|
||||
log "RPC=$RPC integration=$INTEGRATION pools=${#POOLS[@]} swap_via=$SWAP_VIA_LOG linear=[$LINEAR_MIN,$LINEAR_MAX] interval=${INTERVAL}s USD=${USD_MIN}-${USD_MAX} slip_bps=$SLIP_BPS gold_usd=$GOLD_USD gas_wei=$GAS_WEI log_tag=$PMM_SOAK_LOG_TAG transfer_p=$TRANSFER_P apply=$APPLY"
|
||||
|
||||
tick=0
|
||||
while true; do
|
||||
tick=$((tick + 1))
|
||||
li="$(pick_linear_index)"
|
||||
|
||||
maybe_inter_wallet_transfer "$tick" || true
|
||||
|
||||
if ! addr="$(grid_address_for_linear "$li")"; then
|
||||
log "tick $tick skip (no address for linear=$li; set PMM_SOAK_GRID_MNEMONIC or PMM_SOAK_GRID_JSON)"
|
||||
else
|
||||
pk=""
|
||||
if [[ "$APPLY" -eq 1 ]]; then
|
||||
if ! pk="$(grid_private_key_for_linear "$li")"; then
|
||||
log "tick $tick skip linear=$li (no private key)"
|
||||
else
|
||||
log "tick $tick linear=$li trader=$addr"
|
||||
pmm_soak_chain138_run_tick_iteration "$tick" "$addr" "$pk" "$APPLY"
|
||||
fi
|
||||
else
|
||||
log "tick $tick linear=$li trader=$addr"
|
||||
pmm_soak_chain138_run_tick_iteration "$tick" "$addr" "$pk" "$APPLY"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -n "${SOAK_MAX_ITER:-}" && "$tick" -ge "$SOAK_MAX_ITER" ]]; then
|
||||
log "SOAK_MAX_ITER=$SOAK_MAX_ITER done"
|
||||
break
|
||||
fi
|
||||
sleep "$INTERVAL"
|
||||
done
|
||||
132
scripts/deployment/pmm-soak-complete-operator-bootstrap.sh
Executable file
132
scripts/deployment/pmm-soak-complete-operator-bootstrap.sh
Executable file
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env bash
|
||||
# One-shot: ensure grid mnemonic on disk, export 6,534 addresses, optionally fund first tranche from deployer.
|
||||
#
|
||||
# Usage:
|
||||
# bash scripts/deployment/pmm-soak-complete-operator-bootstrap.sh
|
||||
# bash scripts/deployment/pmm-soak-complete-operator-bootstrap.sh --apply-funds --to-linear 19
|
||||
#
|
||||
# Flags:
|
||||
# --init-mnemonic Create ~/.secure-secrets/chain138-pmm-soak-grid.mnemonic if missing (cast new-mnemonic).
|
||||
# --apply-funds After export, run native + cUSDT funding (requires PRIVATE_KEY).
|
||||
# --to-linear N Last linear index for funding tranche (default 19).
|
||||
# --skip-export Use existing PMM_SOAK_GRID_JSON (default config/pmm-soak-wallet-grid.json).
|
||||
#
|
||||
# Env:
|
||||
# PMM_SOAK_GRID_MNEMONIC_FILE — default ~/.secure-secrets/chain138-pmm-soak-grid.mnemonic
|
||||
# PMM_SOAK_GRID_JSON — output path (default: $PROJECT_ROOT/config/pmm-soak-wallet-grid.json)
|
||||
# NATIVE_AMOUNT_WEI — default 20000000000000000 (0.02 native per wallet)
|
||||
# FUND_TOKEN / AMOUNT_WEI_PER_WALLET — ERC-20 tranche (defaults: cUSDT, 50000000 = 50 USDT face)
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
# shellcheck source=/dev/null
|
||||
source "${PROJECT_ROOT}/scripts/lib/pmm-soak-dotenv-override.sh"
|
||||
pmm_soak_snapshot_pool_env_for_restore
|
||||
# shellcheck source=/dev/null
|
||||
[[ -f "${PROJECT_ROOT}/scripts/lib/load-project-env.sh" ]] && source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh"
|
||||
pmm_soak_restore_pool_env_after_dotenv
|
||||
if [[ -n "${PMM_SOAK_RPC_URL_OVERRIDE:-}" ]]; then
|
||||
export RPC_URL_138="$PMM_SOAK_RPC_URL_OVERRIDE"
|
||||
export CHAIN138_RPC_URL="$RPC_URL_138"
|
||||
export CHAIN138_RPC="$RPC_URL_138"
|
||||
export ETH_RPC_URL="$RPC_URL_138"
|
||||
fi
|
||||
|
||||
INIT_MN=0
|
||||
APPLY_FUND=0
|
||||
SKIP_EXPORT=0
|
||||
TO_LINEAR=19
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--init-mnemonic) INIT_MN=1 ;;
|
||||
--apply-funds) APPLY_FUND=1 ;;
|
||||
--skip-export) SKIP_EXPORT=1 ;;
|
||||
--to-linear)
|
||||
TO_LINEAR="$2"
|
||||
shift
|
||||
;;
|
||||
-h | --help)
|
||||
sed -n '2,19p' "$0"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "[bootstrap] unknown arg: $1" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
SECRETS_DIR="${HOME}/.secure-secrets"
|
||||
MN_FILE="${PMM_SOAK_GRID_MNEMONIC_FILE:-${SECRETS_DIR}/chain138-pmm-soak-grid.mnemonic}"
|
||||
OUT_JSON="${PMM_SOAK_GRID_JSON:-${PROJECT_ROOT}/config/pmm-soak-wallet-grid.json}"
|
||||
NATIVE_AMT="${NATIVE_AMOUNT_WEI:-20000000000000000}"
|
||||
FUND_TOKEN="${FUND_TOKEN:-0x93E66202A11B1772E55407B32B44e5Cd8eda7f22}"
|
||||
ERC20_AMT="${AMOUNT_WEI_PER_WALLET:-50000000}"
|
||||
|
||||
require_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || {
|
||||
echo "[bootstrap] missing: $1" >&2
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
require_cmd cast
|
||||
require_cmd python3
|
||||
|
||||
mkdir -p "$SECRETS_DIR"
|
||||
|
||||
if [[ ! -f "$MN_FILE" ]]; then
|
||||
if [[ "$INIT_MN" -eq 1 ]] || [[ "${PMM_SOAK_AUTO_INIT_GRID_MNEMONIC:-}" == "1" ]]; then
|
||||
echo "[bootstrap] creating grid mnemonic at $MN_FILE (chmod 600)"
|
||||
cast wallet new-mnemonic 2>&1 | awk 'f{print; exit} /^Phrase:/{f=1}' | tr -d '\r\n' >"$MN_FILE"
|
||||
chmod 600 "$MN_FILE"
|
||||
echo "[bootstrap] BACK UP this file; it controls all 6,534 grid addresses."
|
||||
else
|
||||
echo "[bootstrap] No mnemonic file at $MN_FILE" >&2
|
||||
echo " Option A: PMM_SOAK_GRID_MNEMONIC='twelve words...' $0" >&2
|
||||
echo " Option B: $0 --init-mnemonic (creates file; then re-run with export/funds)" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -n "${PMM_SOAK_GRID_MNEMONIC:-}" ]]; then
|
||||
export PMM_SOAK_GRID_MNEMONIC
|
||||
elif [[ -f "$MN_FILE" ]]; then
|
||||
PMM_SOAK_GRID_MNEMONIC="$(tr -d '\r\n' <"$MN_FILE")"
|
||||
export PMM_SOAK_GRID_MNEMONIC
|
||||
else
|
||||
echo "[bootstrap] internal error: no mnemonic" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$SKIP_EXPORT" -eq 0 ]]; then
|
||||
echo "[bootstrap] exporting 6,534 addresses to $OUT_JSON (parallel cast; may take a few minutes)..."
|
||||
python3 "${PROJECT_ROOT}/scripts/deployment/pmm-soak-export-wallet-grid.py" --out "$OUT_JSON" --jobs 8
|
||||
else
|
||||
echo "[bootstrap] skip export; using existing $OUT_JSON"
|
||||
[[ -f "$OUT_JSON" ]] || {
|
||||
echo "[bootstrap] missing $OUT_JSON" >&2
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
if [[ "$APPLY_FUND" -eq 1 ]]; then
|
||||
PK="${DEPLOYER_PRIVATE_KEY:-${PRIVATE_KEY:-}}"
|
||||
if [[ -z "$PK" ]]; then
|
||||
echo "[bootstrap] --apply-funds needs PRIVATE_KEY / DEPLOYER_PRIVATE_KEY" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "[bootstrap] funding linear 0..$TO_LINEAR native=$NATIVE_AMT wei"
|
||||
PMM_SOAK_GRID_JSON="$OUT_JSON" NATIVE_AMOUNT_WEI="$NATIVE_AMT" \
|
||||
bash --noprofile --norc "${PROJECT_ROOT}/scripts/deployment/pmm-soak-operator-fund-grid.sh" --native --apply --from-linear 0 --to-linear "$TO_LINEAR"
|
||||
echo "[bootstrap] funding same range ERC-20 token=$FUND_TOKEN amount=$ERC20_AMT"
|
||||
PMM_SOAK_GRID_JSON="$OUT_JSON" TOKEN="$FUND_TOKEN" AMOUNT_WEI_PER_WALLET="$ERC20_AMT" \
|
||||
bash --noprofile --norc "${PROJECT_ROOT}/scripts/deployment/pmm-soak-operator-fund-grid.sh" --apply --from-linear 0 --to-linear "$TO_LINEAR"
|
||||
fi
|
||||
|
||||
echo "[bootstrap] done. Grid JSON: $OUT_JSON Mnemonic file: $MN_FILE"
|
||||
echo "[bootstrap] Next: export PMM_SOAK_GRID_MNEMONIC from $MN_FILE, set PMM_SOAK_GRID_JSON=$OUT_JSON, run chain138-pmm-soak-grid-bot.sh --dry-run then --apply (e.g. --pool-preset stable or cusdt-cusdc; default swap path is pool - see docs/11-references/CHAIN138_GRID_6534_WALLET_FUNDING_PLAN.md)."
|
||||
208
scripts/lib/pmm-soak-chain138-tick.sh
Executable file
208
scripts/lib/pmm-soak-chain138-tick.sh
Executable file
@@ -0,0 +1,208 @@
|
||||
#!/usr/bin/env bash
|
||||
# Chain 138 PMM soak — one tick (quote + optional approve/swap). Source after setting:
|
||||
# POOLS (array), RPC, INTEGRATION, SLIP_BPS, GAS_WEI, GOLD_USD, USD_MIN, USD_MAX
|
||||
# Optional: PMM_SOAK_LOG_TAG (default pmm-soak)
|
||||
#
|
||||
# Optional: CHAIN138_PMM_SOAK_GAS_LIMIT — when set, passed as --gas-limit to approve/swap cast send (helps Besu estimation).
|
||||
# Optional: CHAIN138_PMM_SOAK_SWAP_VIA — pool (default) | integration
|
||||
# On Chain 138, DODOPMMIntegration.swapExactIn reverts inside the pool when msg.sender is the integration contract;
|
||||
# EOA transfer(token, pool, amt) + pool.sellBase/sellQuote(trader) succeeds. Default pool path matches that.
|
||||
# Requires: cast, bc, python3 (pick_random_amount)
|
||||
# shellcheck shell=bash
|
||||
|
||||
PMM_SOAK_CXAUC_LC="${PMM_SOAK_CXAUC_LC:-0x290e52a8819a4fbd0714e517225429aa2b70ec6b}"
|
||||
PMM_SOAK_CXAUT_LC="${PMM_SOAK_CXAUT_LC:-0x94e408e26c6fd8f4ee00b54df19082fda07dc96e}"
|
||||
|
||||
pmm_soak_to_lower() {
|
||||
printf '%s' "$1" | tr '[:upper:]' '[:lower:]'
|
||||
}
|
||||
|
||||
pmm_soak_log() {
|
||||
echo "[${PMM_SOAK_LOG_TAG:-pmm-soak} $(date -Iseconds)] $*"
|
||||
}
|
||||
|
||||
pmm_soak_pick_random_amount() {
|
||||
local token_lc="$1"
|
||||
local decimals="$2"
|
||||
PMM_SOAK_XAU_ADDRS="${PMM_SOAK_CXAUC_LC},${PMM_SOAK_CXAUT_LC}" \
|
||||
GOLD_USD="$GOLD_USD" USD_MIN="$USD_MIN" USD_MAX="$USD_MAX" \
|
||||
python3 - "$token_lc" "$decimals" <<'PY'
|
||||
import os, random, sys
|
||||
tok = sys.argv[1].lower()
|
||||
d = int(sys.argv[2])
|
||||
usd_min = int(os.environ["USD_MIN"])
|
||||
usd_max = int(os.environ["USD_MAX"])
|
||||
gold = float(os.environ["GOLD_USD"])
|
||||
scale = 10 ** d
|
||||
xau = {a.strip().lower() for a in os.environ["PMM_SOAK_XAU_ADDRS"].split(",") if a.strip()}
|
||||
|
||||
if tok in xau:
|
||||
usd = random.randint(usd_min, usd_max)
|
||||
oz = usd / gold
|
||||
raw = int(oz * scale)
|
||||
print(max(raw, 1))
|
||||
else:
|
||||
u = random.randint(usd_min, usd_max)
|
||||
print(u * scale)
|
||||
PY
|
||||
}
|
||||
|
||||
# One loop iteration: random pool, quote as trader, swap with signer_pk when apply=1.
|
||||
# Globals: POOLS RPC INTEGRATION SLIP_BPS GAS_WEI
|
||||
pmm_soak_chain138_run_tick_iteration() {
|
||||
local tick="$1"
|
||||
local trader="$2"
|
||||
local signer_pk="$3"
|
||||
local apply="$4"
|
||||
|
||||
# POOLS[] is set by the caller (pmm-soak-pools.sh); not the local POOL below.
|
||||
# shellcheck disable=SC2153
|
||||
local idx=$((RANDOM % ${#POOLS[@]}))
|
||||
local POOL base_out quote_out base quote base_lc quote_lc token_in token_in_lc token_out
|
||||
local dec_out dec bal_out bal amt qraw quoted min_out
|
||||
local swap_via="${CHAIN138_PMM_SOAK_SWAP_VIA:-pool}"
|
||||
POOL="${POOLS[$idx]}"
|
||||
|
||||
if ! base_out="$(cast call "$POOL" '_BASE_TOKEN_()(address)' --rpc-url "$RPC" 2>/dev/null)"; then
|
||||
pmm_soak_log "tick $tick skip pool=$POOL (base token read failed)"
|
||||
return 0
|
||||
fi
|
||||
if ! quote_out="$(cast call "$POOL" '_QUOTE_TOKEN_()(address)' --rpc-url "$RPC" 2>/dev/null)"; then
|
||||
pmm_soak_log "tick $tick skip pool=$POOL (quote token read failed)"
|
||||
return 0
|
||||
fi
|
||||
base="$(printf '%s\n' "$base_out" | awk '{print $1}')"
|
||||
quote="$(printf '%s\n' "$quote_out" | awk '{print $1}')"
|
||||
base_lc="$(pmm_soak_to_lower "$base")"
|
||||
quote_lc="$(pmm_soak_to_lower "$quote")"
|
||||
|
||||
if (( RANDOM % 2 == 0 )); then
|
||||
token_in="$base"
|
||||
token_in_lc="$base_lc"
|
||||
token_out="$quote"
|
||||
else
|
||||
token_in="$quote"
|
||||
token_in_lc="$quote_lc"
|
||||
token_out="$base"
|
||||
fi
|
||||
|
||||
if ! dec_out="$(cast call "$token_in" 'decimals()(uint8)' --rpc-url "$RPC" 2>/dev/null)"; then
|
||||
pmm_soak_log "tick $tick skip pool=$POOL (decimals failed)"
|
||||
return 0
|
||||
fi
|
||||
dec="$(printf '%s\n' "$dec_out" | awk '{print $1}')"
|
||||
if ! bal_out="$(cast call "$token_in" 'balanceOf(address)(uint256)' "$trader" --rpc-url "$RPC" 2>/dev/null)"; then
|
||||
pmm_soak_log "tick $tick skip pool=$POOL (balance read failed)"
|
||||
return 0
|
||||
fi
|
||||
bal="$(printf '%s\n' "$bal_out" | awk '{print $1}')"
|
||||
|
||||
amt="$(pmm_soak_pick_random_amount "$token_in_lc" "$dec")"
|
||||
if [[ -z "$amt" || "$amt" == "0" ]]; then
|
||||
pmm_soak_log "tick $tick skip pool=$POOL (zero amount)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if (( $(echo "$bal < $amt" | bc -l) )); then
|
||||
if (( $(echo "$bal == 0" | bc -l) )); then
|
||||
pmm_soak_log "tick $tick skip pool=$POOL token_in=$token_in zero balance"
|
||||
return 0
|
||||
fi
|
||||
amt=$((bal * 9 / 10))
|
||||
pmm_soak_log "tick $tick clamp amount to 90% balance -> $amt"
|
||||
fi
|
||||
|
||||
if [[ "$token_in_lc" == "$base_lc" ]]; then
|
||||
if ! qraw="$(cast call "$POOL" 'querySellBase(address,uint256)(uint256,uint256)' "$trader" "$amt" --rpc-url "$RPC" 2>/dev/null)"; then
|
||||
pmm_soak_log "tick $tick skip pool=$POOL querySellBase reverted amt=$amt"
|
||||
return 0
|
||||
fi
|
||||
else
|
||||
if ! qraw="$(cast call "$POOL" 'querySellQuote(address,uint256)(uint256,uint256)' "$trader" "$amt" --rpc-url "$RPC" 2>/dev/null)"; then
|
||||
pmm_soak_log "tick $tick skip pool=$POOL querySellQuote reverted amt=$amt"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
quoted="$(printf '%s\n' "$qraw" | head -1 | awk '{print $1}')"
|
||||
|
||||
if [[ -z "$quoted" || "$quoted" == "0" ]]; then
|
||||
pmm_soak_log "tick $tick skip pool=$POOL token_in=$token_in amt=$amt (no quote)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
min_out="$(echo "scale=0; (${quoted} * (10000 - ${SLIP_BPS})) / 10000" | bc)"
|
||||
|
||||
pmm_soak_log "tick $tick trader=$trader pool=$POOL token_in=$token_in amt=$amt quoted_out=$quoted min_out=$min_out"
|
||||
|
||||
if [[ "$apply" -eq 1 ]]; then
|
||||
if [[ -z "$signer_pk" ]]; then
|
||||
pmm_soak_log "WARN: apply=1 but empty signer_pk; skip swap"
|
||||
return 0
|
||||
fi
|
||||
local _gas_t _gas_s _out_bal_before _out_bal_after _received
|
||||
_gas_t=()
|
||||
_gas_s=()
|
||||
[[ -n "${CHAIN138_PMM_SOAK_GAS_LIMIT:-}" ]] && _gas_t=(--gas-limit "${CHAIN138_PMM_SOAK_GAS_LIMIT}")
|
||||
[[ -n "${CHAIN138_PMM_SOAK_GAS_LIMIT:-}" ]] && _gas_s=(--gas-limit "${CHAIN138_PMM_SOAK_GAS_LIMIT}")
|
||||
|
||||
if [[ "$swap_via" == "integration" ]]; then
|
||||
local allowance al_out can_swap
|
||||
if ! al_out="$(cast call "$token_in" 'allowance(address,address)(uint256)' "$trader" "$INTEGRATION" --rpc-url "$RPC" 2>/dev/null)"; then
|
||||
pmm_soak_log "WARN: allowance read failed; skip swap"
|
||||
else
|
||||
allowance="$(printf '%s\n' "$al_out" | awk '{print $1}')"
|
||||
can_swap=1
|
||||
if (( $(echo "$allowance < $amt" | bc -l) )); then
|
||||
pmm_soak_log "approve $token_in -> integration amount=$amt"
|
||||
if ! cast send "$token_in" 'approve(address,uint256)(bool)' "$INTEGRATION" "$amt" \
|
||||
--rpc-url "$RPC" --private-key "$signer_pk" --legacy --gas-price "$GAS_WEI" "${_gas_t[@]}" >/dev/null; then
|
||||
pmm_soak_log "WARN: approve failed; skip swap"
|
||||
can_swap=0
|
||||
fi
|
||||
fi
|
||||
if [[ "$can_swap" -eq 1 ]]; then
|
||||
if ! cast send "$INTEGRATION" \
|
||||
'swapExactIn(address,address,uint256,uint256)(uint256)' \
|
||||
"$POOL" "$token_in" "$amt" "$min_out" \
|
||||
--rpc-url "$RPC" --private-key "$signer_pk" --legacy --gas-price "$GAS_WEI" "${_gas_s[@]}"; then
|
||||
pmm_soak_log "WARN: swap failed pool=$POOL (continuing)"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# Direct pool: transfer in then sellBase / sellQuote (EOA msg.sender; avoids integration+pool revert on this chain).
|
||||
if ! _out_bal_before="$(cast call "$token_out" 'balanceOf(address)(uint256)' "$trader" --rpc-url "$RPC" 2>/dev/null | awk '{print $1}')"; then
|
||||
pmm_soak_log "WARN: token_out balance read failed; skip swap"
|
||||
else
|
||||
pmm_soak_log "swap_via=pool transfer token_in -> pool amt=$amt"
|
||||
if ! cast send "$token_in" 'transfer(address,uint256)(bool)' "$POOL" "$amt" \
|
||||
--rpc-url "$RPC" --private-key "$signer_pk" --legacy --gas-price "$GAS_WEI" "${_gas_t[@]}" >/dev/null; then
|
||||
pmm_soak_log "WARN: transfer to pool failed pool=$POOL (continuing)"
|
||||
else
|
||||
if [[ "$token_in_lc" == "$base_lc" ]]; then
|
||||
if ! cast send "$POOL" 'sellBase(address)(uint256)' "$trader" \
|
||||
--rpc-url "$RPC" --private-key "$signer_pk" --legacy --gas-price "$GAS_WEI" "${_gas_s[@]}" >/dev/null; then
|
||||
pmm_soak_log "WARN: sellBase failed pool=$POOL (continuing)"
|
||||
fi
|
||||
else
|
||||
if ! cast send "$POOL" 'sellQuote(address)(uint256)' "$trader" \
|
||||
--rpc-url "$RPC" --private-key "$signer_pk" --legacy --gas-price "$GAS_WEI" "${_gas_s[@]}" >/dev/null; then
|
||||
pmm_soak_log "WARN: sellQuote failed pool=$POOL (continuing)"
|
||||
fi
|
||||
fi
|
||||
if ! _out_bal_after="$(cast call "$token_out" 'balanceOf(address)(uint256)' "$trader" --rpc-url "$RPC" 2>/dev/null | awk '{print $1}')"; then
|
||||
pmm_soak_log "WARN: token_out balance re-read failed after swap"
|
||||
else
|
||||
_received="$(echo "${_out_bal_after} - ${_out_bal_before}" | bc)"
|
||||
if (( $(echo "${_received} < ${min_out}" | bc -l) )); then
|
||||
pmm_soak_log "WARN: output ${_received} < min_out ${min_out} (slippage / partial fill)"
|
||||
else
|
||||
pmm_soak_log "swap_via=pool ok received_out=${_received}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
Reference in New Issue
Block a user