Files
lez-programs/apps/amm/src/AmmUiBackend.rep
T
Ricardo Guilherme Schmidt cdedb49609 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:11:47 +02:00

148 lines
9.7 KiB
Plaintext

// QtRO view contract for the AMM UI backend. PROPs auto-sync to every QML
// replica; SLOTs are the async surface QML calls via logos.watch(...).
// The account list is exposed separately as a Q_PROPERTY model on the backend
// (reached from QML via logos.model("amm_ui", "accountModel")).
class AmmUiBackend
{
PROP(bool isWalletOpen READONLY)
// False while startup or reconnect is still resolving wallet state. This
// stays distinct from isWalletOpen because a disconnected wallet is ready.
PROP(bool walletStateReady READONLY)
PROP(bool walletExists READONLY)
PROP(QString configPath READONLY)
PROP(QString storagePath READONLY)
PROP(QString walletHome READONLY)
PROP(int lastSyncedBlock READONLY)
PROP(int currentBlockHeight READONLY)
PROP(QString sequencerAddr READONLY)
// Whether the configured sequencer answered the last reachability probe.
// Defaults true so the UI doesn't flash a warning before the first check.
PROP(bool sequencerReachable READONLY)
// Account management
SLOT(QString createAccountPublic())
SLOT(QString createAccountPrivate())
SLOT(void refreshAccounts())
SLOT(void refreshBalances())
SLOT(QString getBalance(QString accountIdHex, bool isPublic))
// New Position backend surface. QML calls these through logos.watch(...).
// The QVariant payloads are stable maps/lists so the UI never assembles AMM
// transactions or duplicates quote state.
PROP(QVariantMap newPositionContext READONLY)
// Return the published context so the QML refresh watcher always settles.
SLOT(QVariantMap refreshNewPositionContext(QVariantMap request))
// Wallet lifecycle. createNewDefault() is the happy path: it creates a
// fresh wallet at the canonical walletHome with no path picking. createNew()
// keeps explicit paths for an "advanced" flow. Both return the new wallet's
// BIP39 mnemonic (empty on failure) so the UI can force a seed-phrase backup
// before the wallet is usable — this is the only chance to record it.
SLOT(QString createNewDefault(QString password))
SLOT(QString createNew(QString configPath, QString storagePath, QString password))
// Re-open the existing on-disk wallet after a disconnect.
SLOT(bool openExisting())
// Close this app's wallet view (lock); does not delete the wallet and, in
// Basecamp, does not close the wallet other apps share.
SLOT(void disconnectWallet())
// AMM
// Derives the AMM pool's PDAs (config/pool/vaults/current-tick) from the
// deployed AMM program binary (see AMM_PROGRAM_BIN — a RISC Zero
// ProgramBinary .bin, not a raw ELF) and reads the pool's
// on-chain reserves. Returns `{ exists: false }` if the AMM program bin
// isn't configured, the AMM isn't initialized, or the pool has no
// liquidity yet.
SLOT(QVariantMap resolvePool(QString defAHex, QString defBHex))
// Submits a real on-chain SwapExactInput transaction against the pool for
// (defAHex, defBHex). amountInDecimal/minOutDecimal are decimal-string
// u128 amounts in base units; deadlineDecimal is a decimal-string u64 unix
// timestamp in MILLISECONDS (matches amm_core's SwapExactInput deadline —
// passing seconds would expire the swap immediately once deadline handling
// is enforced). Returns the tx hash, or an empty string on failure
// (no pool, unreadable AMM_PROGRAM_BIN, bad inputs, or a failed tx).
SLOT(QString swapExactInput(QString defAHex, QString defBHex, QString userInputHoldingHex, QString userOutputHoldingHex, QString amountInDecimal, QString minOutDecimal, QString deadlineDecimal))
// Server-side SwapExactInput preview for (tokenInHex, tokenOutHex): reads the
// pool and returns { status:"ok", error:"", expectedOutRaw, minReceivedRaw,
// priceImpactBps }, oriented and priced via the shared on-chain formula.
// amountInDecimal is a decimal-string base-unit amount; slippageBps is basis
// points. On failure { status:"error", error:<code> } — no_pool,
// config_missing, bad_amount, invalid_slippage (slippageBps out of range),
// backend_error. Read-only, no submission.
SLOT(QVariantMap swapExactInQuote(QString tokenInHex, QString tokenOutHex, QString amountInDecimal, int slippageBps))
// Server-side SwapExactOutput preview for (tokenInHex, tokenOutHex): reads the
// pool and returns { status:"ok", error:"", requiredInRaw, maxInRaw,
// priceImpactBps } — the input needed for the desired output and the slippage
// ceiling on it — oriented and priced via the shared on-chain formula.
// amountOutDecimal is a decimal-string base-unit amount; slippageBps is basis
// points. On failure { status:"error", error:<code> } — no_pool,
// output_exceeds_liquidity, config_missing, bad_amount, backend_error.
// Read-only, no submission.
SLOT(QVariantMap swapExactOutQuote(QString tokenInHex, QString tokenOutHex, QString amountOutDecimal, int slippageBps))
// Submits a real on-chain SwapExactOutput transaction against the pool for
// (defAHex, defBHex). amountOutDecimal is the exact desired output (base
// units); maxInDecimal is the slippage ceiling on the input actually spent;
// deadlineDecimal is a decimal-string u64 unix timestamp in MILLISECONDS.
// Same return contract as swapExactInput (tx hash, empty string on failure).
SLOT(QString swapExactOutput(QString defAHex, QString defBHex, QString userInputHoldingHex, QString userOutputHoldingHex, QString amountOutDecimal, QString maxInDecimal, QString deadlineDecimal))
// Reads the token list config at TOKENS_CONFIG (absolute path, JSON array
// of { symbol, name, definitionId, holding, decimals }) and returns it as
// a QVariantList of QVariantMap entries. Returns an empty list if
// TOKENS_CONFIG is unset/unreadable/invalid.
SLOT(QVariantList tokenList())
// Server-side create-pool preview from the two deposit amounts. `request`
// carries { tokenAId, tokenBId, amountARaw, amountBRaw } (ids hex or base58;
// amounts decimal-string base units). Returns { status:"ok", error:"",
// amountARaw, amountBRaw, expectedLpRaw, lockedLpRaw, initialPriceRaw } — the
// LP the creator receives and the opening price, via the shared on-chain math.
// On failure { status:"error", error:<code> } — invalid_token_id,
// same_token_pair, amount_too_low, amount_required, bad_amount, backend_error.
// Read-only, no submission (the fee is not needed — it isn't part of the pool
// PDA nor the pricing).
SLOT(QVariantMap createPoolQuote(QVariantMap request))
// Server-side add-liquidity preview from the two max deposit amounts. `request`
// carries { tokenAId, tokenBId, maxAmountARaw, maxAmountBRaw, slippageBps } (ids hex or
// base58). Reads the pool and returns { status:"ok", error:"", amountARaw, amountBRaw
// (the actual ratio-matched deposits, display order), expectedLpRaw, minimumLpRaw (the
// slippage floor on the LP minted — the submit's min_amount_liquidity), priceRaw }. On
// failure { status:"error", error:<code> } — no_pool, pair_mismatch, invalid_token_id,
// invalid_slippage, amount_too_low, minimum_lp_zero, bad_amount, backend_error.
// Read-only, no submission.
SLOT(QVariantMap addLiquidityQuote(QVariantMap request))
// Submits a NewDefinition transaction creating the pool for the request's pair.
// `request` carries { tokenAId, tokenBId, holdingAId, holdingBId, lpHoldingId,
// amountARaw, amountBRaw, feeBps, deadlineMs } (ids hex or base58; amounts/deadline
// decimal strings). A new pool has no existing LP holding, so the caller supplies
// lpHoldingId — a fresh account it created via createAccountPublic(); the backend
// just forwards to the module and creates no wallet accounts here. Returns
// { status:"ok", error:"", transactionId:<hex tx hash> } on success, else
// { status:"error", error:<code> } (wallet_unavailable, config_missing,
// invalid_account_id, bad_amount, bad_fee_bps_amount, invalid_fee_tier,
// wallet_submission_failed, backend_error).
SLOT(QVariantMap createPool(QVariantMap request))
// Submits an AddLiquidity transaction into the request's existing pool. `request`
// carries { tokenAId, tokenBId, holdingAId, holdingBId, lpHoldingId, maxAmountARaw,
// maxAmountBRaw, minLpRaw, deadlineMs } (ids hex or base58; amounts/deadline decimal
// strings). minLpRaw is the slippage floor on the LP minted; lpHoldingId is a fresh
// holding the caller supplies (the flow creates it) to receive the minted LP — the
// backend forwards and creates no wallet accounts. Returns
// { status:"ok", error:"", transactionId:<hex tx hash> } on success, else
// { status:"error", error:<code> } (wallet_unavailable, config_missing,
// invalid_account_id, bad_amount, no_pool, wallet_submission_failed, backend_error).
SLOT(QVariantMap addLiquidity(QVariantMap request))
// Lists the connected wallet's fungible token holdings for the account
// selector: [{ accountId, accountType:"TokenHolding", definitionId,
// definitionIdHex, balanceRaw }] — one row per holding account, every token,
// including zero-balance holdings. The selector narrows to a token by id.
SLOT(QVariantList tokenHoldings())
// Reads the known-pools config at AMM_POOLS_CONFIG (absolute path, JSON array
// of { tokenA, tokenB, feeBps, poolId, tokenADefinitionId, tokenBDefinitionId })
// and returns it as a QVariantList of QVariantMap entries. tokenA/tokenB are
// display symbols; the id fields identify the pool on-chain. Returns an empty
// list if AMM_POOLS_CONFIG is unset/unreadable/invalid. This is app config, not
// an on-chain read, so it lives in the backend rather than the amm_module.
SLOT(QVariantList poolList())
}