PMM soak grid: fund-grid progress/ERR trap, complete-grid START_LEG and timing, tranche RPC override, grid funding doc
- pmm-soak-operator-fund-grid: PMM_SOAK_FUND_PROGRESS_EVERY, ERR trap, help text comments only - pmm-soak-complete-grid-funding-operator: PMM_SOAK_START_LEG resume, per-leg and total wall time - pmm-soak-operator-fund-full-grid-tranches: PMM_SOAK_RPC_URL_OVERRIDE, bash --noprofile --norc, manual hint - pmm-soak-mint-mirror-usdc-deployer-shortfall: ASCII-only operator messages - CHAIN138_GRID_6534_WALLET_FUNDING_PLAN: full-grid orchestrator, env vars, log markers Made-with: Cursor
This commit is contained in:
158
docs/11-references/CHAIN138_GRID_6534_WALLET_FUNDING_PLAN.md
Normal file
158
docs/11-references/CHAIN138_GRID_6534_WALLET_FUNDING_PLAN.md
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
# Chain 138 — Funding plan for 33×33×6 (6,534) PMM soak grid wallets
|
||||||
|
|
||||||
|
**Purpose:** Separate the **operator (deployer)** role from the **6,534 grid EOAs**, summarize how to fund native gas and ERC-20 inventory for soak activity, and give **order-of-magnitude budgets** with formulas.
|
||||||
|
**Companion:** [DEPLOYER_WALLET_FUNDING_PLAN_PMM_POOLS.md](DEPLOYER_WALLET_FUNDING_PLAN_PMM_POOLS.md) (deployer liquidity / reserve split).
|
||||||
|
**Automation:** `scripts/deployment/pmm-soak-operator-fund-grid.sh` (`--native` or ERC-20), `scripts/deployment/pmm-soak-export-wallet-grid.py`, `scripts/deployment/chain138-pmm-soak-grid-bot.sh`, smoke `scripts/deployment/pmm-soak-grid-smoke-check.sh`, **one-shot** `scripts/deployment/pmm-soak-complete-operator-bootstrap.sh` (creates `~/.secure-secrets/chain138-pmm-soak-grid.mnemonic` when `PMM_SOAK_AUTO_INIT_GRID_MNEMONIC=1`, exports 6,534 addresses to `config/pmm-soak-wallet-grid.json`, optional `--apply-funds --to-linear N`), **full-grid resume** `scripts/deployment/pmm-soak-complete-grid-funding-operator.sh` (waits chain + deployer nonce, mirror-USDC mint shortfall, native + four ERC-20 legs in chunks; env `PMM_SOAK_START_LEG`, `PMM_SOAK_RESUME_NATIVE_FROM_LINEAR`, `PMM_SOAK_RPC_URL_OVERRIDE`), and **`scripts/deployment/pmm-soak-operator-fund-full-grid-tranches.sh`** (same legs as tranche loops; same RPC override pattern). **CI:** `.github/workflows/pmm-soak-grid-smoke.yml` runs the smoke script on `CI=true` with public read-only RPC when `RPC_URL_138` is unset.
|
||||||
|
**Pool narrowing:** `scripts/lib/pmm-soak-pools.sh` (`PMM_SOAK_POOL_PRESET`, `PMM_SOAK_POOLS_FILE`).
|
||||||
|
**Swap execution:** `scripts/lib/pmm-soak-chain138-tick.sh` defaults to **`CHAIN138_PMM_SOAK_SWAP_VIA=pool`** (EOA `transfer` into the DVM + `sellBase` / `sellQuote`). On this chain, `DODOPMMIntegration.swapExactIn` reverts inside the pool when the integration contract is `msg.sender`; set `CHAIN138_PMM_SOAK_SWAP_VIA=integration` only if you have confirmed that path on your RPC.
|
||||||
|
**Dotenv vs shell:** Root `.env` is loaded inside soak scripts; `scripts/lib/pmm-soak-dotenv-override.sh` restores **`PMM_SOAK_POOL_PRESET`**, **`PMM_SOAK_POOLS`**, **`PMM_SOAK_POOLS_FILE`**, **`CHAIN138_PMM_SOAK_SWAP_VIA`**, and **`RPC_URL_138`** (plus `CHAIN138_RPC_URL` / `CHAIN138_RPC` after restore) from the parent shell when set before launch — used by `chain138-pmm-soak-grid-bot.sh`, `chain138-pmm-random-soak-swaps.sh`, `pmm-soak-operator-fund-grid.sh`, `pmm-soak-complete-grid-funding-operator.sh`, `pmm-soak-operator-fund-full-grid-tranches.sh`, and `pmm-soak-complete-operator-bootstrap.sh`. Alternatively pass **`--pool-preset <name>`** or **`--swap-via pool|integration`** on the bot CLI (CLI wins over dotenv for preset and clears `PMM_SOAK_POOLS*` so the preset applies).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Two different key systems (do not confuse them)
|
||||||
|
|
||||||
|
| Role | Keys | Address source | Typical use |
|
||||||
|
|------|------|----------------|-------------|
|
||||||
|
| **Operator / deployer** | `PRIVATE_KEY` / `DEPLOYER_PRIVATE_KEY` in `.env` | Single EOA | Funds grid wallets (native + ERC-20), operations, liquidity (see deployer funding plan doc) |
|
||||||
|
| **Grid (6,534 wallets)** | **`PMM_SOAK_GRID_MNEMONIC`** (BIP39), separate from deployer | HD path `m/44'/60'/0'/0/{linearIndex}` with `linearIndex = lpbca×198 + branch×6 + class` | Sign PMM swaps (and optional inter-wallet transfers) in the soak bot |
|
||||||
|
|
||||||
|
- The **deployer** is **not** derived from the grid mnemonic unless you intentionally use the same seed (not recommended).
|
||||||
|
- Export **public** addresses only: `PMM_SOAK_GRID_MNEMONIC='…' python3 scripts/deployment/pmm-soak-export-wallet-grid.py --out config/pmm-soak-wallet-grid.json` — keep that JSON **local** (gitignored pattern in `.gitignore`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Deployer (operator) — review and snapshot
|
||||||
|
|
||||||
|
**Canonical address:** `0x4A666F96fC8764181194447A7dFdb7d471b301C8`
|
||||||
|
**Explorer:** https://explorer.d-bis.org/address/0x4A666F96fC8764181194447A7dFdb7d471b301C8
|
||||||
|
|
||||||
|
**Point-in-time read (LAN Core RPC `http://192.168.11.211:8545`, 2026-04-10):**
|
||||||
|
|
||||||
|
| Asset | Raw (integer) | Human (approx.) |
|
||||||
|
|-------|-----------------|-----------------|
|
||||||
|
| Native | `989399835388702020921911788` wei | ~989,400 ETH nominal units (18 decimals) — private chain genesis style |
|
||||||
|
| cUSDT `0x93E66202A11B1772E55407B32B44e5Cd8eda7f22` | `688280049090000` | ~688.28M units (6 decimals) |
|
||||||
|
| cUSDC `0xf22258f57794CC8E06237084b353Ab30fFfa640b` | `689514099298585` | ~689.51M units (6 decimals) |
|
||||||
|
|
||||||
|
Re-check before funding:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
source scripts/lib/load-project-env.sh
|
||||||
|
D=0x4A666F96fC8764181194447A7dFdb7d471b301C8
|
||||||
|
cast balance "$D" --rpc-url "${RPC_URL_138:-http://192.168.11.211:8545}"
|
||||||
|
cast call 0x93E66202A11B1772E55407B32B44e5Cd8eda7f22 'balanceOf(address)(uint256)' "$D" --rpc-url "$RPC_URL_138"
|
||||||
|
cast call 0xf22258f57794CC8E06237084b353Ab30fFfa640b 'balanceOf(address)(uint256)' "$D" --rpc-url "$RPC_URL_138"
|
||||||
|
```
|
||||||
|
|
||||||
|
The deployer holds **large** stable inventory relative to typical per-wallet soak seeds; still treat **grid funding** as a **budgeted** draw (tranches), not an implicit unlimited tap.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Grid wallets (6,534) — what each needs
|
||||||
|
|
||||||
|
### 3.1 Native (gas)
|
||||||
|
|
||||||
|
Grid wallets must pay **legacy** gas for:
|
||||||
|
|
||||||
|
- `approve` (when allowance < swap amount) on the sold token
|
||||||
|
- `DODOPMMIntegration.swapExactIn`
|
||||||
|
- Optional `ERC20.transfer` if you enable inter-wallet flow (`PMM_SOAK_TRANSFER_*`)
|
||||||
|
|
||||||
|
On Chain 138, `CHAIN138_DEPLOY_GAS_PRICE_WEI` is often **1000 wei** per gas unit (see deployment scripts). Cost per swap is **small in wei terms**, but **6,534 wallets × many swaps** adds up if native per wallet is set too high.
|
||||||
|
|
||||||
|
**Suggested starting native per wallet (order of magnitude):**
|
||||||
|
|
||||||
|
| Scenario | `NATIVE_AMOUNT_WEI` (per wallet) | Notes |
|
||||||
|
|----------|----------------------------------|--------|
|
||||||
|
| Smoke (few ticks) | `5e15` – `2e16` wei (0.005 – 0.02 ETH units) | Enough for multiple approve+swap paths at low gas price |
|
||||||
|
| Sustained soak | `2e16` – `5e16` wei | Raise if you see OOG or heavy revert churn |
|
||||||
|
| **Do not** blindly max-fund all 6,534 without a tranche plan | — | Operator native spend + recipient inventory must stay bounded |
|
||||||
|
|
||||||
|
**Operator overhead (native):** Each funding tx is a native transfer from the deployer; budget **deployer native** for:
|
||||||
|
|
||||||
|
- **Sum to recipients:** `6,534 × NATIVE_AMOUNT_WEI`
|
||||||
|
- **Funding transaction gas:** roughly `21_000 × gasPrice × 6,534` (plus buffer for retries). With `gasPrice = 1000` wei, this term is on the order of **1.4×10^11 wei** total — negligible next to recipient amounts unless `NATIVE_AMOUNT_WEI` is tiny.
|
||||||
|
|
||||||
|
Use **slices** to limit blast radius:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PMM_SOAK_GRID_JSON=config/pmm-soak-wallet-grid.json NATIVE_AMOUNT_WEI=20000000000000000 \
|
||||||
|
bash scripts/deployment/pmm-soak-operator-fund-grid.sh --native --from-linear 0 --to-linear 199
|
||||||
|
# dry-run first; then --apply
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 ERC-20 (swap inventory)
|
||||||
|
|
||||||
|
Soak sizes default to **random USD face** between `PMM_SOAK_USD_MIN` / `PMM_SOAK_USD_MAX` (default 1,000–100,000 USD) expressed as **6-decimal** units for stables (`amount ≈ USD × 10^6`). A wallet must hold **at least** the token it sells each tick (often **cUSDT** or **cUSDC** on stable presets), plus gas.
|
||||||
|
|
||||||
|
**Pool preset drives which tokens matter** (`PMM_SOAK_POOL_PRESET`):
|
||||||
|
|
||||||
|
| Preset | Pools (count) | Primary inventory to fund |
|
||||||
|
|--------|----------------|---------------------------|
|
||||||
|
| `cusdt-cusdc` | 1 | cUSDT and/or cUSDC (both sides of pool) |
|
||||||
|
| `stable` / `stable-mirrors` | 3 | cUSDT, cUSDC, mirror **USDT** / **USDC** as needed for sell side |
|
||||||
|
| `xau-*` | XAU pairs | cUSDT/cUSDC/cEURT + cXAUC/cXAUT per pool (see [ADDRESS_MATRIX_AND_STATUS](ADDRESS_MATRIX_AND_STATUS.md)) |
|
||||||
|
|
||||||
|
**Conservative per-wallet ERC-20 seed (example):**
|
||||||
|
`AMOUNT_WEI_PER_WALLET=500000000` (**500 USDT** face at 6 decimals: `500 × 10^6`) for **stable-only** testing — increase only after observing quote success rates.
|
||||||
|
|
||||||
|
**Total ERC-20 to grid (single token, uniform):**
|
||||||
|
`6,534 × AMOUNT_WEI_PER_WALLET` raw — must be **≤ deployer balance** of that token (minus reserves for other ops). Example: 500 USDT per wallet → **~3.27M USDT** face total if all 6,534 wallets are funded equally.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Automated smoke check (no secrets on disk)
|
||||||
|
|
||||||
|
From repo root (uses a **public test mnemonic** and **dry-run only**; removes temp JSON after):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/deployment/pmm-soak-grid-smoke-check.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Override: `PMM_SOAK_GRID_SMOKE_MNEMONIC='twelve words…'` (still dry-run). For a **partial export** of real addresses:
|
||||||
|
`PMM_SOAK_GRID_MNEMONIC='…' python3 scripts/deployment/pmm-soak-export-wallet-grid.py --out config/pmm-soak-wallet-grid.json --count 100`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Recommended phased funding (6,534 wallets)
|
||||||
|
|
||||||
|
1. **Export addresses** to `config/pmm-soak-wallet-grid.json` (local only).
|
||||||
|
2. **Narrow pools:** `PMM_SOAK_POOL_PRESET=stable` or `cusdt-cusdc` until healthy quotes.
|
||||||
|
3. **Phase A — native:** Fund **linear ranges** in batches (e.g. 0–199, 200–399, …); dry-run then `--apply`.
|
||||||
|
4. **Phase B — ERC-20:** Same batching; start with **one** token (e.g. cUSDT) aligned with your preset’s sell-side testing.
|
||||||
|
5. **Phase C — bot:** `chain138-pmm-soak-grid-bot.sh --dry-run`, then `--apply` with `PMM_SOAK_LINEAR_MIN` / `MAX` restricted before full 0–6533.
|
||||||
|
6. **Monitor:** deployer native + cUSDT/cUSDC balances; grid wallet balances via explorer or scripted `cast balance` / `balanceOf` samples.
|
||||||
|
7. **Full-grid resume (optional):** `bash scripts/deployment/pmm-soak-complete-grid-funding-operator.sh --dry-run` then `--apply`. For long runs from a host where LAN Core RPC may flap, set `PMM_SOAK_RPC_URL_OVERRIDE=https://rpc-http-pub.d-bis.org` (or another stable endpoint). To skip native when every wallet is already funded, set `PMM_SOAK_RESUME_NATIVE_FROM_LINEAR=6534` (above max linear `6533`). To resume after a partial leg, set `PMM_SOAK_START_LEG` to one of `native`, `mint`, `cusdt`, `cusdc`, `mirr_usdt`, `mirr_usdc` — earlier legs are skipped; you must already satisfy deployer balances and on-chain state for those legs. Chunk progress and ETA during apply: `PMM_SOAK_FUND_PROGRESS_EVERY` on `pmm-soak-operator-fund-grid.sh` (default `50`, use `0` for quiet except the last line per chunk). Example background log: `nohup env PMM_SOAK_RPC_URL_OVERRIDE=… bash scripts/deployment/pmm-soak-complete-grid-funding-operator.sh --apply >> /tmp/pmm-soak-complete-grid-lan.log 2>&1 &` — completion lines: `[complete] total apply wall_s=… (after waits)` then `[complete] all legs finished (apply=1)`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Budget table (illustrative totals)
|
||||||
|
|
||||||
|
Let `N = 6,534`, `g = NATIVE_AMOUNT_WEI`, `a = AMOUNT_WEI_PER_WALLET` (one token).
|
||||||
|
|
||||||
|
| Item | Formula |
|
||||||
|
|------|---------|
|
||||||
|
| Native to grid | `N × g` |
|
||||||
|
| One-token ERC-20 to grid | `N × a` |
|
||||||
|
| Deployer funding txs gas (native, order of mag.) | `≈ N × 21_000 × gasPrice` |
|
||||||
|
|
||||||
|
Example: `g = 2e16` wei (0.02 ETH per wallet) → native to grid ≈ `6,534 × 0.02 ≈ 131` ETH nominal (plus deployer gas for funding txs).
|
||||||
|
Example: `a = 500_000_000` raw (**500 USDT** face per wallet) → **~3.27×10^12** raw units total for that token if every wallet gets the same `a`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. References
|
||||||
|
|
||||||
|
| Doc / script | Use |
|
||||||
|
|--------------|-----|
|
||||||
|
| [DEPLOYER_WALLET_FUNDING_PLAN_PMM_POOLS.md](DEPLOYER_WALLET_FUNDING_PLAN_PMM_POOLS.md) | Deployer liquidity / 50% rule for pools |
|
||||||
|
| [ADDRESS_MATRIX_AND_STATUS.md](ADDRESS_MATRIX_AND_STATUS.md) | PMM pool + token addresses |
|
||||||
|
| `scripts/deployment/pmm-soak-operator-fund-grid.sh` | Batch fund native or ERC-20 |
|
||||||
|
| `scripts/deployment/pmm-soak-complete-grid-funding-operator.sh` | One-shot resume: wait chain + nonce, mint mirror-USDC shortfall, native + four ERC-20 legs (`PMM_SOAK_START_LEG`, `PMM_SOAK_RESUME_NATIVE_FROM_LINEAR`, `PMM_SOAK_RPC_URL_OVERRIDE`) |
|
||||||
|
| `scripts/deployment/pmm-soak-operator-fund-full-grid-tranches.sh` | Same funding legs as explicit tranche loops (RPC override + `bash --noprofile --norc` into fund-grid) |
|
||||||
|
| `scripts/lib/pmm-soak-pools.sh` | Narrow pool sets |
|
||||||
|
| `scripts/deployment/chain138-pmm-soak-grid-bot.sh` | Grid soak runner |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Disclaimer:** Soak bots spend **real gas and tokens** on chain. Cap tranches, use dry-run, and align `PMM_SOAK_USD_*` with funded balances.
|
||||||
291
scripts/deployment/pmm-soak-complete-grid-funding-operator.sh
Executable file
291
scripts/deployment/pmm-soak-complete-grid-funding-operator.sh
Executable file
@@ -0,0 +1,291 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Finish PMM soak grid funding after stalls or partial runs: wait for blocks + mempool, optional
|
||||||
|
# owner-mint of mirror USDC shortfall, then fund native (resume) + cUSDT + cUSDC + mirror USDT + mirror USDC.
|
||||||
|
#
|
||||||
|
# Requires: cast, jq, python3, PRIVATE_KEY, RPC_URL_138 (via load-project-env)
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# bash scripts/deployment/pmm-soak-complete-grid-funding-operator.sh --dry-run
|
||||||
|
# bash scripts/deployment/pmm-soak-complete-grid-funding-operator.sh --apply
|
||||||
|
#
|
||||||
|
# Env:
|
||||||
|
# PMM_SOAK_GRID_JSON, PMM_SOAK_FUND_CHUNK (default 250), NATIVE_AMOUNT_WEI, seed RAW vars (same as tranche script)
|
||||||
|
# PMM_SOAK_RESUME_NATIVE_FROM_LINEAR — if set, first linear index to receive native (skip lower). If unset, auto-detect.
|
||||||
|
# PMM_SOAK_WAIT_BLOCK_SEC — max seconds to wait for eth_blockNumber to increase (default 86400)
|
||||||
|
# PMM_SOAK_WAIT_NONCE_CLEAR_SEC — max wait for deployer latest==pending nonce (default 7200)
|
||||||
|
# CAST_SEND_TIMEOUT_SEC / CAST_RPC_TIMEOUT_SEC — forwarded via fund-grid
|
||||||
|
# PMM_SOAK_RPC_URL_OVERRIDE — after dotenv load, force RPC_URL_138 (e.g. https://rpc-http-pub.d-bis.org for long runs)
|
||||||
|
# PMM_SOAK_START_LEG — optional resume: run from this leg onward only (native | mint | cusdt | cusdc | mirr_usdt | mirr_usdc).
|
||||||
|
# Skipped legs are not re-run; ensure deployer balances and mempool are already suitable (e.g. start at cusdt only after native + mint done).
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||||
|
cd "$PROJECT_ROOT"
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
GRID_JSON="${PMM_SOAK_GRID_JSON:-${PROJECT_ROOT}/config/pmm-soak-wallet-grid.json}"
|
||||||
|
CHUNK="${PMM_SOAK_FUND_CHUNK:-250}"
|
||||||
|
NATIVE_WEI="${NATIVE_AMOUNT_WEI:-20000000000000000}"
|
||||||
|
SEED_CUSDT="${PMM_SOAK_SEED_CUSDT_RAW:-100000000}"
|
||||||
|
SEED_CUSDC="${PMM_SOAK_SEED_CUSDC_RAW:-100000000}"
|
||||||
|
SEED_USDT="${PMM_SOAK_SEED_MIRROR_USDT_RAW:-100000000}"
|
||||||
|
SEED_USDC="${PMM_SOAK_SEED_MIRROR_USDC_RAW:-100000000}"
|
||||||
|
|
||||||
|
CUSDT=0x93E66202A11B1772E55407B32B44e5Cd8eda7f22
|
||||||
|
CUSDC=0xf22258f57794CC8E06237084b353Ab30fFfa640b
|
||||||
|
USDT_M=0x004b63A7B5b0E06f6bB6adb4a5F9f590BF3182D1
|
||||||
|
USDC_M=0x71D6687F38b93CCad569Fa6352c876eea967201b
|
||||||
|
|
||||||
|
RPC="${RPC_URL_138:-http://192.168.11.211:8545}"
|
||||||
|
D=0x4A666F96fC8764181194447A7dFdb7d471b301C8
|
||||||
|
MAX_LI=6533
|
||||||
|
WAIT_BLOCK="${PMM_SOAK_WAIT_BLOCK_SEC:-86400}"
|
||||||
|
WAIT_NONCE="${PMM_SOAK_WAIT_NONCE_CLEAR_SEC:-7200}"
|
||||||
|
|
||||||
|
APPLY=0
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--apply) APPLY=1 ;;
|
||||||
|
--dry-run) APPLY=0 ;;
|
||||||
|
-h | --help) sed -n '2,21p' "$0"; exit 0 ;;
|
||||||
|
*) echo "unknown: $1" >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ! -f "$GRID_JSON" ]]; then
|
||||||
|
echo "[complete] missing $GRID_JSON" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "${PMM_SOAK_START_LEG:-}" ]]; then
|
||||||
|
case "${PMM_SOAK_START_LEG}" in
|
||||||
|
native | mint | cusdt | cusdc | mirr_usdt | mirr_usdc) ;;
|
||||||
|
*)
|
||||||
|
echo "[complete] FATAL: PMM_SOAK_START_LEG must be one of: native mint cusdt cusdc mirr_usdt mirr_usdc (got: ${PMM_SOAK_START_LEG})" >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
_leg_idx() {
|
||||||
|
case "$1" in
|
||||||
|
native) echo 0 ;;
|
||||||
|
mint) echo 1 ;;
|
||||||
|
cusdt) echo 2 ;;
|
||||||
|
cusdc) echo 3 ;;
|
||||||
|
mirr_usdt) echo 4 ;;
|
||||||
|
mirr_usdc) echo 5 ;;
|
||||||
|
*) echo -1 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
_leg_should_run() {
|
||||||
|
local leg="$1"
|
||||||
|
local st="${PMM_SOAK_START_LEG:-}"
|
||||||
|
[[ -z "$st" ]] && return 0
|
||||||
|
local a b
|
||||||
|
a="$(_leg_idx "$leg")"
|
||||||
|
b="$(_leg_idx "$st")"
|
||||||
|
(( a >= b ))
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_chain_block_progress() {
|
||||||
|
echo "[complete] waiting for block number to advance (max ${WAIT_BLOCK}s) ..."
|
||||||
|
local first stall=0
|
||||||
|
first="$(cast block-number --rpc-url "$RPC")"
|
||||||
|
while true; do
|
||||||
|
local now
|
||||||
|
now="$(cast block-number --rpc-url "$RPC")"
|
||||||
|
if (( now > first )); then
|
||||||
|
echo "[complete] chain progressed blocks $first -> $now"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if (( stall >= WAIT_BLOCK )); then
|
||||||
|
echo "[complete] FATAL: no new blocks in ${WAIT_BLOCK}s (stuck at $first). Fix Chain 138 consensus / RPC, then re-run." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
sleep 5
|
||||||
|
stall=$((stall + 5))
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_deployer_nonce_mempool_clear() {
|
||||||
|
local start="$SECONDS"
|
||||||
|
while true; do
|
||||||
|
local nl np
|
||||||
|
nl="$(cast nonce "$D" --rpc-url "$RPC" -B latest)"
|
||||||
|
np="$(cast nonce "$D" --rpc-url "$RPC" -B pending)"
|
||||||
|
if [[ "$nl" == "$np" ]]; then
|
||||||
|
echo "[complete] deployer nonce clear (latest=pending=$nl)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if (( SECONDS - start > WAIT_NONCE )); then
|
||||||
|
echo "[complete] FATAL: deployer mempool stuck (latest=$nl pending=$np) after ${WAIT_NONCE}s" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "[complete] waiting deployer mempool latest=$nl pending=$np ..."
|
||||||
|
sleep 3
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
detect_native_resume_linear() {
|
||||||
|
local target="$NATIVE_WEI"
|
||||||
|
# 95% of target: allow tiny fee dust below nominal
|
||||||
|
local thresh
|
||||||
|
thresh="$(python3 -c "print(int(int('$target') * 95 // 100))")"
|
||||||
|
local li
|
||||||
|
for ((li = 0; li <= MAX_LI; li++)); do
|
||||||
|
local addr bal
|
||||||
|
addr="$(jq -r --argjson li "$li" '.wallets[] | select(.linearIndex==$li) | .address' "$GRID_JSON")"
|
||||||
|
bal="$(cast balance "$addr" --rpc-url "$RPC" | head -1 || echo 0)"
|
||||||
|
if (( bal < thresh )); then
|
||||||
|
echo "$li"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "$((MAX_LI + 1))"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_native_chunk() {
|
||||||
|
local from="$1" to="$2"
|
||||||
|
echo "[complete] === native $from..$to apply=$APPLY ==="
|
||||||
|
if [[ "$APPLY" -eq 1 ]]; then
|
||||||
|
PMM_SOAK_GRID_JSON="$GRID_JSON" NATIVE_AMOUNT_WEI="$NATIVE_WEI" \
|
||||||
|
bash --noprofile --norc "${PROJECT_ROOT}/scripts/deployment/pmm-soak-operator-fund-grid.sh" --apply --native --from-linear "$from" --to-linear "$to"
|
||||||
|
else
|
||||||
|
PMM_SOAK_GRID_JSON="$GRID_JSON" NATIVE_AMOUNT_WEI="$NATIVE_WEI" \
|
||||||
|
bash --noprofile --norc "${PROJECT_ROOT}/scripts/deployment/pmm-soak-operator-fund-grid.sh" --native --from-linear "$from" --to-linear "$to"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run_erc20_chunk() {
|
||||||
|
local from="$1" to="$2" tok="$3" amt="$4" label="$5"
|
||||||
|
echo "[complete] === $label $tok $from..$to apply=$APPLY ==="
|
||||||
|
if [[ "$APPLY" -eq 1 ]]; then
|
||||||
|
PMM_SOAK_GRID_JSON="$GRID_JSON" TOKEN="$tok" AMOUNT_WEI_PER_WALLET="$amt" \
|
||||||
|
bash --noprofile --norc "${PROJECT_ROOT}/scripts/deployment/pmm-soak-operator-fund-grid.sh" --apply --from-linear "$from" --to-linear "$to"
|
||||||
|
else
|
||||||
|
PMM_SOAK_GRID_JSON="$GRID_JSON" TOKEN="$tok" AMOUNT_WEI_PER_WALLET="$amt" \
|
||||||
|
bash --noprofile --norc "${PROJECT_ROOT}/scripts/deployment/pmm-soak-operator-fund-grid.sh" --from-linear "$from" --to-linear "$to"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "$APPLY" -eq 0 ]]; then
|
||||||
|
echo "[complete] dry-run: on --apply would: wait new block -> clear deployer mempool -> native from first under-funded linear (or PMM_SOAK_RESUME_NATIVE_FROM_LINEAR) -> mint mirror USDC shortfall -> cUSDT/cUSDC/mirror USDT/mirror USDC for 0..$MAX_LI in chunks of $CHUNK"
|
||||||
|
[[ -n "${PMM_SOAK_START_LEG:-}" ]] && echo "[complete] dry-run: PMM_SOAK_START_LEG=${PMM_SOAK_START_LEG} would skip earlier legs on --apply"
|
||||||
|
RESUME_LI="${PMM_SOAK_RESUME_NATIVE_FROM_LINEAR:-0}"
|
||||||
|
echo "[complete] dry-run sample native chunk from linear $RESUME_LI"
|
||||||
|
to=$((RESUME_LI + CHUNK - 1))
|
||||||
|
[[ "$to" -gt "$MAX_LI" ]] && to="$MAX_LI"
|
||||||
|
run_native_chunk "$RESUME_LI" "$to"
|
||||||
|
bash --noprofile --norc "${PROJECT_ROOT}/scripts/deployment/pmm-soak-mint-mirror-usdc-deployer-shortfall.sh" --dry-run
|
||||||
|
_dto=$((CHUNK - 1))
|
||||||
|
[[ "$_dto" -gt "$MAX_LI" ]] && _dto="$MAX_LI"
|
||||||
|
run_erc20_chunk 0 "$_dto" "$CUSDT" "$SEED_CUSDT" "cUSDT (sample chunk)"
|
||||||
|
echo "[complete] dry-run done (apply=0)"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
wait_chain_block_progress
|
||||||
|
wait_deployer_nonce_mempool_clear
|
||||||
|
|
||||||
|
_complete_apply_start="$SECONDS"
|
||||||
|
_phase_wall_start="$SECONDS"
|
||||||
|
if _leg_should_run native; then
|
||||||
|
RESUME_LI="${PMM_SOAK_RESUME_NATIVE_FROM_LINEAR:-}"
|
||||||
|
if [[ -z "$RESUME_LI" ]]; then
|
||||||
|
echo "[complete] auto-detecting first linear missing native (threshold 95% of $NATIVE_WEI wei) ..."
|
||||||
|
RESUME_LI="$(detect_native_resume_linear)"
|
||||||
|
echo "[complete] native resume linear index: $RESUME_LI"
|
||||||
|
else
|
||||||
|
echo "[complete] native resume linear from env: $RESUME_LI"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if (( RESUME_LI > MAX_LI )); then
|
||||||
|
echo "[complete] all wallets already at/above native threshold - skipping native legs"
|
||||||
|
else
|
||||||
|
for ((from = RESUME_LI; from <= MAX_LI; from += CHUNK)); do
|
||||||
|
to=$((from + CHUNK - 1))
|
||||||
|
[[ "$to" -gt "$MAX_LI" ]] && to="$MAX_LI"
|
||||||
|
run_native_chunk "$from" "$to"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
echo "[complete] phase native wall_s=$((SECONDS - _phase_wall_start))"
|
||||||
|
else
|
||||||
|
echo "[complete] skipping native leg (PMM_SOAK_START_LEG=${PMM_SOAK_START_LEG:-unset})"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_phase_wall_start="$SECONDS"
|
||||||
|
if _leg_should_run mint; then
|
||||||
|
echo "[complete] owner-mint mirror USDC shortfall (if any) ..."
|
||||||
|
bash --noprofile --norc "${PROJECT_ROOT}/scripts/deployment/pmm-soak-mint-mirror-usdc-deployer-shortfall.sh" --apply
|
||||||
|
echo "[complete] phase mint wall_s=$((SECONDS - _phase_wall_start))"
|
||||||
|
else
|
||||||
|
echo "[complete] skipping mint leg (PMM_SOAK_START_LEG=${PMM_SOAK_START_LEG:-unset})"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_phase_wall_start="$SECONDS"
|
||||||
|
if _leg_should_run cusdt; then
|
||||||
|
for ((from = 0; from <= MAX_LI; from += CHUNK)); do
|
||||||
|
to=$((from + CHUNK - 1))
|
||||||
|
[[ "$to" -gt "$MAX_LI" ]] && to="$MAX_LI"
|
||||||
|
run_erc20_chunk "$from" "$to" "$CUSDT" "$SEED_CUSDT" "cUSDT"
|
||||||
|
done
|
||||||
|
echo "[complete] phase cusdt wall_s=$((SECONDS - _phase_wall_start))"
|
||||||
|
else
|
||||||
|
echo "[complete] skipping cUSDT leg (PMM_SOAK_START_LEG=${PMM_SOAK_START_LEG:-unset})"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_phase_wall_start="$SECONDS"
|
||||||
|
if _leg_should_run cusdc; then
|
||||||
|
for ((from = 0; from <= MAX_LI; from += CHUNK)); do
|
||||||
|
to=$((from + CHUNK - 1))
|
||||||
|
[[ "$to" -gt "$MAX_LI" ]] && to="$MAX_LI"
|
||||||
|
run_erc20_chunk "$from" "$to" "$CUSDC" "$SEED_CUSDC" "cUSDC"
|
||||||
|
done
|
||||||
|
echo "[complete] phase cusdc wall_s=$((SECONDS - _phase_wall_start))"
|
||||||
|
else
|
||||||
|
echo "[complete] skipping cUSDC leg (PMM_SOAK_START_LEG=${PMM_SOAK_START_LEG:-unset})"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_phase_wall_start="$SECONDS"
|
||||||
|
if _leg_should_run mirr_usdt; then
|
||||||
|
for ((from = 0; from <= MAX_LI; from += CHUNK)); do
|
||||||
|
to=$((from + CHUNK - 1))
|
||||||
|
[[ "$to" -gt "$MAX_LI" ]] && to="$MAX_LI"
|
||||||
|
run_erc20_chunk "$from" "$to" "$USDT_M" "$SEED_USDT" "mirror USDT"
|
||||||
|
done
|
||||||
|
echo "[complete] phase mirr_usdt wall_s=$((SECONDS - _phase_wall_start))"
|
||||||
|
else
|
||||||
|
echo "[complete] skipping mirror USDT leg (PMM_SOAK_START_LEG=${PMM_SOAK_START_LEG:-unset})"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_phase_wall_start="$SECONDS"
|
||||||
|
if _leg_should_run mirr_usdc; then
|
||||||
|
for ((from = 0; from <= MAX_LI; from += CHUNK)); do
|
||||||
|
to=$((from + CHUNK - 1))
|
||||||
|
[[ "$to" -gt "$MAX_LI" ]] && to="$MAX_LI"
|
||||||
|
run_erc20_chunk "$from" "$to" "$USDC_M" "$SEED_USDC" "mirror USDC"
|
||||||
|
done
|
||||||
|
echo "[complete] phase mirr_usdc wall_s=$((SECONDS - _phase_wall_start))"
|
||||||
|
else
|
||||||
|
echo "[complete] skipping mirror USDC leg (PMM_SOAK_START_LEG=${PMM_SOAK_START_LEG:-unset})"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[complete] total apply wall_s=$((SECONDS - _complete_apply_start)) (after waits)"
|
||||||
|
echo "[complete] all legs finished (apply=$APPLY)"
|
||||||
90
scripts/deployment/pmm-soak-mint-mirror-usdc-deployer-shortfall.sh
Executable file
90
scripts/deployment/pmm-soak-mint-mirror-usdc-deployer-shortfall.sh
Executable file
@@ -0,0 +1,90 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Mint Official USDC mirror (Chain 138) to deployer so PMM soak grid funding can transfer out.
|
||||||
|
# OfficialStableMirrorToken: onlyOwner mint(address,uint256). Deployer is owner.
|
||||||
|
#
|
||||||
|
# Waits until deployer latest nonce == pending (no in-flight txs from this EOA), then mints shortfall:
|
||||||
|
# (PMM_SOAK_SEED_MIRROR_USDC_RAW × (6534 wallets)) − deployer balance
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# bash scripts/deployment/pmm-soak-mint-mirror-usdc-deployer-shortfall.sh --dry-run
|
||||||
|
# bash scripts/deployment/pmm-soak-mint-mirror-usdc-deployer-shortfall.sh --apply
|
||||||
|
#
|
||||||
|
# Env: RPC_URL_138, PMM_SOAK_RPC_URL_OVERRIDE, PRIVATE_KEY / DEPLOYER_PRIVATE_KEY, PMM_SOAK_GRID_JSON, PMM_SOAK_SEED_MIRROR_USDC_RAW,
|
||||||
|
# PMM_SOAK_WAIT_NONCE_CLEAR_SEC, CHAIN138_DEPLOY_GAS_PRICE_WEI
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||||
|
cd "$PROJECT_ROOT"
|
||||||
|
# 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
|
||||||
|
|
||||||
|
USDC_M=0x71D6687F38b93CCad569Fa6352c876eea967201b
|
||||||
|
D=0x4A666F96fC8764181194447A7dFdb7d471b301C8
|
||||||
|
RPC="${RPC_URL_138:-http://192.168.11.211:8545}"
|
||||||
|
PK="${DEPLOYER_PRIVATE_KEY:-${PRIVATE_KEY:-}}"
|
||||||
|
SEED_USDC="${PMM_SOAK_SEED_MIRROR_USDC_RAW:-100000000}"
|
||||||
|
MAX_LI=6533
|
||||||
|
GAS_WEI="${CHAIN138_DEPLOY_GAS_PRICE_WEI:-1000}"
|
||||||
|
MAX_WAIT="${PMM_SOAK_WAIT_NONCE_CLEAR_SEC:-7200}"
|
||||||
|
|
||||||
|
APPLY=0
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--apply) APPLY=1 ;;
|
||||||
|
--dry-run) APPLY=0 ;;
|
||||||
|
*) echo "unknown: $1" >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "$APPLY" -eq 1 && -z "$PK" ]]; then
|
||||||
|
echo "[mint-usdc] FATAL: --apply needs PRIVATE_KEY" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
USDC_NEEDED="$(python3 -c "print(int('$SEED_USDC') * (int('$MAX_LI') + 1))")"
|
||||||
|
USDC_BAL="$(cast call "$USDC_M" 'balanceOf(address)(uint256)' "$D" --rpc-url "$RPC" | awk '{print $1}')"
|
||||||
|
if (( USDC_BAL >= USDC_NEEDED )); then
|
||||||
|
echo "[mint-usdc] deployer already has $USDC_BAL >= need $USDC_NEEDED - nothing to do"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
SHORTFALL="$(python3 -c "print(int('$USDC_NEEDED') - int('$USDC_BAL'))")"
|
||||||
|
echo "[mint-usdc] need=$USDC_NEEDED bal=$USDC_BAL shortfall=$SHORTFALL"
|
||||||
|
|
||||||
|
if [[ "$APPLY" -eq 0 ]]; then
|
||||||
|
echo "[mint-usdc] dry-run: after mempool clear, would run:"
|
||||||
|
echo " cast send $USDC_M 'mint(address,uint256)' $D $SHORTFALL --rpc-url \"\$RPC_URL_138\" --private-key \"\$PRIVATE_KEY\" --legacy --gas-price $GAS_WEI"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
start="$SECONDS"
|
||||||
|
while true; do
|
||||||
|
nl="$(cast nonce "$D" --rpc-url "$RPC" -B latest)"
|
||||||
|
np="$(cast nonce "$D" --rpc-url "$RPC" -B pending)"
|
||||||
|
if [[ "$nl" == "$np" ]]; then
|
||||||
|
echo "[mint-usdc] nonce clear (latest=pending=$nl)"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if (( SECONDS - start > MAX_WAIT )); then
|
||||||
|
echo "[mint-usdc] FATAL: pending nonce (latest=$nl pending=$np) after ${MAX_WAIT}s" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "[mint-usdc] waiting mempool latest=$nl pending=$np ..."
|
||||||
|
sleep 3
|
||||||
|
done
|
||||||
|
|
||||||
|
cast send "$USDC_M" 'mint(address,uint256)' "$D" "$SHORTFALL" \
|
||||||
|
--rpc-url "$RPC" --private-key "$PK" --legacy --gas-price "$GAS_WEI"
|
||||||
|
USDC_BAL="$(cast call "$USDC_M" 'balanceOf(address)(uint256)' "$D" --rpc-url "$RPC" | awk '{print $1}')"
|
||||||
|
echo "[mint-usdc] done deployer mirror USDC balance=$USDC_BAL"
|
||||||
195
scripts/deployment/pmm-soak-operator-fund-full-grid-tranches.sh
Executable file
195
scripts/deployment/pmm-soak-operator-fund-full-grid-tranches.sh
Executable file
@@ -0,0 +1,195 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Fund all grid wallets (0..6533) in linear tranches — native + ERC-20 from deployer.
|
||||||
|
# Each tranche invokes pmm-soak-operator-fund-grid.sh (one tx per recipient per tranche).
|
||||||
|
#
|
||||||
|
# Usage (dry-run first):
|
||||||
|
# bash scripts/deployment/pmm-soak-operator-fund-full-grid-tranches.sh --dry-run
|
||||||
|
# bash scripts/deployment/pmm-soak-operator-fund-full-grid-tranches.sh --apply
|
||||||
|
#
|
||||||
|
# Env (optional overrides):
|
||||||
|
# PMM_SOAK_GRID_JSON — default config/pmm-soak-wallet-grid.json
|
||||||
|
# PMM_SOAK_FUND_CHUNK — wallets per tranche (default 250)
|
||||||
|
# NATIVE_AMOUNT_WEI — default 20000000000000000 (0.02)
|
||||||
|
# PMM_SOAK_SEED_CUSDT_RAW / PMM_SOAK_SEED_CUSDC_RAW / PMM_SOAK_SEED_MIRROR_USDT_RAW — 6-decimal raw per wallet (default 100000000 = 100 face)
|
||||||
|
# PMM_SOAK_SEED_MIRROR_USDC_RAW — per-wallet raw amount (default 100000000).
|
||||||
|
# PMM_SOAK_SKIP_MIRROR_USDC_OWNER_MINT=1 — do not auto-mint OfficialStableMirrorToken USDC to deployer when balance is short (default: mint shortfall via owner mint() before transfers).
|
||||||
|
# PMM_SOAK_WAIT_NONCE_CLEAR_SEC — before owner-mint, wait up to this many seconds for deployer latest==pending nonce (default 7200). Avoids "replacement transaction underpriced" when another process holds the next nonce.
|
||||||
|
# PMM_SOAK_RPC_URL_OVERRIDE — after dotenv load, force RPC_URL_138 (same as complete-grid / fund-grid long runs).
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||||
|
cd "$PROJECT_ROOT"
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
GRID_JSON="${PMM_SOAK_GRID_JSON:-${PROJECT_ROOT}/config/pmm-soak-wallet-grid.json}"
|
||||||
|
CHUNK="${PMM_SOAK_FUND_CHUNK:-250}"
|
||||||
|
NATIVE_WEI="${NATIVE_AMOUNT_WEI:-20000000000000000}"
|
||||||
|
SEED_CUSDT="${PMM_SOAK_SEED_CUSDT_RAW:-100000000}"
|
||||||
|
SEED_CUSDC="${PMM_SOAK_SEED_CUSDC_RAW:-100000000}"
|
||||||
|
SEED_USDT="${PMM_SOAK_SEED_MIRROR_USDT_RAW:-100000000}"
|
||||||
|
SEED_USDC="${PMM_SOAK_SEED_MIRROR_USDC_RAW:-100000000}"
|
||||||
|
|
||||||
|
CUSDT=0x93E66202A11B1772E55407B32B44e5Cd8eda7f22
|
||||||
|
CUSDC=0xf22258f57794CC8E06237084b353Ab30fFfa640b
|
||||||
|
USDT_M=0x004b63A7B5b0E06f6bB6adb4a5F9f590BF3182D1
|
||||||
|
USDC_M=0x71D6687F38b93CCad569Fa6352c876eea967201b
|
||||||
|
|
||||||
|
RPC="${RPC_URL_138:-http://192.168.11.211:8545}"
|
||||||
|
PK="${DEPLOYER_PRIVATE_KEY:-${PRIVATE_KEY:-}}"
|
||||||
|
D=0x4A666F96fC8764181194447A7dFdb7d471b301C8
|
||||||
|
|
||||||
|
APPLY=0
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--apply) APPLY=1 ;;
|
||||||
|
--dry-run) APPLY=0 ;;
|
||||||
|
-h | --help)
|
||||||
|
sed -n '1,28p' "$0" | tail -n +2
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*) echo "unknown: $1" >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "$APPLY" -eq 1 && -z "$PK" ]]; then
|
||||||
|
echo "[fund-tranches] FATAL: --apply needs PRIVATE_KEY / DEPLOYER_PRIVATE_KEY" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$GRID_JSON" ]]; then
|
||||||
|
echo "[fund-tranches] missing $GRID_JSON" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
MAX_LI=6533
|
||||||
|
GAS_WEI="${CHAIN138_DEPLOY_GAS_PRICE_WEI:-1000}"
|
||||||
|
|
||||||
|
refresh_usdc_bal() {
|
||||||
|
USDC_BAL="$(cast call "$USDC_M" 'balanceOf(address)(uint256)' "$D" --rpc-url "$RPC" | awk '{print $1}')"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Wait until deployer has no pending txs (latest nonce tag == pending nonce tag).
|
||||||
|
wait_deployer_nonce_mempool_clear() {
|
||||||
|
local max_wait="${PMM_SOAK_WAIT_NONCE_CLEAR_SEC:-7200}"
|
||||||
|
local start="$SECONDS"
|
||||||
|
while true; do
|
||||||
|
local nl np
|
||||||
|
nl="$(cast nonce "$D" --rpc-url "$RPC" -B latest)"
|
||||||
|
np="$(cast nonce "$D" --rpc-url "$RPC" -B pending)"
|
||||||
|
if [[ "$nl" == "$np" ]]; then
|
||||||
|
echo "[fund-tranches] deployer nonce clear (latest=pending=$nl)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if (( SECONDS - start > max_wait )); then
|
||||||
|
echo "[fund-tranches] FATAL: deployer still has pending nonce (latest=$nl pending=$np) after ${max_wait}s — stop other deployer senders or raise PMM_SOAK_WAIT_NONCE_CLEAR_SEC" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "[fund-tranches] waiting for deployer mempool (latest=$nl pending=$np) …"
|
||||||
|
sleep 3
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
USDC_NEEDED="$(python3 -c "print(int('$SEED_USDC') * (int('$MAX_LI') + 1))")"
|
||||||
|
refresh_usdc_bal
|
||||||
|
DO_MIRROR_USDC=1
|
||||||
|
if (( USDC_BAL < USDC_NEEDED )); then
|
||||||
|
SHORTFALL="$(python3 -c "print(int('$USDC_NEEDED') - int('$USDC_BAL'))")"
|
||||||
|
if [[ "${PMM_SOAK_SKIP_MIRROR_USDC_OWNER_MINT:-0}" == "1" ]]; then
|
||||||
|
DO_MIRROR_USDC=0
|
||||||
|
echo "[fund-tranches] WARN: deployer mirror USDC balance $USDC_BAL < need $USDC_NEEDED; PMM_SOAK_SKIP_MIRROR_USDC_OWNER_MINT=1 — skipping mirror USDC tranches"
|
||||||
|
elif [[ "$APPLY" -eq 0 ]]; then
|
||||||
|
echo "[fund-tranches] deployer mirror USDC $USDC_BAL < need $USDC_NEEDED — dry-run: on --apply would owner-mint $SHORTFALL to deployer then fund mirror USDC"
|
||||||
|
echo " cast send $USDC_M 'mint(address,uint256)' $D $SHORTFALL --rpc-url \"\$RPC_URL_138\" --private-key \"\$PRIVATE_KEY\" --legacy --gas-price $GAS_WEI"
|
||||||
|
DO_MIRROR_USDC=1
|
||||||
|
elif [[ -z "$PK" ]]; then
|
||||||
|
DO_MIRROR_USDC=0
|
||||||
|
echo "[fund-tranches] WARN: shortfall $SHORTFALL but no PRIVATE_KEY — cannot mint; skipping mirror USDC tranches" >&2
|
||||||
|
else
|
||||||
|
echo "[fund-tranches] owner-mint mirror USDC shortfall $SHORTFALL to deployer (need $USDC_NEEDED, have $USDC_BAL)"
|
||||||
|
wait_deployer_nonce_mempool_clear
|
||||||
|
cast send "$USDC_M" 'mint(address,uint256)' "$D" "$SHORTFALL" \
|
||||||
|
--rpc-url "$RPC" --private-key "$PK" --legacy --gas-price "$GAS_WEI"
|
||||||
|
refresh_usdc_bal
|
||||||
|
if (( USDC_BAL < USDC_NEEDED )); then
|
||||||
|
echo "[fund-tranches] FATAL: after mint deployer USDC $USDC_BAL still < $USDC_NEEDED" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "[fund-tranches] deployer mirror USDC balance now $USDC_BAL"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
run_native() {
|
||||||
|
local from="$1" to="$2"
|
||||||
|
echo "[fund-tranches] === native linear $from..$to (apply=$APPLY) ==="
|
||||||
|
if [[ "$APPLY" -eq 1 ]]; then
|
||||||
|
PMM_SOAK_GRID_JSON="$GRID_JSON" NATIVE_AMOUNT_WEI="$NATIVE_WEI" \
|
||||||
|
bash --noprofile --norc "${PROJECT_ROOT}/scripts/deployment/pmm-soak-operator-fund-grid.sh" --apply --native --from-linear "$from" --to-linear "$to"
|
||||||
|
else
|
||||||
|
PMM_SOAK_GRID_JSON="$GRID_JSON" NATIVE_AMOUNT_WEI="$NATIVE_WEI" \
|
||||||
|
bash --noprofile --norc "${PROJECT_ROOT}/scripts/deployment/pmm-soak-operator-fund-grid.sh" --native --from-linear "$from" --to-linear "$to"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run_erc20() {
|
||||||
|
local from="$1" to="$2" tok="$3" amt="$4"
|
||||||
|
echo "[fund-tranches] === ERC-20 $tok linear $from..$to amount=$amt (apply=$APPLY) ==="
|
||||||
|
if [[ "$APPLY" -eq 1 ]]; then
|
||||||
|
PMM_SOAK_GRID_JSON="$GRID_JSON" TOKEN="$tok" AMOUNT_WEI_PER_WALLET="$amt" \
|
||||||
|
bash --noprofile --norc "${PROJECT_ROOT}/scripts/deployment/pmm-soak-operator-fund-grid.sh" --apply --from-linear "$from" --to-linear "$to"
|
||||||
|
else
|
||||||
|
PMM_SOAK_GRID_JSON="$GRID_JSON" TOKEN="$tok" AMOUNT_WEI_PER_WALLET="$amt" \
|
||||||
|
bash --noprofile --norc "${PROJECT_ROOT}/scripts/deployment/pmm-soak-operator-fund-grid.sh" --from-linear "$from" --to-linear "$to"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((from = 0; from <= MAX_LI; from += CHUNK)); do
|
||||||
|
to=$((from + CHUNK - 1))
|
||||||
|
[[ "$to" -gt "$MAX_LI" ]] && to="$MAX_LI"
|
||||||
|
run_native "$from" "$to"
|
||||||
|
done
|
||||||
|
|
||||||
|
for ((from = 0; from <= MAX_LI; from += CHUNK)); do
|
||||||
|
to=$((from + CHUNK - 1))
|
||||||
|
[[ "$to" -gt "$MAX_LI" ]] && to="$MAX_LI"
|
||||||
|
run_erc20 "$from" "$to" "$CUSDT" "$SEED_CUSDT"
|
||||||
|
done
|
||||||
|
|
||||||
|
for ((from = 0; from <= MAX_LI; from += CHUNK)); do
|
||||||
|
to=$((from + CHUNK - 1))
|
||||||
|
[[ "$to" -gt "$MAX_LI" ]] && to="$MAX_LI"
|
||||||
|
run_erc20 "$from" "$to" "$CUSDC" "$SEED_CUSDC"
|
||||||
|
done
|
||||||
|
|
||||||
|
for ((from = 0; from <= MAX_LI; from += CHUNK)); do
|
||||||
|
to=$((from + CHUNK - 1))
|
||||||
|
[[ "$to" -gt "$MAX_LI" ]] && to="$MAX_LI"
|
||||||
|
run_erc20 "$from" "$to" "$USDT_M" "$SEED_USDT"
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "$DO_MIRROR_USDC" -eq 1 ]]; then
|
||||||
|
for ((from = 0; from <= MAX_LI; from += CHUNK)); do
|
||||||
|
to=$((from + CHUNK - 1))
|
||||||
|
[[ "$to" -gt "$MAX_LI" ]] && to="$MAX_LI"
|
||||||
|
run_erc20 "$from" "$to" "$USDC_M" "$SEED_USDC"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo "[fund-tranches] mirror USDC tranches skipped (see WARN above). Options: unset PMM_SOAK_SKIP_MIRROR_USDC_OWNER_MINT and re-run --apply (auto-mint), or manual mint then:"
|
||||||
|
echo " PMM_SOAK_GRID_JSON=$GRID_JSON TOKEN=$USDC_M AMOUNT_WEI_PER_WALLET=$SEED_USDC bash --noprofile --norc scripts/deployment/pmm-soak-operator-fund-grid.sh --apply --from-linear 0 --to-linear $MAX_LI"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[fund-tranches] done (apply=$APPLY)"
|
||||||
209
scripts/deployment/pmm-soak-operator-fund-grid.sh
Executable file
209
scripts/deployment/pmm-soak-operator-fund-grid.sh
Executable file
@@ -0,0 +1,209 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Operator (deployer) funds grid wallets from an exported JSON manifest.
|
||||||
|
#
|
||||||
|
# Modes:
|
||||||
|
# ERC-20 (default): TOKEN + AMOUNT_WEI_PER_WALLET — transfer() from operator to each grid address.
|
||||||
|
# Native (--native): NATIVE_AMOUNT_WEI (or AMOUNT_WEI_PER_WALLET) — simple value transfer for gas on Chain 138.
|
||||||
|
#
|
||||||
|
# Default: dry-run. Live: --apply
|
||||||
|
#
|
||||||
|
# Usage (ERC-20):
|
||||||
|
# PMM_SOAK_GRID_JSON=config/pmm-soak-wallet-grid.json \
|
||||||
|
# TOKEN=0x93E66202A11B1772E55407B32B44e5Cd8eda7f22 AMOUNT_WEI_PER_WALLET=10000000000 \
|
||||||
|
# bash scripts/deployment/pmm-soak-operator-fund-grid.sh --apply --from-linear 0 --to-linear 99
|
||||||
|
#
|
||||||
|
# Usage (native / gas):
|
||||||
|
# PMM_SOAK_GRID_JSON=config/pmm-soak-wallet-grid.json \
|
||||||
|
# NATIVE_AMOUNT_WEI=20000000000000000 \
|
||||||
|
# bash scripts/deployment/pmm-soak-operator-fund-grid.sh --native --apply --from-linear 0 --to-linear 199
|
||||||
|
#
|
||||||
|
# Env:
|
||||||
|
# PRIVATE_KEY / DEPLOYER_PRIVATE_KEY — operator
|
||||||
|
# RPC_URL_138
|
||||||
|
# PMM_SOAK_GRID_JSON — default: $PROJECT_ROOT/config/pmm-soak-wallet-grid.json
|
||||||
|
# TOKEN — ERC-20 (not used with --native)
|
||||||
|
# AMOUNT_WEI_PER_WALLET — per-recipient raw amount (ERC-20); also accepted for --native if NATIVE_AMOUNT_WEI unset
|
||||||
|
# NATIVE_AMOUNT_WEI — preferred for --native (wei per wallet)
|
||||||
|
# CHAIN138_DEPLOY_GAS_PRICE_WEI — default 1000
|
||||||
|
# CAST_SEND_TIMEOUT_SEC — passed to cast as ETH_TIMEOUT (seconds to wait for tx confirmation; default 900)
|
||||||
|
# CAST_RPC_TIMEOUT_SEC — ETH_RPC_TIMEOUT for cast (default 120)
|
||||||
|
# PMM_SOAK_RPC_URL_OVERRIDE — after dotenv load, force RPC_URL_138 for all cast calls
|
||||||
|
# PMM_SOAK_FUND_PROGRESS_EVERY — during --apply, log ETA every N successful txs (0=off except final; default 50)
|
||||||
|
#
|
||||||
|
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
|
||||||
|
|
||||||
|
require_cmd() {
|
||||||
|
command -v "$1" >/dev/null 2>&1 || {
|
||||||
|
echo "[fund-grid] missing: $1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
require_cmd cast
|
||||||
|
require_cmd python3
|
||||||
|
|
||||||
|
APPLY=0
|
||||||
|
FROM_L=0
|
||||||
|
TO_L=6533
|
||||||
|
MODE="erc20"
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--apply) APPLY=1 ;;
|
||||||
|
--native) MODE="native" ;;
|
||||||
|
--erc20) MODE="erc20" ;;
|
||||||
|
--from-linear)
|
||||||
|
FROM_L="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--to-linear)
|
||||||
|
TO_L="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h | --help)
|
||||||
|
sed -n '2,31p' "$0"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "[fund-grid] unknown arg: $1" >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
PK="${DEPLOYER_PRIVATE_KEY:-${PRIVATE_KEY:-}}"
|
||||||
|
RPC="${RPC_URL_138:-http://192.168.11.211:8545}"
|
||||||
|
GRID_JSON="${PMM_SOAK_GRID_JSON:-${PROJECT_ROOT}/config/pmm-soak-wallet-grid.json}"
|
||||||
|
TOKEN_ADDR="${TOKEN:-}"
|
||||||
|
GAS_WEI="${CHAIN138_DEPLOY_GAS_PRICE_WEI:-1000}"
|
||||||
|
|
||||||
|
NATIVE_AMOUNT="${NATIVE_AMOUNT_WEI:-}"
|
||||||
|
ERC20_AMOUNT="${AMOUNT_WEI_PER_WALLET:-}"
|
||||||
|
|
||||||
|
if [[ "$MODE" == "native" ]]; then
|
||||||
|
AMOUNT="${NATIVE_AMOUNT:-${ERC20_AMOUNT:-}}"
|
||||||
|
if [[ -z "$AMOUNT" ]]; then
|
||||||
|
echo "[fund-grid] --native requires NATIVE_AMOUNT_WEI or AMOUNT_WEI_PER_WALLET (wei per wallet)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
AMOUNT="${ERC20_AMOUNT:-}"
|
||||||
|
if [[ -z "$TOKEN_ADDR" || -z "$AMOUNT" ]]; then
|
||||||
|
echo "[fund-grid] ERC-20 mode: set TOKEN and AMOUNT_WEI_PER_WALLET" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$GRID_JSON" ]]; then
|
||||||
|
echo "[fund-grid] missing grid JSON: $GRID_JSON" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$APPLY" -eq 1 && -z "$PK" ]]; then
|
||||||
|
echo "[fund-grid] --apply requires PRIVATE_KEY / DEPLOYER_PRIVATE_KEY" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
OPERATOR="$(cast wallet address --private-key "$PK" 2>/dev/null || true)"
|
||||||
|
if [[ "$APPLY" -eq 1 && -z "$OPERATOR" ]]; then
|
||||||
|
echo "[fund-grid] could not derive operator address" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mapfile -t RECIPIENTS < <(
|
||||||
|
python3 - "$GRID_JSON" "$FROM_L" "$TO_L" <<'PY'
|
||||||
|
import json, sys
|
||||||
|
path, lo, hi = sys.argv[1], int(sys.argv[2]), int(sys.argv[3])
|
||||||
|
with open(path, encoding="utf-8") as f:
|
||||||
|
doc = json.load(f)
|
||||||
|
for w in doc["wallets"]:
|
||||||
|
li = int(w["linearIndex"])
|
||||||
|
if lo <= li <= hi:
|
||||||
|
print(w["address"])
|
||||||
|
PY
|
||||||
|
)
|
||||||
|
|
||||||
|
total="${#RECIPIENTS[@]}"
|
||||||
|
if [[ "$MODE" == "native" ]]; then
|
||||||
|
echo "[fund-grid] mode=native recipients=[$FROM_L,$TO_L] count=$total amount_each_wei=$AMOUNT apply=$APPLY"
|
||||||
|
else
|
||||||
|
echo "[fund-grid] mode=erc20 recipients=[$FROM_L,$TO_L] count=$total token=$TOKEN_ADDR amount_each=$AMOUNT apply=$APPLY"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$total" -eq 0 ]]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
export ETH_TIMEOUT="${CAST_SEND_TIMEOUT_SEC:-900}"
|
||||||
|
export ETH_RPC_TIMEOUT="${CAST_RPC_TIMEOUT_SEC:-120}"
|
||||||
|
|
||||||
|
total_needed="$(python3 -c "print(int('$AMOUNT') * $total)")"
|
||||||
|
|
||||||
|
if [[ "$APPLY" -eq 0 ]]; then
|
||||||
|
echo "[fund-grid] dry-run sample (first 3):"
|
||||||
|
for i in 0 1 2; do
|
||||||
|
[[ "$i" -lt "$total" ]] || break
|
||||||
|
if [[ "$MODE" == "native" ]]; then
|
||||||
|
echo " cast send ${RECIPIENTS[$i]} --value $AMOUNT --rpc-url \"\$RPC_URL_138\" --private-key \"\$PRIVATE_KEY\" --legacy --gas-price $GAS_WEI"
|
||||||
|
else
|
||||||
|
echo " cast send $TOKEN_ADDR 'transfer(address,uint256)(bool)' ${RECIPIENTS[$i]} $AMOUNT --rpc-url \"\$RPC_URL_138\" --private-key \"\$PRIVATE_KEY\" --legacy --gas-price $GAS_WEI"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ "$MODE" == "native" ]]; then
|
||||||
|
echo "[fund-grid] aggregate native to recipients: $total_needed wei (+ operator gas for each funding tx)"
|
||||||
|
else
|
||||||
|
echo "[fund-grid] aggregate ERC-20 to recipients: $total_needed raw units (+ operator gas for each funding tx)"
|
||||||
|
fi
|
||||||
|
echo "[fund-grid] rerun with --apply to broadcast $total transactions"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$MODE" == "native" && -n "$OPERATOR" ]]; then
|
||||||
|
op_bal="$(cast balance "$OPERATOR" --rpc-url "$RPC" 2>/dev/null | head -1 || echo "0")"
|
||||||
|
echo "[fund-grid] operator native balance (approx): $op_bal wei - need $total_needed wei to recipients + gas for $total txs"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_pmm_fund_grid_err() {
|
||||||
|
echo "[fund-grid] ERR line=${BASH_LINENO[0]} n=${n:-0}/${total} mode=${MODE} recipients=[$FROM_L,$TO_L]" >&2
|
||||||
|
}
|
||||||
|
trap '_pmm_fund_grid_err' ERR
|
||||||
|
|
||||||
|
_chunk_wall_start="$SECONDS"
|
||||||
|
_prog_every="${PMM_SOAK_FUND_PROGRESS_EVERY:-50}"
|
||||||
|
[[ "$_prog_every" =~ ^[0-9]+$ ]] || _prog_every=50
|
||||||
|
n=0
|
||||||
|
for r in "${RECIPIENTS[@]}"; do
|
||||||
|
n=$((n + 1))
|
||||||
|
echo "[fund-grid] $n/$total -> $r"
|
||||||
|
if [[ "$MODE" == "native" ]]; then
|
||||||
|
cast send "$r" --value "$AMOUNT" --rpc-url "$RPC" --private-key "$PK" --legacy --gas-price "$GAS_WEI"
|
||||||
|
else
|
||||||
|
cast send "$TOKEN_ADDR" 'transfer(address,uint256)(bool)' "$r" "$AMOUNT" \
|
||||||
|
--rpc-url "$RPC" --private-key "$PK" --legacy --gas-price "$GAS_WEI"
|
||||||
|
fi
|
||||||
|
if [[ "$_prog_every" -gt 0 ]] && (( n % _prog_every == 0 || n == total )); then
|
||||||
|
_el=$((SECONDS - _chunk_wall_start))
|
||||||
|
python3 -c "n=$n;total=$total;el=$_el;avg=el/n if n else 0.0;rem=total-n;eta=int(rem*avg) if rem>0 else 0;print(f'[fund-grid] progress {n}/{total} chunk_elapsed_s={el} avg_s_per_tx={avg:.2f} est_remaining_this_chunk_s={eta}')" 2>/dev/null || true
|
||||||
|
elif [[ "$_prog_every" -eq 0 ]] && [[ "$n" -eq "$total" ]]; then
|
||||||
|
echo "[fund-grid] progress ${n}/${total} chunk_elapsed_s=$((SECONDS - _chunk_wall_start)) (final)"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
trap - ERR
|
||||||
|
echo "[fund-grid] done"
|
||||||
Reference in New Issue
Block a user