33 Commits
Author SHA1 Message Date
r4bbit 3994ba3055 feat(apps/amm): let users pick which LP account to remove from
The remove-liquidity sheet burned from a single LP holding the detail page
picked. A pool position can span several LP accounts (each add mints a
fresh one), so add a "Remove from" account selector above the actions:
picking an account repoints the burn and re-prices for its balance, so the
percentage, the previewed A/B amounts, and the slippage floors all follow
the chosen holding. It defaults to the largest holding.

PoolDetailPage passes the pool's LP holdings (encoding-tolerant match) into
the dialog; the selector filters them by account type and drives
lpHoldingId + lpBalance on selection.

Extend the remove-liquidity e2e test to assert the selector renders,
preselects a real holding, and that the dialog's burn account tracks it.
2026-08-25 12:48:36 +02:00
r4bbit 68c0e9cd23 test(apps/amm): add remove-liquidity e2e test
Drive the full remove-liquidity flow through the QML inspector: open the
wallet's seeded A/B position from the positions view, use the Manage
dropdown to open the remove sheet, withdraw 50% (the slider default),
submit, and verify the A/B pool reserves shrank on-chain.

Give the Manage trigger an objectName (poolDetailManageButton) so the
test can open the dropdown via its openMenu().
2026-08-25 11:17:08 +02:00
r4bbit 62d133e909 feat(amm): let LPs choose the LP-token destination account
Add-liquidity minted a fresh LP account every time, fragmenting a position
across holdings. The New position form now has an LP-destination selector (the
same Input-mode component as the token funding rows): add-liquidity preselects
the wallet's existing LP holding so deposits consolidate, while create-pool has
none and mints a fresh one.

- addLiquidityQuote returns lpDefinitionId (base58) so the form matches holdings
- createPool/addLiquidity submit into the chosen holding, else create-fresh
- e2e: add-liquidity waits for the preselect; create-pool asserts fresh-account
2026-08-21 15:35:27 +02:00
r4bbit 4cb7c7e51c refactor(amm): drop the Raw suffix from amount/value field names
The `*Raw` suffix on the module's amount/price/balance/LP fields was
redundant — every such field is already a base-unit integer, and there was
no formatted sibling to disambiguate from. Drop it across the whole wire
contract in lockstep: the amm_ffi request/response fields (snake_case
`amount_in_raw` → `amount_in`, serde `rename_all="camelCase"` keeps the JSON
keys mapped), the C++ module API, the QtRO `.rep`, the QML/app that consumes
it, the mjs tests, and the module README.

Examples: expectedOutRaw→expectedOut, minReceivedRaw→minReceived,
maxInRaw→maxIn, requiredInRaw→requiredIn, priceRaw→price, reserve{A,B}Raw→
reserve{A,B}, amount{In,Out}Raw→amount{In,Out}, expectedLpRaw→expectedLp,
lpAmountRaw→lpAmount, {max,min,minimum,actual}Amount{A,B}Raw, minimumLpRaw,
minLpRaw, selectedBalance*Raw, totalSupplyRaw, quote*Raw. This also unifies a
pre-existing inconsistency where resolvePoolAccount already emitted `reserveA`
and resolveTokens already emitted `balance`.

Kept where a formatted UI sibling of the same base name exists, so `Raw`
still disambiguates the base-unit value: amountARaw / amountBRaw (vs the
user-input `amountA`/`amountB`), balanceRaw (vs display `balance`), and
initialPriceRaw (vs formatted `initialPrice`). Also kept the format-boundary
helpers formatRaw / rawLpText / probeRaw / displayRaw / displayQuoteRaw /
boundRaw.

BREAKING: the `amm_module` public API field names change (logoscore /
Basecamp / QtRO consumers must update).
2026-08-21 08:11:58 +02:00
r4bbit 99ea6805df feat(apps/amm): introduce positions view
This view allows the user to manage their positions.
2026-08-20 19:52:35 +02:00
r4bbit 06d7119a97 feat(apps/amm): add a pool detail view reached from the Pools list 2026-08-20 15:39:40 +02:00
r4bbit cbb75c38fd refactor(amm): remove the dead Network/context machinery
The liquidity token surface moved app-side (resolveTokens + custom tokens),
leaving the whole newPositionContext path dormant. Delete it end to end and
point the swap methods at the same lean program-id helper everything else uses.
2026-08-13 16:17:58 +02:00
r4bbit 7a7ebfdbaf feat(amm): source liquidity tokens app-side + add custom tokens by id
Move the liquidity token selector off the module's stateful newPositionContext
onto a lean, app-owned surface, and let users add unlisted tokens by id.

FFI: new stateless `resolve_tokens` op — the app passes an explicit id set and
gets uniform selector rows `{ definitionId (base58), name, totalSupply, holdingId,
balance }`, held tokens first, unresolvable/non-fungible ids omitted. Reuses the
per-token definition/holding logic from `context`, without the network/status
envelope. Unit-tested.

Module: `resolveTokens(request, wallet_open)` reads the definitions + wallet and
calls the op (ids wrapped in a map — the universal-module glue only marshals
map/scalar inputs, not bare lists).

Backend: the app owns the id set — configured tokens (TOKENS_CONFIG) plus the
user's persisted custom ids. Held-but-unlisted tokens are NOT auto-listed (the
list mirrors the swap side); a token you hold still shows its balance once listed.
`addCustomToken` validates a pasted id by resolving its on-chain definition, then
persists it to CUSTOM_TOKEN_CONFIG (defaulting to the per-user app-data store, with
a HOME fallback so persistence never silently no-ops on an empty path).

QML: NewPositionForm/LiquidityPage take tokens/walletReady/loadingTokens as inputs
and drive selection + custom-token resolution through the backend; dropped all
newPositionContext reads and the selectable/status/code row fields.

Tests: custom-token.mjs creates token D on-chain (left out of the token config)
and verifies pasting its id resolves, selects, and persists it across a reload.
The setup script mints token D and initializes/prints the isolated
CUSTOM_TOKEN_CONFIG store
2026-08-13 15:33:31 +02:00
Ricardo Guilherme Schmidt 4cfc03a815 feat(apps/amm): drive the Pools list from AMM_POOLS_CONFIG
The Pools page shipped with a hardcoded four-pair sample. Replace it with a
config-driven "known pools" list, mirroring how the Swap token picker reads
TOKENS_CONFIG: the app loads a flat JSON array from the AMM_POOLS_CONFIG
environment variable and renders one row per entry. Adding pairs is a config
edit — no app change.

Pool discovery is an app concern, so the config is read in the backend
(AmmUiBackend::poolList, Qt JSON) rather than the amm_module — the module is
shedding app-specific view surface (tokenList/newPositionContext), so pools go
where tokens are heading, not where they are today. poolList() fails soft to an
empty list when AMM_POOLS_CONFIG is unset/unreadable/not an array, and skips
individual entries missing tokenA/tokenB/a numeric feeBps.

Each entry carries the display symbols (tokenA/tokenB), feeBps, and the on-chain
identifiers (poolId, tokenADefinitionId, tokenBDefinitionId) so a row can later
be resolved against chain state. PoolsPage takes injected backend/runtime and
loads via runtime.watch(backend.poolList()); the Repeater renders entries
generically.

The AMM testnet setup script now emits amm-pools.json from a POOL_SPECS array
(one line per seeded pool, currently the seeded TKA/TKB pool) and prints
AMM_POOLS_CONFIG in the launch instructions. Adds amm-pools.json.example, a
README section, and gitignores the runtime config files.
2026-08-13 14:13:31 +02:00
r4bbit c47f387ad4 refactor(amm): rename the create-pool quote surface for symmetry
Two naming cleanups on the create-pool quote, aligning it with the add / remove
counterparts (per modules/amm/INTERFACE.md). Pure renames — no behavior change.

- `liquidityQuote` → `createPoolQuote` across the stack: the FFI op
  (`liquidity_quote` → `create_pool_quote`, `LiquidityQuoteRequest` →
  `CreatePoolQuoteRequest`, `amm_liquidity_quote` → `amm_create_pool_quote`,
  cbindgen header regenerated), the module method, the AmmUiBackend slot, and the
  QML call site. It really is the create-pool quote — `addLiquidityQuote` /
  `removeLiquidityQuote` are the other branches — so the old name misled.
- `initialPriceRealRaw` → `priceRaw` (request field `initial_price_real_raw` →
  `price_raw`): drops the legacy "Real" and unifies the price key with the add /
  remove quotes, which already return `priceRaw`. Create, add, and remove quotes
  now all speak `priceRaw`; the create-vs-add routing in NewPositionFlow keys on
  `request.priceRaw`.
2026-08-13 13:25:20 +02:00
Ricardo Guilherme Schmidt 574d814f48 fix(amm): restore liquidity controls after refresh 2026-08-13 13:24:16 +02:00
r4bbit 64e7614e74 refactor(amm): remove the dead newPosition quote path
Both liquidity branches now quote through the lean ops (liquidityQuote /
addLiquidityQuote), so quoteNewPosition and the heavy amm_quote machinery it
drove are unreachable. Remove them end to end.

FFI (modules/amm/ffi):
- Drop the amm_quote entry point and the whole quote-evaluation graph:
  api/{accounts,commitment,funding,position}.rs, the QuoteRequest /
  PositionRequest / PairSnapshot request types, quote_error::fatal_quote, and
  api/clock.rs (its decode_clock was quote-only). quote.rs keeps only the shared
  opening-deposit math (minimum_opening_pair + helpers) that liquidity_quote
  reuses.
- Trim the fields the quote path was the sole reader of: SelectedHolding.account
  and PairIds.{token_program,twap_program}.
- Drop the quote-path unit tests; keep the math / pair / context / holding /
  swap ones (37 pass, clippy clean).

Module (modules/amm/src):
- Remove AmmModuleImpl::quoteNewPosition and its buildQuoteInput snapshot helper.

App (apps/amm):
- Remove the AmmUiBackend quoteNewPosition slot (.rep/.h/.cpp) and the dead QML
  backend mock + obsolete fresh-quote test.
- finishSubmitFailure no longer keeps a submit-returned re-quote (the lean submit
  ops never return one); it always re-quotes on failure.
- submissionSnapshot drops the always-empty quoteHash and derives the confirm
  dialog's action from the resolved pool state instead of the dead
  quotePayload.instruction (restores the "Create pool" / "Add liquidity" label).
2026-08-11 17:51:51 +02:00
r4bbit eb98aac31f feat(amm): drive the create-pool liquidity preview from liquidityQuote
Both liquidity branches now quote through the lean composable ops. The create
path joins the add path (already on addLiquidityQuote) by reworking
liquidity_quote into a dual-mode create quote and wiring the form to it via
the resolvePool pool read. quoteNewPosition/amm_quote are no longer reached
from the UI.

FFI (modules/amm/ffi):
- liquidity_quote is dual-mode: price-only (initialPriceRealRaw, no amounts)
  returns the minimum opening deposit via minimum_opening_pair; supplied
  amounts return the actual deposit with the price derived from them. Emits
  actual/minimum amounts, expectedLp, lockedLp and the Q64.64 price.
- LiquidityQuoteRequest gains initial_price_real_raw (Option<String>, needed
  only in price-only mode).

Module (modules/amm/src):
- liquidityQuote forwards initialPriceRealRaw to the op.

UI (apps/amm/qml):
- Route create-vs-add on the pool read (resolvePool -> poolExists); create
  quotes via liquidityQuote, assembled into the missing-pool shape the form
  already consumes.
- poolStatus moves off the quote onto the flow's poolExists; the form derives
  activePool/missingPool from it. Trim the vestigial quote fields (canSubmit,
  requiresFreshLp, warnings, errors[], accountPreview, the "Pool" row) and drop
  the account-plan panel for parity with the swap view.
- Fix a real bug: a pair change now resets poolExists (resetPoolExistence) so
  resetPairDraft re-resolves the pool like a fresh selection. Otherwise an
  active pool kept stale (cleared) reserves with no re-quote, and the deposit
  ratio-fill silently no-op'd.

Tests (apps/amm/tests):
- Read activePool instead of the removed poolStatus. The add test waits for the
  reset's active-pool quote to settle (reserves reloaded) before the ratio-fill;
  the create test resets the draft to clear leftover cross-run amounts and the
  stale submitted transactionId.
2026-08-11 17:51:51 +02:00
r4bbit b1b6ec8517 refactor(amm): remove the dead submitNewPosition path
Now that add-liquidity and pool creation submit via addLiquidity / createPool,
the legacy submitNewPosition path is dead. Remove it end to end.

App backend (AmmUiBackend):
- Drop the submitNewPosition slot/method and its newPositionError helper.

Module (AmmModuleImpl):
- Drop submitNewPosition, the m_requestPending guard, and the now-orphaned
  nowMs/parseU64 helpers (+ the <chrono> include).

FFI (amm_ffi) — the plan op only submitNewPosition called:
- Delete plan.rs; remove amm_plan (extern + regenerated header), api::plan,
  and PlanRequest.
- Remove the plan-only machinery it fed: QuoteBranch, NewPositionPlan,
  EvaluatedQuote.plan/quote_hash, and AccountPlan's wallet_args /
  requires_fresh_lp / contains / validate_ready, plus the plan construction
  in quote.rs.
- Tests: drop the plan-only tests/helpers; keep quote coverage by trimming
  the mixed tests to their quote assertions.

QML tests (tst_LiquidityPage):
- Remove the two legacy-submit tests (base58-only success) + the
  submitNewPosition mock and its now-unused fixtures. Keep the
  finishSubmitFailure test (unchanged behaviour).

quoteNewPosition and its machinery (amm_quote, buildQuoteInput, PairSnapshot,
AccountPlan preview/sources, commitment) stay — they retire with the legacy
quoting in the quote-migration vertical.
2026-08-11 17:51:51 +02:00
r4bbit 71fb18c50f feat(apps/amm): wire the add-liquidity submit end-to-end
Migrate the active-pool branch of the liquidity form onto the new addLiquidity
op (quoting stays on legacy quoteNewPosition for now, as agreed).

- AmmUiBackend: add the addLiquidity QtRO slot; forwards to the module and
  refreshes balances (mirrors createPool).
- NewPositionFlow: route the active-pool confirm to addLiquidity, minting a
  fresh LP holding then submitting {tokenA/B, holdingA/B, lpHolding, maxAmountA/B,
  minLpRaw, deadline}. minLpRaw comes from the legacy quote's minimumLpRaw.
- NewPositionForm: show the per-side account selectors in add mode; gate the CTA
  on both holdings and on the deposit amounts being present (hasDepositAmounts) —
  the pair's probe quote otherwise reports canSubmit on simulated amounts and
  wrongly enables the button before any amount is entered.
- amm_ffi: fix add_liquidity_plan to orient the (max amount, holding) pair to the
  pool's STORED definition order, not is_canonical_pair — a pool created outside
  the FFI (the testnet setup's spel new-definition) can store a non-canonical
  order, which otherwise sent a holding into the wrong vault (Transfer
  sender/recipient definition mismatch). Test uses a non-canonical pool.

Adds add-liquidity.mjs: asserts the CTA stays disabled with no amounts, submits
an add to the seeded A/B pool, and verifies reserveA grew on-chain.
2026-08-11 17:51:51 +02:00
r4bbit b1b4631234 feat(apps/amm): pick the token account per side when creating a pool
Add per-side account selectors to the create-pool form, sourced from the
wallet's token holdings, so a user holding a token in several accounts chooses
which funds each deposit. A single holding auto-selects.

Mirrors the swap card: the selector lives inside the token input card, below
the token button. AmmTokenAmountSurface gains an optional footer slot (unchanged
when unset, so add-liquidity renders as before); TokenAmountInput fills it with a
ProgramAccountSelector filtered on the token's base58 definitionId.

- LiquidityPage fetches backend.tokenHoldings(), refetching when the wallet opens
- NewPositionForm routes the chosen holdings into submissionSnapshot's createPool
  call; canConfirm now requires both holdings when creating a pool (add-liquidity
  is untouched — it enumerates holdings server-side)
- create-pool.mjs selects the funding account for each side before submitting
2026-08-11 12:04:48 +02:00
r4bbit 86575a65aa test(apps/amm): select the funding account before submitting a swap
canSubmit now requires a chosen holding on both swap sides, so the swap e2e
test must select them first. The selector auto-selects a single holding, but
pick it explicitly (robust to multi-account wallets) via a new selectAccount
step that waits for the holdings to load and selects the first match.

Expose each side's selector via selectorObjectName (swapSell/BuyAccountSelector)
and surface sellHolding/buyHolding in the failure diagnostics.
2026-08-11 12:04:48 +02:00
r4bbit 02e77032b7 test(apps/amm): add create-pool UI e2e test + Token C setup
- setup-amm-testnet.sh: mint a third token (TKC), appended to ACCOUNT_LABELS so
  the deterministic a/b/lp ids don't shift and left unseeded (only A/B is created)
  for the test to create the A/C pair. Split wallet restore from account
  registration (ensure_accounts always runs) so adding a token needs no re-restore.
- create-pool.mjs: drives the Liquidity view to create the A/C pool, then verifies
  it on-chain via the swap card's resolvePool. evaluate() fallbacks for the
  submit/confirm buttons (synthetic clicks aren't reliable on QtQuick Buttons).
- Adds test-hook objectNames (newPositionSubmitButton, liquidityConfirmDialog).
2026-08-11 12:04:48 +02:00
r4bbit e1398ffcad feat(apps/amm): create pools via the new createPool op; drop the pool-watch poll
Route pool creation through the redesigned createPool op and retire the old
create-flow machinery. Add-liquidity stays on the legacy submitNewPosition.

Module (amm_module):
- createPool becomes a single-param envelope: it reads the caller-provided
  lpHoldingId from the request (a new pool has no pre-existing LP holding),
  dropping the requires-fresh-lp handshake — the module never creates wallet
  accounts. Returns { status, error, transactionId }; unlike the swaps, a
  submit failure carries a code so the UI can explain why.

Backend (AmmUiBackend):
- Expose liquidityQuote (read-only preview) and createPool slots. createPool
  guards on the app's wallet-open state, forwards the request, and refreshes
  balances on success. No account creation here.

UI (liquidity flow/form):
- NewPositionFlow.confirm() branches on the missing-pool signal: create ->
  createPool (mint a fresh public LP account via createAccountPublic, then
  submit); add -> unchanged submitNewPosition. Hex transactionId accepted.
- submissionSnapshot supplies canonical-order holdingAId/holdingBId.
- (liquidityQuote is wired to the backend but the create preview still rides
  the legacy quote for now.)

Cleanup: the pool-creation confirmation poll is orphaned now that create no
longer submits via submitNewPosition. It polled the pool account by re-quoting
until poolStatus flipped to active_pool — a stopgap for the missing
transactionStatus/poll_tx on the lez module. Removed pendingPoolProbes,
poolPoller, watchPoolCreation, pollPendingPool, finishPoolProbe,
rotate/removePendingPool, pairKey, matchesSelectedPair,
selectedPoolCreationPending, poolActivated, the poolCreationPending state,
acceptPoolActivation, and their now-obsolete tests.
2026-08-11 12:04:48 +02:00
r4bbit 37c2f294ac feat(apps/amm): drive the exact-input swap preview from swapExactInQuote
Wire the Sell direction of the swap card to the module's server-side quote
instead of the client-side DummySwapState estimate. AmmUiBackend gains a
swapExactInQuote(tokenIn, tokenOut, amountInDecimal, slippageBps) slot that
forwards to amm_module and returns { expectedOutRaw, minReceivedRaw,
priceImpactBps } (read-only, no wallet guard).

SwapCard debounces a swapExactInQuote call as the user types a Sell amount and
sources the expected output, min received, and price impact from it. The exact
figures shown (buy field, confirmation snapshot) and the submitted min_out come
straight from the quote's raw integer strings, so the preview can't drift from
execution and the client no longer orients reserves (fixes the #236 defAHex
bug) or recomputes min_out in double/BigInt. A retyped amount invalidates the
quote immediately and blocks submit until the re-quote lands.

The Buy direction is unchanged — still a local DummySwapState preview, pending
the exact-output wiring. resolvePool stays as the source of pool existence, the
fee row, and the Buy-side reserves.
2026-08-06 23:15:01 +02:00
Andrea Franz 200f429ec6 test(amm-ui): feed setup password via stdin so bootstrap never blocks 2026-08-05 17:19:38 +02:00
Andrea Franz c5b9508e4d docs(amm-ui): clarify test wallet password (throwaway setup vs restore-keys) 2026-08-05 17:19:38 +02:00
Andrea Franz 0576b10dcb test(amm-ui): feed wallet setup password non-interactively 2026-08-05 17:19:38 +02:00
Andrea Franz 191942f2a8 docs(amm-ui): document isolated UI test flow in tests/README.md 2026-08-05 17:19:38 +02:00
Andrea Franz 2ed13506d1 test(amm-ui): isolate test token config, fix repo-root resolution 2026-08-05 17:19:38 +02:00
Andrea Franz 9a1f76ff6b test(amm-ui): bootstrap deterministic test wallet in testnet setup 2026-08-05 17:19:38 +02:00
Andrea Franz 380bbff308 test(amm-ui): add isolated AMM testnet setup script 2026-08-05 17:19:38 +02:00
Andrea Franz fc7b07174c test(amm-ui): add swap UI test 2026-08-05 17:19:38 +02:00
r4bbit afeba568d8 refactor(amm): drop the new-position schema version tag
The add-liquidity flow stamped a `new-position.v1` schema tag on every
request and response and validated it across all three layers — the QML
plugin, the amm_module core module, and the amm_client Rust crate. It was a
cross-version compatibility guard, but these artifacts always ship together,
so the contract is honored implicitly, and the swap view already works fine
without one. Dropping it makes the liquidity view consistent with swap and
removes a layer of ceremony.

- amm_client: remove PositionRequest.schema and the unsupported_schema check
  in compute_quote; drop QuoteCommitment.schema (changes quoteHash, which is
  internal-only) and every "schema" response stamp; delete the SCHEMA /
  NEW_POSITION_SCHEMA constants and the public export.
- amm_module: remove the SCHEMA constant and its four response stamps.
- AmmUiBackend: remove its local NEW_POSITION_SCHEMA and the stamps in
  loadingContext() / newPositionError().
- QML: drop the "schema" fields from the request/envelope builders and relax
  the validity gates to check status / canSubmit instead (the sole check in
  NewPositionFlow now guards on a missing `status`); strip the now-dead
  schema fields from the liquidity QML test fixtures.
- Also removes the last stale comment references to the deleted *Runtime
  classes.
2026-08-03 23:01:53 +02:00
r4bbit 72b330122d feat(amm): move all AMM logic into the amm_module core module; flip UI to consume it
Introduce modules/amm — the AMM business logic as a universal core Logos module,
consumed identically by the QML UI (via modules().amm_module) and headlessly
(logoscore call amm_module ...). The module is a thin transport adapter: the
domain math lives in the Rust amm_client crate (the transport-independent JSON
FFI), and the module sequences those pure ops with chain I/O delegated to the
logos_execution_zone wallet module. It reaches the same shared wallet instance
the UI opened (Basecamp loads core modules as singletons; standalone the
LogosAPI client cache dedups the connection), so it never opens a second wallet.

The module owns the full AMM surface — not just swaps:
- resolvePool / swapExactInput / tokenList (the swap path)
- newPositionContext / quoteNewPosition / submitNewPosition (add-liquidity)

apps/amm: delete the app-side orchestration (SwapRuntime, NewPositionRuntime,
AmmClient/BundledAmmClient) and the amm_client link. AmmUiBackend now owns only
wallet-session lifecycle and forwards every AMM slot to modules().amm_module.
The one wallet-keyset mutation add-liquidity needs — creating a fresh LP holding
— stays in the backend (via its wallet provider, keeping the account model and
on-disk storage coherent): the module returns "requires_fresh_lp" without
submitting, the backend creates the account and resubmits with its id.

flake.nix / CMakeLists / metadata: the module links the amm_client crate; the UI
links no external lib and depends on amm_module (injected into the UI builder's
flakeInputs so the dependency resolves).

- amounts/deadline declared nlohmann::json so the generated dispatch accepts a
  JSON number (bare small ints on the CLI) or a string (exact u128 from the UI,
  or a quote-wrapped big value on the CLI); JSON floats are rejected rather than
  submit a silently-rounded amount.
- AMM_DEBUG-gated tracing for the swap path.
- Drop tests/cpp/NewPositionRuntimeTest.cpp with the class it covered
  (module-level tests to follow).
- modules/amm/README.md: architecture, headless prerequisites, logoscore recipe.
2026-08-03 23:01:53 +02:00
r4bbit e585489a60 factor(amm-ui): source new-position network context from AMM_PROGRAM_BIN/TOKENS_CONFIG/wallet
The create-pool / new-position flow carried its own network layer:
AMM_UI_NETWORK + AMM_UI_DEVNET_FILE (a devnet.json) or a bundled
config/networks.json supplied the AMM program id and token set, and a
JSON-RPC channel/checkpoint "identity probe" gated the flow to a verified
network. Main already exposes all of this the way the Swap view consumes it,
so collapse onto those sources instead of a parallel system:

- ammProgramId  <- $AMM_PROGRAM_BIN (derived like swapExactInput's program id;
                   doubles as the quote's network fingerprint so a quote can't
                   be replayed against a different deployment)
- tokenIds      <- $TOKENS_CONFIG (amm-tokens.json), same as the Swap picker
- sequencer     <- the wallet config (already surfaced via syncWalletState)

networkSnapshot() builds the ActiveNetworkSnapshot from those; status is
"ready"/"config_missing", gated to "loading" until wallet state resolves so no
module reads happen during construction. The channel probe is gone — submit
needs no channelId (the wallet module supplies the channel via
submitPublicTransaction), so the whole verification apparatus was overhead.

Removes: AMM_UI_NETWORK / AMM_UI_DEVNET_FILE, devnet.json / networks.json, the
ActiveNetwork class (+ its test) and its QNetwork channel probe, and Qt6Network.
ActiveNetwork.h keeps only the ActiveNetworkSnapshot struct. Run command drops
the AMM_UI_* vars:
```
  LEE_WALLET_HOME_DIR=… AMM_PROGRAM_BIN=… TOKENS_CONFIG=… nix run .#amm-ui
```
2026-07-27 12:14:27 +02:00
Ricardo Guilherme Schmidt aafe5e900b fix(amm-ui): require explicit liquidity inputs
Keep wallet assets as token choices without automatically selecting a pair. Keep pool-probe amounts internal so active-pool quotes do not populate the form before user input.
2026-07-27 12:14:27 +02:00
r4bbit 01829a280c feat(apps/amm): add create-pool / new liquidity position flow
Add a "Create Pool" flow to the AMM app that lets a user open a new
liquidity position — seeding a pool's initial liquidity — from token
selection and amount entry, through a confirmation dialog, to on-chain
submission.

- client crate (apps/amm/client): pure, testable protocol logic — account
  decoding, pair/position modelling, and quote/plan computation — exposed to
  the app over a C ABI (config/networks.json drives network selection).
- C++ runtime + backend: AmmClient, ActiveNetwork, and NewPositionRuntime,
  wired into AmmUiBackend (new resolve/quote/submit slots).
- QML flow: NewPositionForm, NewPositionFlow state, NewPositionConfirmation-
  Dialog, TokenSelectorModal, and reusable Amm* presentational components
  (theme, surfaces, buttons) + AmountMath.js.
- tests: C++ (NewPositionRuntimeTest, ActiveNetworkTest) and QML
  (tst_NewPositionForm, tst_LiquidityPage, tst_TokenAmountInput, …).
2026-07-27 12:14:27 +02:00