Commit Graph
22 Commits
Author SHA1 Message Date
Ricardo Guilherme Schmidt 8c3e6fccfe feat(wallet): humanize shared wallet experience
Consolidate wallet account decoding and portfolio handling around the shared Rust IDL decoder. Simplify AMM wallet integration, remove obsolete caches and network plumbing, and cover account selection and live flows.
2026-08-21 17:38:45 -03: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 78edd23b5b feat(apps/amm): remove liquidity from the pool detail view
The module already had removeLiquidityQuote and removeLiquidity, but
AmmUiBackend never forwarded them, so QML had no way to reach them. Expose
both, mirroring the add pair: the quote is read-only and unguarded, the
submit is wallet-guarded and refreshes balances once the withdrawal lands.
Unlike createPool/addLiquidity nothing fresh is created -- the request names
the existing LP holding to burn and the two holdings that receive.

The pool detail view's secondary action reads "Add liquidity" until the
wallet holds LP for that pool, then becomes "Manage position" with a
dropdown offering both directions, opening on hover with the same deferred
close the nav bar's tab menu uses. Remove is disabled until the LP account
and both receiving holdings resolve.

RemoveLiquidityDialog is a modal sheet: 25/50/75/Max presets over a slider,
a debounced quote of both withdrawals, the post-slippage floors, submit. The
quote is generation-tagged because dragging the slider fires quotes faster
than they return and a late reply must not paint over a newer percentage.
The submit passes the quote's own minimumAmount*Raw as its floors, so it
enforces what the preview promised. 100% burns the balance exactly; every
other percentage floors, so rounding can't push the request past it.
2026-08-20 20:02:11 +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
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
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 fc7b07174c test(amm-ui): add swap UI test 2026-08-05 17:19:38 +02:00
r4bbit 96dc69c39f docs(apps/amm): remove stale BIN reference 2026-08-03 23:11:06 +02:00
r4bbit f5ff9b829f refactor(apps/amm): move the amm_client crate into modules/amm/ffi as amm_ffi
After the amm_module refactor, this crate is linked only by the module (the
UI delegates to modules().amm_module and links nothing), so its home under
apps/amm/ and the name "client" were both misnomers: it's the AMM business
logic the module wraps, reached across an FFI boundary — the same relationship
logos_execution_zone has with wallet_ffi. Co-locate it with the module that
owns it and name it for that role.

The FFI surface is unchanged — the exported functions are already amm_* (not
amm_client_*) — so only the crate, directory, generated header, dylib, and
package names move. The module's call sites are untouched; it just includes the
renamed header.

- apps/amm/client → modules/amm/ffi (git-tracked rename; history preserved)
- crate amm_client → amm_ffi: package name, include/amm_ffi.h, libamm_ffi.dylib,
  AMM_FFI_H guard, build.rs output path, tests/public_api.rs import
- workspace member path + Cargo.lock
- flake.nix: pname, -p, header-copy path, dylib install_name, packages.amm_ffi,
  ammModuleOutputs externalLibInputs, DYLD wrapper
- modules/amm: metadata external_libraries, CMakeLists EXTERNAL_LIBS, impl
  #include + comments, README, flake note
- apps/amm/flake.nix: drop the now-dead amm_client external-lib input (the UI
  links no external lib of its own)

Resulting layout:
  modules/amm/
    src/   # C++ module  (amm_module_impl.{h,cpp})
    ffi/   # Rust crate  amm_ffi  (Cargo.toml, src/, include/amm_ffi.h)
2026-08-03 23:11:06 +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
r4bbit d7017a2515 chore: remove unnecessary macos prerequisites docs 2026-07-27 12:14:27 +02:00
Ricardo Guilherme Schmidt 54afb26087 fix(amm): align execution zone dependencies 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
Andrea Franz c0568e3a88 feat(amm): byte-encode swap instruction for QtRO + AMM_DEBUG tracing + token config 2026-07-23 16:17:25 +02:00
Andrea Franz 906aa65b4f feat(amm): config-driven token picker wired to on-chain swaps 2026-07-23 16:17:25 +02:00
Andrea Franz b51a71ddf2 feat(amm): resolvePool + swapExactInput backend slots for on-chain swaps 2026-07-23 16:17:25 +02:00
Andrea Franz cfb62e4d2f build(amm): link amm_client_ffi into the AMM UI module 2026-07-23 16:17:25 +02:00
r4bbit 25b8b86103 chore(amm): add Logos Basecamp support
Provides the necessary instructions to run the AMM app inside Logos
Basecamp.

Closes #29
2026-07-15 18:31:39 +02:00
r4bbit 751d4ac530 feat(amm): wire the AMM app to the LEZ wallet module
Turns the dummy-data AMM UI into a real client of the on-chain LEZ wallet.
Adds a hand-written ui_qml C++ backend (src/AmmUi*) over the core
logos_execution_zone module: create/open a local wallet, create and list
public/private accounts, and a navbar Connect / Connected + account-selector
+ Disconnect flow. Onboarding is password-only (no path picking) with a
per-app wallet at ~/.lee/amm-wallet (override: AMM_WALLET_HOME_DIR);
standalone gets its own wallet, Basecamp shares accounts via adopt-on-start.

Requires Nix with flakes; macOS also needs `sandbox = false` (the default).
The logos_execution_zone input is pinned to a module rev whose LEZ (lssa)
already includes the macOS Metal-build fix, so no `--override-input` is
needed — plain `nix run .` works:

    cd apps/amm
    nix run .

- create_new now returns the new wallet's BIP39 mnemonic (not an int status);
  the app currently discards it, so the wallet can't yet be recovered. Surfacing
  it in onboarding (+ restore_storage) is a follow-up.
- The wallet password is currently a no-op upstream (storage.rs: "TODO: use
  password for storage encryption"); storage.json is plaintext. So Disconnect
  is a UI-level lock and reconnect does not (cannot yet) re-prompt for it.
- wallet-ffi requires explicit config/storage paths; a *_default() FFI would
  let the app drop its path handling.
- Bundled network config: connects to whatever WalletConfig::default() points
  at; real testnet endpoints still TBD.
2026-07-02 18:57:01 +02:00
r4bbit 3622016e6c refactor: move programs into programs and UIs into apps
This refactors the repository structure as it has grown over time.
2026-05-26 14:05:52 +02:00