mirror of
https://github.com/logos-blockchain/lez-programs.git
synced 2026-07-25 16:23:16 +00:00
229 lines
8.5 KiB
Markdown
229 lines
8.5 KiB
Markdown
# AMM UI
|
|
|
|
A QML UI application for the Automated Market Maker (AMM) program.
|
|
|
|
See the [Logos QML UI App Tutorial](https://github.com/logos-co/logos-tutorial/blob/master/tutorial-qml-ui-app.md) for more information.
|
|
|
|
## Wallet / chain integration
|
|
|
|
This app is a `ui_qml` module with a hand-written C++ backend
|
|
(`src/AmmUiBackend.*`, plugin in `src/AmmUiPlugin.*`) that depends on the core
|
|
**`logos_execution_zone`** wallet module. The backend calls the core module's
|
|
wallet FFI through `m_logos->logos_execution_zone.*` and exposes an async QtRO
|
|
surface (`src/AmmUiBackend.rep`) plus an account list model to the QML view.
|
|
|
|
**Onboarding is non-invasive.** The app opens straight to the Trade screen; the
|
|
navbar shows **Connect** (opens a password-only modal) or **Connected** + the
|
|
account selector. There is no path picking — the wallet uses LEZ's canonical
|
|
home, `~/.lee/wallet/` (override with `LEE_WALLET_HOME_DIR`, the same var LEZ
|
|
honors), and its config (`wallet_config.json`) self-initializes.
|
|
|
|
Account/keystore sharing follows the runtime:
|
|
|
|
- **Standalone** (`nix run .#amm-ui`): own core-module instance, but the canonical
|
|
`~/.lee/wallet` keystore is shared with the LEZ wallet UI and any other LEZ
|
|
app on the machine. A previously-created wallet auto-opens on launch.
|
|
- **Inside Basecamp**: the core wallet module is a single shared instance, so on
|
|
startup the backend **adopts** the already-open wallet (see
|
|
`openOrAdoptWallet()`), surfacing **shared** accounts across apps.
|
|
|
|
> Follow-up: the wallet FFI requires explicit `config_path`/`storage_path` even
|
|
> though the wallet crate already defines defaults (`~/.lee/wallet`,
|
|
> `from_path_or_initialize_default`). A `wallet_ffi_create_new_default()` /
|
|
> `_open_default()` upstream would let the app drop its path handling entirely.
|
|
|
|
## Setup
|
|
|
|
This project requires Nix with experimental features enabled. If you haven't already, enable them permanently:
|
|
|
|
```bash
|
|
mkdir -p ~/.config/nix && echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf
|
|
```
|
|
|
|
Install the Logos package manager CLI globally (one-time):
|
|
|
|
```bash
|
|
nix profile install 'github:logos-co/logos-package-manager#cli'
|
|
```
|
|
|
|
This makes `lgpm` available as a global command.
|
|
|
|
## Running the UI standalone
|
|
|
|
The app is built from the **repository-root** flake (which also provides the
|
|
`amm_client_ffi` library it links). From the repo root, launch it with its named
|
|
attribute:
|
|
|
|
```bash
|
|
nix run .#amm-ui
|
|
```
|
|
|
|
This builds and runs the application in development mode. The Logos bridge is unavailable in standalone mode, but the UI layout and mock data are fully functional.
|
|
|
|
Build just the FFI crate with `nix build .#amm_client_ffi`. (Each UI is exposed
|
|
under its own name, so future apps are `nix run .#<name>` — there is no bare
|
|
`nix run .` default.)
|
|
|
|
## Running inside Logos Basecamp
|
|
|
|
This app is a UI plugin that depends on the **core wallet module**
|
|
`logos_execution_zone` (see the Wallet / chain integration section above). Both
|
|
have to be installed into Basecamp — the UI plugin alone will show the AMM tab
|
|
but fail to open it with `Failed to load core dependencies for amm_ui`.
|
|
|
|
### 1. Build the LGX packages
|
|
|
|
```bash
|
|
# The AMM UI plugin — development variant (requires nix store at runtime)
|
|
nix build '.#lgx' --out-link result-lgx
|
|
|
|
# Portable variant (self-contained, works without nix)
|
|
nix build '.#lgx-portable' --out-link result-lgx-portable
|
|
|
|
# The core wallet module it depends on. Use the same rev this app pins as the
|
|
# `logos_execution_zone` input in flake.nix so the ImageID/ABI match.
|
|
nix build 'github:logos-blockchain/logos-execution-zone-module?rev=d2e9400ac06c3cdbfc2405b4f153fff9841a453c#lgx' \
|
|
--out-link result-core
|
|
```
|
|
|
|
### 2. Install into Basecamp
|
|
|
|
```bash
|
|
# Launch Basecamp once to initialise its data directory, then quit (see below)
|
|
|
|
# Set the data directory path
|
|
# macOS:
|
|
BASECAMP_DIR="$HOME/Library/Application Support/Logos/LogosBasecampDev"
|
|
# Linux:
|
|
# BASECAMP_DIR="$HOME/.local/share/Logos/LogosBasecampDev"
|
|
|
|
# Install the core wallet module first (into the modules dir), then the UI plugin
|
|
lgpm --modules-dir "$BASECAMP_DIR/modules" \
|
|
install --file result-core/*.lgx
|
|
lgpm --ui-plugins-dir "$BASECAMP_DIR/plugins" \
|
|
install --file result-lgx/*.lgx
|
|
```
|
|
|
|
> **Note:** Use matching variants throughout — dev with dev, portable with portable. Mixing variants causes loading failures. The portable build uses the `LogosBasecamp` data directory instead of `LogosBasecampDev`.
|
|
|
|
### 3. Launch Basecamp
|
|
|
|
```bash
|
|
nix build 'github:logos-co/logos-basecamp' --accept-flake-config -o ~/.basecamp-result
|
|
~/.basecamp-result/bin/LogosBasecamp
|
|
```
|
|
|
|
The AMM UI appears as a new tab in the Basecamp sidebar.
|
|
|
|
> **Note:** `nix run 'github:logos-co/logos-basecamp'` currently fails with
|
|
> `unable to execute ... No such file or directory` — the flake's default app
|
|
> is named `logos-basecamp` but the packaged binary is `LogosBasecamp`. Build
|
|
> the package and run the `bin/LogosBasecamp` wrapper directly, as above.
|
|
|
|
### Installing via the Basecamp UI
|
|
|
|
Alternatively, use the built-in package manager. Install both packages — the
|
|
core module from `result-core/` and the UI plugin from `result-lgx/`:
|
|
|
|
1. Launch Basecamp
|
|
2. Open Package Manager
|
|
3. Select "Install from file"
|
|
4. Choose the core module `.lgx` from `result-core/`, then the UI plugin `.lgx`
|
|
from `result-lgx/`
|
|
|
|
To actually use the Swap view you must also set `AMM_PROGRAM_BIN` and
|
|
`TOKENS_CONFIG` (both explained below). Run this **from the repo root** — use
|
|
absolute paths (`$(pwd)/…`), because `nix run` may not preserve the working
|
|
directory, so relative paths won't resolve:
|
|
|
|
```bash
|
|
AMM_PROGRAM_BIN=$(pwd)/programs/amm/methods/guest/target/riscv32im-risc0-zkvm-elf/docker/amm.bin \
|
|
TOKENS_CONFIG=$(pwd)/amm-tokens.json \
|
|
nix run .#amm-ui
|
|
```
|
|
|
|
Without `AMM_PROGRAM_BIN` the Swap view stays disabled; without `TOKENS_CONFIG`
|
|
the token picker is empty. Each is detailed below.
|
|
|
|
### AMM program binary (required for swaps)
|
|
|
|
To execute a swap, the app must submit a transaction against the **exact AMM
|
|
program you deployed** (its ELF determines the program id, and therefore every
|
|
pool/vault/config PDA and the transaction's target). The app therefore needs the
|
|
deployed `amm.bin` bytes at runtime — it does **not** derive them from the wallet
|
|
module (whose embedded AMM program may differ from your deployment).
|
|
|
|
Point the app at your deployed binary with the `AMM_PROGRAM_BIN` environment
|
|
variable (absolute path):
|
|
|
|
```bash
|
|
AMM_PROGRAM_BIN=/abs/path/to/amm.bin nix run .#amm-ui
|
|
```
|
|
|
|
This is the same `amm.bin` you deployed via the testnet runbook
|
|
(`programs/amm/methods/guest/target/riscv32im-risc0-zkvm-elf/docker/amm.bin`).
|
|
The app reads it, derives the AMM program id (`amm_client_program_id_from_elf`),
|
|
and reads the on-chain AMM config account to discover the TWAP oracle program id
|
|
for the pool's current-tick PDA. If `AMM_PROGRAM_BIN` is unset or unreadable, the
|
|
Swap view stays disabled (no pool can be resolved).
|
|
|
|
> **Golden rule (from the runbook):** recompiling the AMM changes its program id
|
|
> and *every* derived PDA. After any redeploy, point `AMM_PROGRAM_BIN` at the new
|
|
> `amm.bin` — never mix a stale binary with a fresh deployment.
|
|
|
|
### Token list config (required for the Swap token picker)
|
|
|
|
The Swap view's token picker is config-driven: it doesn't derive tokens from
|
|
chain state, it reads a flat JSON list from the `TOKENS_CONFIG` environment
|
|
variable (absolute path). Each entry needs, at minimum, the token's
|
|
`definitionId` and **your own** `holding` account address for that token (the
|
|
account the wallet will sign transfers from/to for that token):
|
|
|
|
```json
|
|
[
|
|
{
|
|
"symbol": "TKA",
|
|
"name": "Token A",
|
|
"definitionId": "9qbX…",
|
|
"holding": "4T69…",
|
|
"decimals": 18
|
|
}
|
|
]
|
|
```
|
|
|
|
If `TOKENS_CONFIG` is unset, unreadable, or not a valid JSON array, the token
|
|
picker stays empty (a `qWarning` naming the exact cause is logged to stderr; no
|
|
swap can be started). `definitionId`/`holding` may be given as base58 (as the
|
|
wallet/runbook display them) or hex — the app normalizes both to hex.
|
|
|
|
Full command with both variables set (absolute paths, from the repo root):
|
|
|
|
```bash
|
|
AMM_PROGRAM_BIN=$(pwd)/programs/amm/methods/guest/target/riscv32im-risc0-zkvm-elf/docker/amm.bin \
|
|
TOKENS_CONFIG=$(pwd)/amm-tokens.json \
|
|
nix run .#amm-ui
|
|
```
|
|
|
|
## Updating Dependencies
|
|
|
|
To update the pinned versions of dependencies in `flake.lock`:
|
|
|
|
```bash
|
|
nix flake update
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
**Stale QML cache after rebuild:**
|
|
```bash
|
|
QML_DISABLE_DISK_CACHE=1 ~/.basecamp-result/bin/LogosBasecamp
|
|
```
|
|
|
|
**Reset Basecamp data directory:**
|
|
```bash
|
|
# macOS
|
|
rm -rf ~/Library/Application\ Support/Logos/LogosBasecampDev
|
|
# Linux
|
|
rm -rf ~/.local/share/Logos/LogosBasecampDev
|
|
```
|