From 88eef454c43561ec4183c4b5a992a8bb14d4d84c Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Thu, 30 Jul 2026 10:44:34 +0000 Subject: [PATCH 1/7] test(amm-ui): add isolated AMM testnet setup script --- apps/amm/.gitignore | 3 + apps/amm/tests/testnet/setup-amm-testnet.sh | 314 ++++++++++++++++++++ 2 files changed, 317 insertions(+) create mode 100755 apps/amm/tests/testnet/setup-amm-testnet.sh diff --git a/apps/amm/.gitignore b/apps/amm/.gitignore index 6acdd425..f7ad73a3 100644 --- a/apps/amm/.gitignore +++ b/apps/amm/.gitignore @@ -8,3 +8,6 @@ amm-tokens.json # Screenshot artifacts written by tests/swap.mjs tests/*.png + +# Isolated wallet home used by tests/testnet/setup-amm-testnet.sh +tests/testnet/.wallet/ diff --git a/apps/amm/tests/testnet/setup-amm-testnet.sh b/apps/amm/tests/testnet/setup-amm-testnet.sh new file mode 100755 index 00000000..92b88ac3 --- /dev/null +++ b/apps/amm/tests/testnet/setup-amm-testnet.sh @@ -0,0 +1,314 @@ +#!/usr/bin/env bash +# +# setup-amm-testnet.sh +# -------------------- +# Deploy the token/amm/twap programs, mint two fungible tokens, initialize the +# AMM, and create a pool — from scratch — against whatever sequencer your +# `wallet` / `spel` config points at. This is the prerequisite state that the +# AMM UI swap test (apps/amm/tests/swap.mjs) exercises; run it once to stand up +# a swappable pool, then launch the UI / run the test. +# +# Program IDs and all AMM PDAs (config, pool, vaults, LP, tick) are DERIVED at +# runtime from the deployed binaries + the token definition accounts, so this +# script stays correct even if you rebuild the guest binaries (new image id => +# new program id => new PDAs). Only the input accounts below are hand-picked. +# +# TEST WALLET (isolated): by default this script points the wallet at a +# dedicated, git-ignored home under this folder (apps/amm/tests/testnet/.wallet) +# so it never touches your personal ~/.lee/wallet. Override with TEST_WALLET_HOME. +# +# Prerequisites (all managed by you, outside this script): +# - `wallet` and `spel` on PATH (from the SPEL toolchain) +# - a wallet initialized at TEST_WALLET_HOME, funded and synced, that OWNS the +# account ids configured below (see "TEST ACCOUNTS" — these must be derived +# from / created in the test wallet; see docs/testnet-runbook.md §2) +# - `cargo` (to run the amm_pdas example) +# - the guest .bin files already built (`make build-programs`) +# - the IDL files under artifacts/ (`make idl`) +# +# Usage (from anywhere in the repo): +# apps/amm/tests/testnet/setup-amm-testnet.sh +# TEST_WALLET_HOME=/tmp/lez-test-wallet apps/amm/tests/testnet/setup-amm-testnet.sh +# +set -euo pipefail + +# Resolve the repo root robustly regardless of where the script lives / is called +# from. Prefer git; fall back to walking up from this script's directory. +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="${REPO_ROOT:-$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null || cd "$SCRIPT_DIR/../../../.." && pwd)}" +cd "$REPO_ROOT" + +############################################################################### +# TEST WALLET — isolated from your personal wallet +############################################################################### + +# Dedicated wallet home for tests. Kept out of git (see .gitignore). Exported +# under both env var names so whichever the installed `wallet`/`spel` expects +# is satisfied. +TEST_WALLET_HOME="${TEST_WALLET_HOME:-$SCRIPT_DIR/.wallet}" +export LEE_WALLET_HOME_DIR="$TEST_WALLET_HOME" +export NSSA_WALLET_HOME_DIR="$TEST_WALLET_HOME" + +# The deterministic test mnemonic. A wallet restored from this seed always +# yields the same account ids, which is why the ids below can be pinned and +# shared with the team. Keep in sync with the wallet at TEST_WALLET_HOME. +TEST_MNEMONIC="${TEST_MNEMONIC:-test test test test test test test test test test test junk}" + +############################################################################### +# CONFIG — edit these +############################################################################### + +# --- Program binaries (docker release builds; image ids must match deployment) --- +TOKEN_BIN="programs/token/methods/guest/target/riscv32im-risc0-zkvm-elf/docker/token.bin" +AMM_BIN="programs/amm/methods/guest/target/riscv32im-risc0-zkvm-elf/docker/amm.bin" +TWAP_BIN="programs/twap_oracle/methods/guest/target/riscv32im-risc0-zkvm-elf/docker/twap_oracle.bin" + +# --- IDLs --- +TOKEN_IDL="artifacts/token-idl.json" +AMM_IDL="artifacts/amm-idl.json" + +# --- TEST ACCOUNTS (must be owned by the wallet at TEST_WALLET_HOME) ---------- +# These are the deterministic accounts the test suite relies on. See the +# "Deterministic test accounts" note at the top of the file / the PR discussion: +# once the test wallet is restored from TEST_MNEMONIC, capture the ids it derives +# and pin them here so amm-tokens.json and swap.mjs can reference known accounts. + +# --- Token A --- +TOKEN_A_NAME="TOKEN A" +TOKEN_A_SUPPLY="1000000000000000000000" +TOKEN_A_DEF="6gQMF38wEDPEnUamLmNqN8opss5xvr9w55eddddMmpEK" # --definition-target-account +TOKEN_A_HOLDING="EF6c3VtgzUzpxfEKpvR3ZxsCch8y5YqazmWQu6Bybvyq" # --holding-target-account +TOKEN_A_MINT_AUTH="EF6c3VtgzUzpxfEKpvR3ZxsCch8y5YqazmWQu6Bybvyq" + +# --- Token B --- +TOKEN_B_NAME="TOKEN B" +TOKEN_B_SUPPLY="1000000000000000000000" +TOKEN_B_DEF="Hw65ZimauFtHtvmDvWb24aWi1E6uRCifdyEn46Ei8wAc" +TOKEN_B_HOLDING="L3hr1xABT3gkSYR1Fztu2smyJ1ftXcivjM8LguMjAsp" +TOKEN_B_MINT_AUTH="L3hr1xABT3gkSYR1Fztu2smyJ1ftXcivjM8LguMjAsp" + +# --- AMM / pool inputs --- +AMM_AUTHORITY="EF6c3VtgzUzpxfEKpvR3ZxsCch8y5YqazmWQu6Bybvyq" +USER_HOLDING_A="$TOKEN_A_HOLDING" +USER_HOLDING_B="$TOKEN_B_HOLDING" +USER_HOLDING_LP="7taJs6YpzBcWc5jiZcnZ817nU1G5WnQtBHskbcMDUc6A" +CLOCK_ACCOUNT="4BdcjoXkq786TMWcBGGHqcxeLYMZmn17rL4eM9ZyRWNU" + +POOL_TOKEN_A_AMOUNT="10000" +POOL_TOKEN_B_AMOUNT="10000" +POOL_FEES="1" +POOL_DEADLINE="18446744073709551615" + +############################################################################### +# Helpers +############################################################################### + +BOLD=$'\033[1m'; DIM=$'\033[2m'; RED=$'\033[31m'; GRN=$'\033[32m'; YEL=$'\033[33m'; CYN=$'\033[36m'; RST=$'\033[0m' + +hr() { printf '%s\n' "${DIM}────────────────────────────────────────────────────────────────────────${RST}"; } +log() { printf '%s\n' "$*"; } +sec() { hr; printf '%s\n' "${BOLD}${CYN}==> $*${RST}"; hr; } +kv() { printf ' %-22s %s\n' "$1" "$2"; } +die() { printf '%s\n' "${RED}✗ $*${RST}" >&2; exit 1; } + +require_cmd() { command -v "$1" >/dev/null 2>&1 || die "required command not found on PATH: $1"; } +require_file(){ [ -f "$1" ] || die "required file not found: $1 (cwd=$(pwd))"; } + +# Run a transaction command, streaming its output live, then assert the +# sequencer confirmation marker is present. +# run_tx "" -- [args...] +run_tx() { + local mode="$1"; shift + local desc="$1"; shift + [ "$1" = "--" ] && shift + + sec "TX: $desc" + log "${DIM}\$ $*${RST}" + local tmp; tmp="$(mktemp)" + + set +e + "$@" 2>&1 | tee "$tmp" + local rc=${PIPESTATUS[0]} + set -e + + if [ "$rc" -ne 0 ]; then + rm -f "$tmp" + die "command exited with status $rc — $desc" + fi + + # The confirmation line printed by spel is: + # ✅ Transaction confirmed — included in a block. + # Match on the two stable substrings to be robust to emoji/dash encoding. + if grep -q "Transaction confirmed" "$tmp" && grep -q "included in a block" "$tmp"; then + log "${GRN}✅ CONFIRMED — included in a block: ${desc}${RST}" + rm -f "$tmp" + return 0 + fi + + rm -f "$tmp" + if [ "$mode" = "soft" ]; then + log "${YEL}⚠ no '✅ Transaction confirmed — included in a block.' marker for: ${desc}" + log " (continuing — 'wallet deploy-program' may not print the spel marker; verify manually)${RST}" + return 0 + fi + die "NOT CONFIRMED — expected '✅ Transaction confirmed — included in a block.' for: $desc" +} + +# Read-only account inspection (no confirmation check). +inspect() { + local idl="$1" addr="$2" type="$3" + sec "INSPECT: $type @ $addr" + log "${DIM}\$ spel --idl $idl inspect $addr --type $type${RST}" + spel --idl "$idl" inspect "$addr" --type "$type" +} + +# Extract a 64-char hex program id from `spel -- program-id `. +program_id() { + local bin="$1" out pid + out="$(spel -- program-id "$bin" 2>&1)" || { echo "$out" >&2; die "spel program-id failed for $bin"; } + pid="$(printf '%s' "$out" | grep -oiE '[0-9a-f]{64}' | head -n1 || true)" + [ -n "$pid" ] || { echo "$out" >&2; die "could not parse a 64-char program id from spel output for $bin"; } + printf '%s' "$pid" +} + +############################################################################### +# 0. Preflight +############################################################################### +sec "Preflight" +require_cmd wallet +require_cmd spel +require_cmd cargo +require_file "$TOKEN_BIN"; require_file "$AMM_BIN"; require_file "$TWAP_BIN" +require_file "$TOKEN_IDL"; require_file "$AMM_IDL" +kv "repo root" "$REPO_ROOT" +kv "test wallet home" "$TEST_WALLET_HOME" +if [ ! -d "$TEST_WALLET_HOME" ]; then + die "test wallet home not found: $TEST_WALLET_HOME + Initialize a wallet there from the test mnemonic, then create/pin the TEST + ACCOUNTS above. See docs/testnet-runbook.md §2. Mnemonic: + \"$TEST_MNEMONIC\"" +fi +kv "token bin" "$TOKEN_BIN" +kv "amm bin" "$AMM_BIN" +kv "twap bin" "$TWAP_BIN" + +############################################################################### +# 1. Deploy programs +############################################################################### +run_tx soft "deploy token program" -- wallet deploy-program "$TOKEN_BIN" +run_tx soft "deploy amm program" -- wallet deploy-program "$AMM_BIN" +run_tx soft "deploy twap_oracle program" -- wallet deploy-program "$TWAP_BIN" + +############################################################################### +# 2. Derive program IDs +############################################################################### +sec "Program IDs (derived from the deployed binaries)" +TOKEN_PID="$(program_id "$TOKEN_BIN")"; kv "token program id" "$TOKEN_PID" +AMM_PID="$(program_id "$AMM_BIN")"; kv "amm program id" "$AMM_PID" +TWAP_PID="$(program_id "$TWAP_BIN")"; kv "twap program id" "$TWAP_PID" + +############################################################################### +# 3. Create token definitions (mint supply to the holding accounts) +############################################################################### +run_tx strict "create fungible definition: $TOKEN_A_NAME" -- \ + spel --idl "$TOKEN_IDL" --program "$TOKEN_BIN" -- new-fungible-definition \ + --name "$TOKEN_A_NAME" --total-supply "$TOKEN_A_SUPPLY" \ + --definition-target-account "$TOKEN_A_DEF" \ + --holding-target-account "$TOKEN_A_HOLDING" \ + --mint-authority "$TOKEN_A_MINT_AUTH" + +run_tx strict "create fungible definition: $TOKEN_B_NAME" -- \ + spel --idl "$TOKEN_IDL" --program "$TOKEN_BIN" -- new-fungible-definition \ + --name "$TOKEN_B_NAME" --total-supply "$TOKEN_B_SUPPLY" \ + --definition-target-account "$TOKEN_B_DEF" \ + --holding-target-account "$TOKEN_B_HOLDING" \ + --mint-authority "$TOKEN_B_MINT_AUTH" + +############################################################################### +# 4. Verify token definitions & holdings +############################################################################### +inspect "$TOKEN_IDL" "$TOKEN_A_DEF" "TokenDefinition" +inspect "$TOKEN_IDL" "$TOKEN_A_HOLDING" "TokenHolding" +inspect "$TOKEN_IDL" "$TOKEN_B_DEF" "TokenDefinition" +inspect "$TOKEN_IDL" "$TOKEN_B_HOLDING" "TokenHolding" + +############################################################################### +# 5. Derive AMM PDAs from the program ids + token pair +############################################################################### +sec "Deriving AMM PDAs (amm_pdas example)" +log "${DIM}\$ cargo run -q -p amm_program --example amm_pdas -- $AMM_PID $TWAP_PID $TOKEN_A_DEF $TOKEN_B_DEF${RST}" +PDAS="$(RISC0_DEV_MODE=1 RISC0_SKIP_BUILD=1 cargo run -q -p amm_program --example amm_pdas -- \ + "$AMM_PID" "$TWAP_PID" "$TOKEN_A_DEF" "$TOKEN_B_DEF")" +printf '%s\n' "$PDAS" + +pda() { printf '%s' "$PDAS" | awk -v k="$1" '$1==k {print $2; exit}'; } +CONFIG="$(pda config)" +POOL="$(pda pool)" +VAULT_A="$(pda vault_a)" +VAULT_B="$(pda vault_b)" +POOL_LP="$(pda pool_definition_lp)" +LP_LOCK="$(pda lp_lock_holding)" +TICK="$(pda current_tick_account)" + +for name in CONFIG POOL VAULT_A VAULT_B POOL_LP LP_LOCK TICK; do + [ -n "${!name}" ] || die "failed to parse PDA '$name' from amm_pdas output" +done + +sec "Resolved accounts" +kv "config" "$CONFIG" +kv "pool" "$POOL" +kv "vault_a" "$VAULT_A" +kv "vault_b" "$VAULT_B" +kv "pool_definition_lp" "$POOL_LP" +kv "lp_lock_holding" "$LP_LOCK" +kv "current_tick_account" "$TICK" +kv "user_holding_a" "$USER_HOLDING_A" +kv "user_holding_b" "$USER_HOLDING_B" +kv "user_holding_lp" "$USER_HOLDING_LP" +kv "clock" "$CLOCK_ACCOUNT" + +############################################################################### +# 6. Initialize the AMM +############################################################################### +run_tx strict "initialize AMM config" -- \ + spel --idl "$AMM_IDL" --program "$AMM_BIN" -- initialize \ + --config "$CONFIG" \ + --token-program-id "$TOKEN_PID" \ + --twap-oracle-program-id "$TWAP_PID" \ + --authority "$AMM_AUTHORITY" + +############################################################################### +# 7. Create the pool (seed initial liquidity) +############################################################################### +run_tx strict "create pool + seed liquidity" -- \ + spel --idl "$AMM_IDL" --program "$AMM_BIN" -- new-definition \ + --config "$CONFIG" \ + --pool "$POOL" \ + --vault-a "$VAULT_A" \ + --vault-b "$VAULT_B" \ + --pool-definition-lp "$POOL_LP" \ + --lp-lock-holding "$LP_LOCK" \ + --user-holding-a "$USER_HOLDING_A" \ + --user-holding-b "$USER_HOLDING_B" \ + --user-holding-lp "$USER_HOLDING_LP" \ + --current-tick-account "$TICK" \ + --clock "$CLOCK_ACCOUNT" \ + --token-a-amount "$POOL_TOKEN_A_AMOUNT" \ + --token-b-amount "$POOL_TOKEN_B_AMOUNT" \ + --fees "$POOL_FEES" \ + --deadline "$POOL_DEADLINE" + +############################################################################### +# 8. Verify the pool +############################################################################### +inspect "$AMM_IDL" "$POOL" "PoolDefinition" + +sec "Done" +log "${GRN}✅ Setup complete.${RST}" +kv "AMM program id" "$AMM_PID" +kv "TWAP program id" "$TWAP_PID" +kv "pool" "$POOL" +log "" +log "For the UI / swap test, set:" +log " ${DIM}AMM_PROGRAM_BIN=$REPO_ROOT/$AMM_BIN${RST}" +log " ${DIM}TOKENS_CONFIG (apps/amm/amm-tokens.json with def ids $TOKEN_A_DEF / $TOKEN_B_DEF)${RST}" From 7eabccee6204437e719a83574c7da943e700b4b8 Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Thu, 30 Jul 2026 11:25:09 +0000 Subject: [PATCH 2/7] test(amm-ui): bootstrap deterministic test wallet in testnet setup --- apps/amm/tests/testnet/setup-amm-testnet.sh | 214 +++++++++++++------- 1 file changed, 142 insertions(+), 72 deletions(-) diff --git a/apps/amm/tests/testnet/setup-amm-testnet.sh b/apps/amm/tests/testnet/setup-amm-testnet.sh index 92b88ac3..7f921744 100755 --- a/apps/amm/tests/testnet/setup-amm-testnet.sh +++ b/apps/amm/tests/testnet/setup-amm-testnet.sh @@ -8,27 +8,30 @@ # AMM UI swap test (apps/amm/tests/swap.mjs) exercises; run it once to stand up # a swappable pool, then launch the UI / run the test. # +# DETERMINISTIC TEST WALLET: by default the script bootstraps an ISOLATED wallet +# (git-ignored, under this folder) by restoring it from a fixed BIP-39 mnemonic +# and creating its accounts in a fixed order. The wallet's BIP-32 key tree makes +# those account ids reproducible across machines, so the whole team gets the +# same token/holding ids — and the script auto-writes apps/amm/amm-tokens.json +# from them for the UI. It never touches your personal ~/.lee/wallet. +# # Program IDs and all AMM PDAs (config, pool, vaults, LP, tick) are DERIVED at # runtime from the deployed binaries + the token definition accounts, so this # script stays correct even if you rebuild the guest binaries (new image id => -# new program id => new PDAs). Only the input accounts below are hand-picked. -# -# TEST WALLET (isolated): by default this script points the wallet at a -# dedicated, git-ignored home under this folder (apps/amm/tests/testnet/.wallet) -# so it never touches your personal ~/.lee/wallet. Override with TEST_WALLET_HOME. +# new program id => new PDAs). # -# Prerequisites (all managed by you, outside this script): +# Prerequisites (managed by you, outside this script): # - `wallet` and `spel` on PATH (from the SPEL toolchain) -# - a wallet initialized at TEST_WALLET_HOME, funded and synced, that OWNS the -# account ids configured below (see "TEST ACCOUNTS" — these must be derived -# from / created in the test wallet; see docs/testnet-runbook.md §2) +# - a reachable, funded sequencer (set TEST_SEQUENCER_ADDR, or pre-configure +# the wallet). Account creation is local, but deploys/mints need funds. # - `cargo` (to run the amm_pdas example) # - the guest .bin files already built (`make build-programs`) # - the IDL files under artifacts/ (`make idl`) # # Usage (from anywhere in the repo): # apps/amm/tests/testnet/setup-amm-testnet.sh -# TEST_WALLET_HOME=/tmp/lez-test-wallet apps/amm/tests/testnet/setup-amm-testnet.sh +# TEST_SEQUENCER_ADDR=http://127.0.0.1:8080 apps/amm/tests/testnet/setup-amm-testnet.sh +# FORCE_BOOTSTRAP=1 ... # re-restore the test wallet (rewrites its storage) # set -euo pipefail @@ -39,23 +42,31 @@ REPO_ROOT="${REPO_ROOT:-$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/ cd "$REPO_ROOT" ############################################################################### -# TEST WALLET — isolated from your personal wallet +# TEST WALLET — isolated + deterministic ############################################################################### # Dedicated wallet home for tests. Kept out of git (see .gitignore). Exported -# under both env var names so whichever the installed `wallet`/`spel` expects -# is satisfied. +# under both env var names so whichever the installed `wallet`/`spel` expects is +# satisfied (the current wallet uses LEE_WALLET_HOME_DIR). TEST_WALLET_HOME="${TEST_WALLET_HOME:-$SCRIPT_DIR/.wallet}" export LEE_WALLET_HOME_DIR="$TEST_WALLET_HOME" export NSSA_WALLET_HOME_DIR="$TEST_WALLET_HOME" -# The deterministic test mnemonic. A wallet restored from this seed always -# yields the same account ids, which is why the ids below can be pinned and -# shared with the team. Keep in sync with the wallet at TEST_WALLET_HOME. +# The deterministic test seed. A wallet restored from this mnemonic yields the +# same account ids every time, which is why they can be shared/pinned. TEST_MNEMONIC="${TEST_MNEMONIC:-test test test test test test test test test test test junk}" +TEST_WALLET_PASSWORD="${TEST_WALLET_PASSWORD:-test}" +TEST_WALLET_DEPTH="${TEST_WALLET_DEPTH:-3}" +# Optional: point the test wallet's config at your sequencer. Leave empty to use +# whatever the wallet home is already configured with. +TEST_SEQUENCER_ADDR="${TEST_SEQUENCER_ADDR:-}" + +# Deterministic accounts, created in THIS fixed order after a fresh restore so +# their ids are reproducible. Resolved to ids at runtime via `wallet account id`. +ACCOUNT_LABELS=(token-a-def token-a-holding token-b-def token-b-holding lp-holding) ############################################################################### -# CONFIG — edit these +# CONFIG — non-account parameters (edit freely) ############################################################################### # --- Program binaries (docker release builds; image ids must match deployment) --- @@ -67,38 +78,20 @@ TWAP_BIN="programs/twap_oracle/methods/guest/target/riscv32im-risc0-zkvm-elf/doc TOKEN_IDL="artifacts/token-idl.json" AMM_IDL="artifacts/amm-idl.json" -# --- TEST ACCOUNTS (must be owned by the wallet at TEST_WALLET_HOME) ---------- -# These are the deterministic accounts the test suite relies on. See the -# "Deterministic test accounts" note at the top of the file / the PR discussion: -# once the test wallet is restored from TEST_MNEMONIC, capture the ids it derives -# and pin them here so amm-tokens.json and swap.mjs can reference known accounts. - -# --- Token A --- -TOKEN_A_NAME="TOKEN A" -TOKEN_A_SUPPLY="1000000000000000000000" -TOKEN_A_DEF="6gQMF38wEDPEnUamLmNqN8opss5xvr9w55eddddMmpEK" # --definition-target-account -TOKEN_A_HOLDING="EF6c3VtgzUzpxfEKpvR3ZxsCch8y5YqazmWQu6Bybvyq" # --holding-target-account -TOKEN_A_MINT_AUTH="EF6c3VtgzUzpxfEKpvR3ZxsCch8y5YqazmWQu6Bybvyq" - -# --- Token B --- -TOKEN_B_NAME="TOKEN B" -TOKEN_B_SUPPLY="1000000000000000000000" -TOKEN_B_DEF="Hw65ZimauFtHtvmDvWb24aWi1E6uRCifdyEn46Ei8wAc" -TOKEN_B_HOLDING="L3hr1xABT3gkSYR1Fztu2smyJ1ftXcivjM8LguMjAsp" -TOKEN_B_MINT_AUTH="L3hr1xABT3gkSYR1Fztu2smyJ1ftXcivjM8LguMjAsp" - -# --- AMM / pool inputs --- -AMM_AUTHORITY="EF6c3VtgzUzpxfEKpvR3ZxsCch8y5YqazmWQu6Bybvyq" -USER_HOLDING_A="$TOKEN_A_HOLDING" -USER_HOLDING_B="$TOKEN_B_HOLDING" -USER_HOLDING_LP="7taJs6YpzBcWc5jiZcnZ817nU1G5WnQtBHskbcMDUc6A" -CLOCK_ACCOUNT="4BdcjoXkq786TMWcBGGHqcxeLYMZmn17rL4eM9ZyRWNU" +# --- Token metadata --- +TOKEN_A_NAME="TOKEN A"; TOKEN_A_SYMBOL="TKA"; TOKEN_A_SUPPLY="1000000000000000000000"; TOKEN_A_DECIMALS=18 +TOKEN_B_NAME="TOKEN B"; TOKEN_B_SYMBOL="TKB"; TOKEN_B_SUPPLY="1000000000000000000000"; TOKEN_B_DECIMALS=18 +# --- Pool inputs --- +CLOCK_ACCOUNT="4BdcjoXkq786TMWcBGGHqcxeLYMZmn17rL4eM9ZyRWNU" # canonical LEZ system clock POOL_TOKEN_A_AMOUNT="10000" POOL_TOKEN_B_AMOUNT="10000" POOL_FEES="1" POOL_DEADLINE="18446744073709551615" +# Where the UI token config is written (git-ignored; consumed via TOKENS_CONFIG). +TOKENS_CONFIG_OUT="apps/amm/amm-tokens.json" + ############################################################################### # Helpers ############################################################################### @@ -136,9 +129,6 @@ run_tx() { die "command exited with status $rc — $desc" fi - # The confirmation line printed by spel is: - # ✅ Transaction confirmed — included in a block. - # Match on the two stable substrings to be robust to emoji/dash encoding. if grep -q "Transaction confirmed" "$tmp" && grep -q "included in a block" "$tmp"; then log "${GRN}✅ CONFIRMED — included in a block: ${desc}${RST}" rm -f "$tmp" @@ -148,7 +138,7 @@ run_tx() { rm -f "$tmp" if [ "$mode" = "soft" ]; then log "${YEL}⚠ no '✅ Transaction confirmed — included in a block.' marker for: ${desc}" - log " (continuing — 'wallet deploy-program' may not print the spel marker; verify manually)${RST}" + log " (continuing — some commands don't print the spel marker; verify manually)${RST}" return 0 fi die "NOT CONFIRMED — expected '✅ Transaction confirmed — included in a block.' for: $desc" @@ -171,8 +161,47 @@ program_id() { printf '%s' "$pid" } +# Resolve a wallet account id (bare base58) from its label. Deterministic under +# the test mnemonic. Returns non-zero if the label isn't registered yet. +acct_id() { + local label="$1" out + out="$(wallet account id --account-id "$label" 2>/dev/null)" || return 1 + printf '%s' "$out" | grep -oE '[1-9A-HJ-NP-Za-km-z]{32,44}' | head -n1 +} + +# Restore the isolated test wallet from the fixed mnemonic and register the +# deterministic accounts. `restore-keys` REWRITES storage (safe here — it's a +# throwaway test home). Idempotent: skips accounts that already resolve. +bootstrap_test_wallet() { + sec "Bootstrap deterministic test wallet" + kv "wallet home" "$TEST_WALLET_HOME" + mkdir -p "$TEST_WALLET_HOME" + + if [ -n "$TEST_SEQUENCER_ADDR" ]; then + log "${DIM}\$ wallet config set sequencer_addr $TEST_SEQUENCER_ADDR${RST}" + wallet config set sequencer_addr "$TEST_SEQUENCER_ADDR" \ + || log "${YEL}⚠ 'wallet config set sequencer_addr' failed — configure the wallet manually.${RST}" + fi + + # restore-keys reads the mnemonic then the password from stdin. + log "${DIM}\$ printf '\\n\\n' | wallet restore-keys --depth $TEST_WALLET_DEPTH${RST}" + printf '%s\n%s\n' "$TEST_MNEMONIC" "$TEST_WALLET_PASSWORD" \ + | wallet restore-keys --depth "$TEST_WALLET_DEPTH" \ + || die "wallet restore-keys failed" + + local label + for label in "${ACCOUNT_LABELS[@]}"; do + if acct_id "$label" >/dev/null 2>&1; then + kv "exists" "$label" + else + log "${DIM}\$ wallet account new public --label $label${RST}" + wallet account new public --label "$label" || die "failed to create account: $label" + fi + done +} + ############################################################################### -# 0. Preflight +# 0. Preflight + wallet bootstrap ############################################################################### sec "Preflight" require_cmd wallet @@ -181,26 +210,47 @@ require_cmd cargo require_file "$TOKEN_BIN"; require_file "$AMM_BIN"; require_file "$TWAP_BIN" require_file "$TOKEN_IDL"; require_file "$AMM_IDL" kv "repo root" "$REPO_ROOT" -kv "test wallet home" "$TEST_WALLET_HOME" -if [ ! -d "$TEST_WALLET_HOME" ]; then - die "test wallet home not found: $TEST_WALLET_HOME - Initialize a wallet there from the test mnemonic, then create/pin the TEST - ACCOUNTS above. See docs/testnet-runbook.md §2. Mnemonic: - \"$TEST_MNEMONIC\"" +kv "token bin" "$TOKEN_BIN"; kv "amm bin" "$AMM_BIN"; kv "twap bin" "$TWAP_BIN" + +if [ ! -d "$TEST_WALLET_HOME" ] || [ "${FORCE_BOOTSTRAP:-0}" = "1" ]; then + bootstrap_test_wallet +else + kv "test wallet" "reusing $TEST_WALLET_HOME (FORCE_BOOTSTRAP=1 to re-restore)" fi -kv "token bin" "$TOKEN_BIN" -kv "amm bin" "$AMM_BIN" -kv "twap bin" "$TWAP_BIN" ############################################################################### -# 1. Deploy programs +# 1. Resolve the deterministic test accounts +############################################################################### +sec "Resolve deterministic test accounts (from the test mnemonic)" +TOKEN_A_DEF="$(acct_id token-a-def)" || die "token-a-def not registered — run with FORCE_BOOTSTRAP=1" +TOKEN_A_HOLDING="$(acct_id token-a-holding)" || die "token-a-holding not registered" +TOKEN_B_DEF="$(acct_id token-b-def)" || die "token-b-def not registered" +TOKEN_B_HOLDING="$(acct_id token-b-holding)" || die "token-b-holding not registered" +USER_HOLDING_LP="$(acct_id lp-holding)" || die "lp-holding not registered" +for v in TOKEN_A_DEF TOKEN_A_HOLDING TOKEN_B_DEF TOKEN_B_HOLDING USER_HOLDING_LP; do + [ -n "${!v}" ] || die "failed to resolve account id for $v" +done + +# Derived roles (the input holding signs; mint authority == holding; authority is the A holding). +TOKEN_A_MINT_AUTH="$TOKEN_A_HOLDING"; TOKEN_B_MINT_AUTH="$TOKEN_B_HOLDING" +AMM_AUTHORITY="$TOKEN_A_HOLDING" +USER_HOLDING_A="$TOKEN_A_HOLDING"; USER_HOLDING_B="$TOKEN_B_HOLDING" + +kv "token-a-def" "$TOKEN_A_DEF" +kv "token-a-holding" "$TOKEN_A_HOLDING" +kv "token-b-def" "$TOKEN_B_DEF" +kv "token-b-holding" "$TOKEN_B_HOLDING" +kv "lp-holding" "$USER_HOLDING_LP" + +############################################################################### +# 2. Deploy programs ############################################################################### run_tx soft "deploy token program" -- wallet deploy-program "$TOKEN_BIN" run_tx soft "deploy amm program" -- wallet deploy-program "$AMM_BIN" run_tx soft "deploy twap_oracle program" -- wallet deploy-program "$TWAP_BIN" ############################################################################### -# 2. Derive program IDs +# 3. Derive program IDs ############################################################################### sec "Program IDs (derived from the deployed binaries)" TOKEN_PID="$(program_id "$TOKEN_BIN")"; kv "token program id" "$TOKEN_PID" @@ -208,7 +258,7 @@ AMM_PID="$(program_id "$AMM_BIN")"; kv "amm program id" "$AMM_PID" TWAP_PID="$(program_id "$TWAP_BIN")"; kv "twap program id" "$TWAP_PID" ############################################################################### -# 3. Create token definitions (mint supply to the holding accounts) +# 4. Create token definitions (mint supply to the holding accounts) ############################################################################### run_tx strict "create fungible definition: $TOKEN_A_NAME" -- \ spel --idl "$TOKEN_IDL" --program "$TOKEN_BIN" -- new-fungible-definition \ @@ -225,7 +275,7 @@ run_tx strict "create fungible definition: $TOKEN_B_NAME" -- \ --mint-authority "$TOKEN_B_MINT_AUTH" ############################################################################### -# 4. Verify token definitions & holdings +# 5. Verify token definitions & holdings ############################################################################### inspect "$TOKEN_IDL" "$TOKEN_A_DEF" "TokenDefinition" inspect "$TOKEN_IDL" "$TOKEN_A_HOLDING" "TokenHolding" @@ -233,7 +283,7 @@ inspect "$TOKEN_IDL" "$TOKEN_B_DEF" "TokenDefinition" inspect "$TOKEN_IDL" "$TOKEN_B_HOLDING" "TokenHolding" ############################################################################### -# 5. Derive AMM PDAs from the program ids + token pair +# 6. Derive AMM PDAs from the program ids + token pair ############################################################################### sec "Deriving AMM PDAs (amm_pdas example)" log "${DIM}\$ cargo run -q -p amm_program --example amm_pdas -- $AMM_PID $TWAP_PID $TOKEN_A_DEF $TOKEN_B_DEF${RST}" @@ -262,13 +312,9 @@ kv "vault_b" "$VAULT_B" kv "pool_definition_lp" "$POOL_LP" kv "lp_lock_holding" "$LP_LOCK" kv "current_tick_account" "$TICK" -kv "user_holding_a" "$USER_HOLDING_A" -kv "user_holding_b" "$USER_HOLDING_B" -kv "user_holding_lp" "$USER_HOLDING_LP" -kv "clock" "$CLOCK_ACCOUNT" ############################################################################### -# 6. Initialize the AMM +# 7. Initialize the AMM ############################################################################### run_tx strict "initialize AMM config" -- \ spel --idl "$AMM_IDL" --program "$AMM_BIN" -- initialize \ @@ -278,7 +324,7 @@ run_tx strict "initialize AMM config" -- \ --authority "$AMM_AUTHORITY" ############################################################################### -# 7. Create the pool (seed initial liquidity) +# 8. Create the pool (seed initial liquidity) ############################################################################### run_tx strict "create pool + seed liquidity" -- \ spel --idl "$AMM_IDL" --program "$AMM_BIN" -- new-definition \ @@ -299,16 +345,40 @@ run_tx strict "create pool + seed liquidity" -- \ --deadline "$POOL_DEADLINE" ############################################################################### -# 8. Verify the pool +# 9. Verify the pool ############################################################################### inspect "$AMM_IDL" "$POOL" "PoolDefinition" +############################################################################### +# 10. Write the UI token config from the deterministic accounts +############################################################################### +sec "Write UI token config -> $TOKENS_CONFIG_OUT" +cat > "$TOKENS_CONFIG_OUT" < Date: Thu, 30 Jul 2026 14:04:06 +0000 Subject: [PATCH 3/7] test(amm-ui): isolate test token config, fix repo-root resolution --- apps/amm/.gitignore | 3 +++ apps/amm/tests/testnet/setup-amm-testnet.sh | 18 ++++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/apps/amm/.gitignore b/apps/amm/.gitignore index f7ad73a3..9ab39af4 100644 --- a/apps/amm/.gitignore +++ b/apps/amm/.gitignore @@ -11,3 +11,6 @@ tests/*.png # Isolated wallet home used by tests/testnet/setup-amm-testnet.sh tests/testnet/.wallet/ + +# Isolated token config written by tests/testnet/setup-amm-testnet.sh +tests/testnet/amm-tokens.json diff --git a/apps/amm/tests/testnet/setup-amm-testnet.sh b/apps/amm/tests/testnet/setup-amm-testnet.sh index 7f921744..2ec7be6a 100755 --- a/apps/amm/tests/testnet/setup-amm-testnet.sh +++ b/apps/amm/tests/testnet/setup-amm-testnet.sh @@ -38,7 +38,7 @@ set -euo pipefail # Resolve the repo root robustly regardless of where the script lives / is called # from. Prefer git; fall back to walking up from this script's directory. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -REPO_ROOT="${REPO_ROOT:-$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null || cd "$SCRIPT_DIR/../../../.." && pwd)}" +REPO_ROOT="${REPO_ROOT:-$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null || (cd "$SCRIPT_DIR/../../../.." && pwd))}" cd "$REPO_ROOT" ############################################################################### @@ -89,8 +89,11 @@ POOL_TOKEN_B_AMOUNT="10000" POOL_FEES="1" POOL_DEADLINE="18446744073709551615" -# Where the UI token config is written (git-ignored; consumed via TOKENS_CONFIG). -TOKENS_CONFIG_OUT="apps/amm/amm-tokens.json" +# Where the UI token config is written for TESTS ONLY (git-ignored). This is +# deliberately NOT apps/amm/amm-tokens.json — that file is your personal local +# config with your own accounts. Tests stay fully isolated: pass this path as +# TOKENS_CONFIG when launching the UI for a test run. +TOKENS_CONFIG_OUT="apps/amm/tests/testnet/amm-tokens.json" ############################################################################### # Helpers @@ -379,6 +382,9 @@ kv "AMM program id" "$AMM_PID" kv "TWAP program id" "$TWAP_PID" kv "pool" "$POOL" log "" -log "Launch the UI / run the swap test with:" -log " ${DIM}export LEE_WALLET_HOME_DIR=$TEST_WALLET_HOME${RST}" -log " ${DIM}AMM_PROGRAM_BIN=$REPO_ROOT/$AMM_BIN TOKENS_CONFIG=$REPO_ROOT/$TOKENS_CONFIG_OUT nix run .#amm-ui${RST}" +log "Launch the UI against the ISOLATED test wallet + test token config:" +log " ${DIM}LEE_WALLET_HOME_DIR=$TEST_WALLET_HOME \\${RST}" +log " ${DIM} AMM_PROGRAM_BIN=$REPO_ROOT/$AMM_BIN \\${RST}" +log " ${DIM} TOKENS_CONFIG=$REPO_ROOT/$TOKENS_CONFIG_OUT \\${RST}" +log " ${DIM} nix run .#amm-ui${RST}" +log "Then in another terminal: ${DIM}node apps/amm/tests/swap.mjs${RST}" From fc9f4c43dbe26f6c0eca00da52f3a18b653ec77d Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Thu, 30 Jul 2026 14:21:38 +0000 Subject: [PATCH 4/7] docs(amm-ui): document isolated UI test flow in tests/README.md --- apps/amm/README.md | 5 +++ apps/amm/tests/README.md | 71 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 apps/amm/tests/README.md diff --git a/apps/amm/README.md b/apps/amm/README.md index e9a893c4..5a0575be 100644 --- a/apps/amm/README.md +++ b/apps/amm/README.md @@ -232,6 +232,11 @@ selects two tokens, enters a sell amount, submits a swap end-to-end, and then verifies the pool reserves actually changed on-chain (read back from the sequencer via the app's `resolvePool`). +> **For the fully isolated, script-driven test flow** (a dedicated wallet from a +> fixed mnemonic + auto-created pool + isolated token config, touching nothing in +> your local setup), see **[`apps/amm/tests/README.md`](tests/README.md)**. The +> steps below run the test against *your own* local wallet/config instead. + The test framework itself — the `test()` / `run()` / `app.*` API that the tests import from `test-framework/framework.mjs` — comes from the [**`logos-co/logos-qt-mcp`**](https://github.com/logos-co/logos-qt-mcp) repo. diff --git a/apps/amm/tests/README.md b/apps/amm/tests/README.md new file mode 100644 index 00000000..efc7a158 --- /dev/null +++ b/apps/amm/tests/README.md @@ -0,0 +1,71 @@ +# AMM UI tests + +UI-driven tests for the AMM app. `swap.mjs` drives the running app through the +QML inspector (framework from +[`logos-co/logos-qt-mcp`](https://github.com/logos-co/logos-qt-mcp)): it selects +two tokens, enters an amount, submits a swap, and verifies the pool reserves +changed **on-chain**. + +## Isolation + +Test runs never touch your personal setup. Everything test-related lives under +`apps/amm/tests/testnet/` and is git-ignored: + +| Concern | Test (isolated) | Your local dev | +| --- | --- | --- | +| Wallet home | `apps/amm/tests/testnet/.wallet/` | `~/.lee/wallet/` | +| Token config | `apps/amm/tests/testnet/amm-tokens.json` | `apps/amm/amm-tokens.json` | + +`testnet/setup-amm-testnet.sh` bootstraps an isolated wallet from a **fixed +mnemonic** (`test test … junk`) so the token/holding account ids are +deterministic and reproducible across machines, then deploys the programs, +creates a seeded pool, and writes the test token config. + +## Full isolated run + +From the **repo root**, with `wallet` / `spel` / `cargo` / `nix` on `PATH`, a +local sequencer running, and the guest binaries built (`make build-programs`): + +```bash +# 0. Once: build the JS test framework (symlinked where swap.mjs expects it) +nix build .#test-framework -o apps/amm/result-mcp + +# 1. Bootstrap the isolated wallet + deploy programs + create the pool. +# Writes apps/amm/tests/testnet/{.wallet, amm-tokens.json}. Nothing else is touched. +TEST_SEQUENCER_ADDR=http://127.0.0.1:3040 apps/amm/tests/testnet/setup-amm-testnet.sh + +# 2. Terminal 1 — launch the UI against ONLY the isolated wallet + test tokens. +LEE_WALLET_HOME_DIR=$(pwd)/apps/amm/tests/testnet/.wallet \ + AMM_PROGRAM_BIN=$(pwd)/programs/amm/methods/guest/target/riscv32im-risc0-zkvm-elf/docker/amm.bin \ + TOKENS_CONFIG=$(pwd)/apps/amm/tests/testnet/amm-tokens.json \ + nix run .#amm-ui + +# 3. Terminal 2 — drive the swap test; watch it click through the live UI. +node apps/amm/tests/swap.mjs +``` + +Headless CI variant (no window, launches the app itself, pass/fail only): + +```bash +nix build .#integration-test -L +``` + +## Notes + +- **Wallet password.** The isolated wallet is restored with password `test` + (`TEST_WALLET_PASSWORD`). If the UI shows the **Connect** modal instead of + auto-opening, unlock with `test`. +- **Re-bootstrap.** `FORCE_BOOTSTRAP=1 apps/amm/tests/testnet/setup-amm-testnet.sh` + re-restores the isolated `.wallet` (rewrites only that directory). +- **Overrides.** `TEST_WALLET_HOME`, `TEST_MNEMONIC`, `TEST_WALLET_PASSWORD`, + `TEST_WALLET_DEPTH`, `TEST_SEQUENCER_ADDR` — see the script header. +- **Framework location.** `swap.mjs` loads `../result-mcp` by default; override + with `LOGOS_QT_MCP=/abs/path/to/result-mcp`. +- **Artifacts.** On failure `swap.mjs` prints the `SwapCard` state and saves + `apps/amm/tests/swap-*.png` (git-ignored) for inspection. + +## Files + +- `swap.mjs` — the end-to-end swap UI test. +- `testnet/setup-amm-testnet.sh` — isolated testnet + wallet bootstrap. +- `qml/`, `cpp/` — the module's own QML/C++ unit tests. From da225389132edca3a780bd170040652a1f7eb858 Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Thu, 30 Jul 2026 14:39:12 +0000 Subject: [PATCH 5/7] test(amm-ui): feed wallet setup password non-interactively --- apps/amm/tests/testnet/setup-amm-testnet.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/amm/tests/testnet/setup-amm-testnet.sh b/apps/amm/tests/testnet/setup-amm-testnet.sh index 2ec7be6a..a361973e 100755 --- a/apps/amm/tests/testnet/setup-amm-testnet.sh +++ b/apps/amm/tests/testnet/setup-amm-testnet.sh @@ -182,7 +182,12 @@ bootstrap_test_wallet() { if [ -n "$TEST_SEQUENCER_ADDR" ]; then log "${DIM}\$ wallet config set sequencer_addr $TEST_SEQUENCER_ADDR${RST}" - wallet config set sequencer_addr "$TEST_SEQUENCER_ADDR" \ + # On a fresh home this triggers first-time wallet setup, which prompts for a + # password (and generates a throwaway random seed). Feed the password via + # stdin so the bootstrap stays non-interactive; restore-keys below then + # replaces those keys with the deterministic test mnemonic. + printf '%s\n' "$TEST_WALLET_PASSWORD" \ + | wallet config set sequencer_addr "$TEST_SEQUENCER_ADDR" \ || log "${YEL}⚠ 'wallet config set sequencer_addr' failed — configure the wallet manually.${RST}" fi From 41d18c26f21a0c1b8deb38086c8fb586bcc5af32 Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Thu, 30 Jul 2026 15:03:24 +0000 Subject: [PATCH 6/7] docs(amm-ui): clarify test wallet password (throwaway setup vs restore-keys) --- apps/amm/tests/README.md | 12 +++++++++--- apps/amm/tests/testnet/setup-amm-testnet.sh | 16 +++++++++------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/apps/amm/tests/README.md b/apps/amm/tests/README.md index efc7a158..62fdf8fb 100644 --- a/apps/amm/tests/README.md +++ b/apps/amm/tests/README.md @@ -52,9 +52,15 @@ nix build .#integration-test -L ## Notes -- **Wallet password.** The isolated wallet is restored with password `test` - (`TEST_WALLET_PASSWORD`). If the UI shows the **Connect** modal instead of - auto-opening, unlock with `test`. +- **Wallet password.** The wallet's key storage is encrypted with a password, + which you enter to **unlock** the wallet so the app can sign transactions (the + UI's **Connect** modal). During first-time setup you're prompted once for a + password (read from the terminal — it can't be scripted), but **that wallet is + a throwaway**: `restore-keys` then rebuilds it from the test mnemonic and sets + the **real** password to `TEST_WALLET_PASSWORD` (default `test`). So type + anything at the setup prompt; **unlock the UI with `test`** — not whatever you + typed there. Prefer no password? Run with `TEST_WALLET_PASSWORD=""` and unlock + with an empty password everywhere. - **Re-bootstrap.** `FORCE_BOOTSTRAP=1 apps/amm/tests/testnet/setup-amm-testnet.sh` re-restores the isolated `.wallet` (rewrites only that directory). - **Overrides.** `TEST_WALLET_HOME`, `TEST_MNEMONIC`, `TEST_WALLET_PASSWORD`, diff --git a/apps/amm/tests/testnet/setup-amm-testnet.sh b/apps/amm/tests/testnet/setup-amm-testnet.sh index a361973e..c522f9d0 100755 --- a/apps/amm/tests/testnet/setup-amm-testnet.sh +++ b/apps/amm/tests/testnet/setup-amm-testnet.sh @@ -182,16 +182,18 @@ bootstrap_test_wallet() { if [ -n "$TEST_SEQUENCER_ADDR" ]; then log "${DIM}\$ wallet config set sequencer_addr $TEST_SEQUENCER_ADDR${RST}" - # On a fresh home this triggers first-time wallet setup, which prompts for a - # password (and generates a throwaway random seed). Feed the password via - # stdin so the bootstrap stays non-interactive; restore-keys below then - # replaces those keys with the deterministic test mnemonic. - printf '%s\n' "$TEST_WALLET_PASSWORD" \ - | wallet config set sequencer_addr "$TEST_SEQUENCER_ADDR" \ + # NOTE: on a fresh home this triggers first-time wallet setup, which + # generates a THROWAWAY random-seed wallet and prompts once for a password + # (read from the terminal, so it can't be piped — just type anything, even + # empty). That wallet is immediately discarded: restore-keys below rebuilds + # the wallet from the test mnemonic and sets the REAL password to + # $TEST_WALLET_PASSWORD, which is what unlocks the wallet afterward. + wallet config set sequencer_addr "$TEST_SEQUENCER_ADDR" \ || log "${YEL}⚠ 'wallet config set sequencer_addr' failed — configure the wallet manually.${RST}" fi - # restore-keys reads the mnemonic then the password from stdin. + # restore-keys reads the mnemonic then the password from stdin (non-interactive) + # and REWRITES storage — so the wallet's password becomes $TEST_WALLET_PASSWORD. log "${DIM}\$ printf '\\n\\n' | wallet restore-keys --depth $TEST_WALLET_DEPTH${RST}" printf '%s\n%s\n' "$TEST_MNEMONIC" "$TEST_WALLET_PASSWORD" \ | wallet restore-keys --depth "$TEST_WALLET_DEPTH" \ From c550eeaffb087f08f17fda1d6b7785d9ed45a9a2 Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Thu, 30 Jul 2026 15:09:21 +0000 Subject: [PATCH 7/7] test(amm-ui): feed setup password via stdin so bootstrap never blocks --- apps/amm/tests/README.md | 17 ++++++++--------- apps/amm/tests/testnet/setup-amm-testnet.sh | 14 +++++++------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/apps/amm/tests/README.md b/apps/amm/tests/README.md index 62fdf8fb..b316c6b6 100644 --- a/apps/amm/tests/README.md +++ b/apps/amm/tests/README.md @@ -52,15 +52,14 @@ nix build .#integration-test -L ## Notes -- **Wallet password.** The wallet's key storage is encrypted with a password, - which you enter to **unlock** the wallet so the app can sign transactions (the - UI's **Connect** modal). During first-time setup you're prompted once for a - password (read from the terminal — it can't be scripted), but **that wallet is - a throwaway**: `restore-keys` then rebuilds it from the test mnemonic and sets - the **real** password to `TEST_WALLET_PASSWORD` (default `test`). So type - anything at the setup prompt; **unlock the UI with `test`** — not whatever you - typed there. Prefer no password? Run with `TEST_WALLET_PASSWORD=""` and unlock - with an empty password everywhere. +- **Wallet password.** The wallet's key storage is encrypted with a password — + the one you enter to **unlock** it (the UI's **Connect** modal) so the app can + sign transactions. First-time setup reads a throwaway password (the script + feeds it via stdin, so it doesn't block), then `restore-keys` rebuilds the + wallet from the test mnemonic and sets the **real** password to + `TEST_WALLET_PASSWORD` (default `test`). So **unlock the UI with `test`**. + Prefer no password? Run with `TEST_WALLET_PASSWORD=""` and unlock with an empty + password. - **Re-bootstrap.** `FORCE_BOOTSTRAP=1 apps/amm/tests/testnet/setup-amm-testnet.sh` re-restores the isolated `.wallet` (rewrites only that directory). - **Overrides.** `TEST_WALLET_HOME`, `TEST_MNEMONIC`, `TEST_WALLET_PASSWORD`, diff --git a/apps/amm/tests/testnet/setup-amm-testnet.sh b/apps/amm/tests/testnet/setup-amm-testnet.sh index c522f9d0..65155a55 100755 --- a/apps/amm/tests/testnet/setup-amm-testnet.sh +++ b/apps/amm/tests/testnet/setup-amm-testnet.sh @@ -182,13 +182,13 @@ bootstrap_test_wallet() { if [ -n "$TEST_SEQUENCER_ADDR" ]; then log "${DIM}\$ wallet config set sequencer_addr $TEST_SEQUENCER_ADDR${RST}" - # NOTE: on a fresh home this triggers first-time wallet setup, which - # generates a THROWAWAY random-seed wallet and prompts once for a password - # (read from the terminal, so it can't be piped — just type anything, even - # empty). That wallet is immediately discarded: restore-keys below rebuilds - # the wallet from the test mnemonic and sets the REAL password to - # $TEST_WALLET_PASSWORD, which is what unlocks the wallet afterward. - wallet config set sequencer_addr "$TEST_SEQUENCER_ADDR" \ + # On a fresh home the first wallet command triggers one-time setup, which + # reads a password from STDIN ("Input password:") and generates a THROWAWAY + # random-seed wallet. Feed the password so it never blocks; restore-keys + # below immediately rewrites storage from the test mnemonic and sets the real + # password to $TEST_WALLET_PASSWORD. + printf '%s\n' "$TEST_WALLET_PASSWORD" \ + | wallet config set sequencer_addr "$TEST_SEQUENCER_ADDR" \ || log "${YEL}⚠ 'wallet config set sequencer_addr' failed — configure the wallet manually.${RST}" fi