diff --git a/apps/amm/qml/components/swap/SwapCard.qml b/apps/amm/qml/components/swap/SwapCard.qml index 17e140a..9dbe023 100644 --- a/apps/amm/qml/components/swap/SwapCard.qml +++ b/apps/amm/qml/components/swap/SwapCard.qml @@ -88,9 +88,25 @@ Rectangle { if (!root.backend || !root.sellToken || !root.buyToken) return + // Capture the pair this request is for. resolvePool callbacks can arrive + // out of order: if the user switches tokens while an earlier resolve is + // still in flight, its (stale) callback must NOT overwrite the current + // pair's pool state — that would corrupt the preview and the submitted + // min_out. A stale callback also leaves poolLoading alone, since the + // newer in-flight request owns it. + var reqSell = root.sellToken.definitionId + var reqBuy = root.buyToken.definitionId + function isStale() { + return !root.sellToken || !root.buyToken + || root.sellToken.definitionId !== reqSell + || root.buyToken.definitionId !== reqBuy + } + root.poolLoading = true - logos.watch(root.backend.resolvePool(root.sellToken.definitionId, root.buyToken.definitionId), + logos.watch(root.backend.resolvePool(reqSell, reqBuy), function (pool) { + if (isStale()) + return root.poolLoading = false root.poolResolved = true root.poolExists = !!(pool && pool.exists) @@ -103,6 +119,8 @@ Rectangle { root.poolError = (pool && pool.error && pool.error !== "no_pool") ? pool.error : "" }, function (error) { + if (isStale()) + return console.warn("resolvePool error:", error) root.poolLoading = false root.poolResolved = true diff --git a/apps/amm/src/AmmUiBackend.cpp b/apps/amm/src/AmmUiBackend.cpp index f1d9008..10fe05f 100644 --- a/apps/amm/src/AmmUiBackend.cpp +++ b/apps/amm/src/AmmUiBackend.cpp @@ -62,11 +62,14 @@ namespace { // canonical wallet (~/.lee/wallet) used by the wallet UI and other apps. const char WALLET_HOME_ENV[] = "LEE_WALLET_HOME_DIR"; - // Absolute path to the deployed AMM program's compiled ELF (amm.bin). The - // app can't safely embed/derive this itself: the wallet module's bundled - // AMM program may differ from whatever is actually deployed on the target - // sequencer, and the program's ELF bytes are what determine its program id - // (and therefore every PDA derived from it). See apps/amm/README.md. + // Absolute path to the deployed AMM program's RISC Zero program binary + // (amm.bin — the `ProgramBinary` `.bin` from the docker guest build, decoded + // on the Rust side via `ProgramBinary::decode`; NOT a raw ELF — pointing at + // the raw guest ELF yields a different/failed program id). The app can't + // safely embed/derive this itself: the wallet module's bundled AMM program + // may differ from whatever is actually deployed on the target sequencer, and + // the binary's bytes are what determine its program id (and therefore every + // PDA derived from it). See apps/amm/README.md. const char AMM_PROGRAM_BIN_ENV[] = "AMM_PROGRAM_BIN"; // Absolute path to the JSON token-list config consumed by tokenList() diff --git a/apps/amm/src/AmmUiBackend.rep b/apps/amm/src/AmmUiBackend.rep index d486463..055e610 100644 --- a/apps/amm/src/AmmUiBackend.rep +++ b/apps/amm/src/AmmUiBackend.rep @@ -53,8 +53,10 @@ class AmmUiBackend 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. Returns the tx hash, or an empty string on failure + // 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)) // Reads the token list config at TOKENS_CONFIG (absolute path, JSON array