Files
lez-programs/apps/amm/src/AmmUiBackend.h
T
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

91 lines
3.8 KiB
C++

#ifndef AMM_UI_BACKEND_H
#define AMM_UI_BACKEND_H
#include <memory>
#include <QObject>
#include <QString>
#include <QStringList>
#include <QVariant>
#include <QVariantList>
#include <QVariantMap>
#include "rep_AmmUiBackend_source.h"
#include "WalletAccountModel.h"
class LogosAPI;
struct LogosModules;
class LogosWalletProvider;
class WalletController;
// Source-side implementation of the AmmUiBackend .rep interface.
// Inheriting from AmmUiBackendSimpleSource gives us the generated PROPs and
// SLOTs from AmmUiBackend.rep — all the simple ones flow over QtRO.
//
// The AMM business logic (pool resolution, swaps, add-liquidity) lives in the
// amm_module core Logos module; this backend owns only wallet-session lifecycle
// and forwards every AMM slot to modules().amm_module. The one exception is
// creating a fresh LP holding for add-liquidity: that mutates the wallet keyset,
// so it stays here (via the wallet provider, which keeps the account model and
// on-disk storage coherent) and its id is handed to the module's submit.
class AmmUiBackend : public AmmUiBackendSimpleSource {
Q_OBJECT
Q_PROPERTY(WalletAccountModel* accountModel READ accountModel CONSTANT)
public:
explicit AmmUiBackend(LogosAPI* logosAPI = nullptr, QObject* parent = nullptr);
~AmmUiBackend() override;
WalletAccountModel* accountModel() const;
public slots:
// Overrides of the pure-virtual slots generated from the .rep.
QString createAccountPublic() override;
QString createAccountPrivate() override;
void refreshAccounts() override;
void refreshBalances() override;
QString getBalance(QString accountIdHex, bool isPublic) override;
void refreshNewPositionContext(QVariantMap request) override;
QVariantMap quoteNewPosition(QVariantMap request) override;
QVariantMap submitNewPosition(QVariantMap request, QString quoteHash) override;
// Return the new wallet's BIP39 mnemonic (empty string on failure) so the
// UI can force a one-time seed-phrase backup step.
QString createNewDefault(QString password) override;
QString createNew(QString configPath, QString storagePath, QString password) override;
bool openExisting() override;
void disconnectWallet() override;
// AMM — all forwarded to the amm_module core module.
QVariantMap resolvePool(QString defAHex, QString defBHex) override;
QString swapExactInput(QString defAHex, QString defBHex, QString userInputHoldingHex,
QString userOutputHoldingHex, QString amountInDecimal,
QString minOutDecimal, QString deadlineDecimal) override;
// Reads the token list from TOKENS_CONFIG (via the module) so the Swap UI's
// token picker is config-driven instead of hardcoded.
QVariantList tokenList() override;
private:
void syncWalletState();
// Publishes the new-position context PROP: a local "loading" placeholder
// until wallet state (and thus the module connection) is ready, then the
// module's newPositionContext for the current hints.
void publishNetworkContext();
LogosAPI* m_logosAPI;
// Handle for the amm_module core module (resolvePool / swapExactInput /
// tokenList / new-position). The module wraps the amm_client brain and
// reaches the shared wallet through its own logos_execution_zone dependency;
// this backend keeps a thin LogosModules over the same LogosAPI as the
// wallet provider so both resolve that one shared wallet instance.
std::unique_ptr<LogosModules> m_logos;
std::unique_ptr<LogosWalletProvider> m_wallet;
std::unique_ptr<WalletController> m_walletController;
// Sticky new-position hints (recent/resolved token ids) so a bare
// republish (wallet-state change) keeps the user's last selection.
QVariantMap m_newPositionHints;
};
#endif // AMM_UI_BACKEND_H