From c53331934bc2ed313a664b9f02ca93543da367d0 Mon Sep 17 00:00:00 2001 From: r4bbit <445106+0x-r4bbit@users.noreply.github.com> Date: Fri, 24 Jul 2026 18:43:09 +0200 Subject: [PATCH] fix(amm-ui): cache network snapshot to avoid remote calls on the hot path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit networkSnapshot() rebuilt the new-position network context on every call — deriving ammProgramId from $AMM_PROGRAM_BIN and resolving the $TOKENS_CONFIG token ids, which run tokenList()'s remote account_id_from_base58 conversions. It is called on the quote hot path (every keystroke) and, critically, from inside runtime reply callbacks: after a create-pool submit, pool activation runs refreshContext() from within a quoteNewPosition reply, so the nested synchronous remote calls reentered the module connection and hung the reply. refreshNewPositionContext never completed, contextLoading never cleared, and the token selectors (gated on !contextLoading) stayed disabled — the view became unusable after creating a pool. $AMM_PROGRAM_BIN and $TOKENS_CONFIG are fixed for the process lifetime, so resolve ammProgramId and the token ids once and cache them; networkSnapshot() now returns the cached values with no per-call remote work. (Still gated to "loading" until wallet state resolves, so the one-time resolve happens at startup, not inside a callback.) --- apps/amm/src/AmmUiBackend.cpp | 33 ++++++++++++++++++++++----------- apps/amm/src/AmmUiBackend.h | 9 +++++++++ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/apps/amm/src/AmmUiBackend.cpp b/apps/amm/src/AmmUiBackend.cpp index 0800f7d..acb5396 100644 --- a/apps/amm/src/AmmUiBackend.cpp +++ b/apps/amm/src/AmmUiBackend.cpp @@ -322,20 +322,31 @@ ActiveNetworkSnapshot AmmUiBackend::networkSnapshot() snapshot.status = QStringLiteral("loading"); return snapshot; } - snapshot.ammProgramId = ammProgramIdHex(); + // Resolve the AMM deployment id ($AMM_PROGRAM_BIN) and configured token set + // ($TOKENS_CONFIG) ONCE and cache — they're fixed for the process lifetime. + // networkSnapshot() runs on the quote hot path and from inside runtime reply + // callbacks, and tokenList() makes remote base58 conversions; recomputing each + // call reenters the module connection and hangs the reply. + if (!m_networkResolved) { + m_ammProgramIdCache = ammProgramIdHex(); + m_tokenIdsCache.clear(); + // Configured token set = the TOKENS_CONFIG definition ids, the same source + // the Swap view's token picker uses (tokenList normalizes them to hex). + const QVariantList tokens = tokenList(); + for (const QVariant& entry : tokens) { + const QString id = entry.toMap().value(QStringLiteral("definitionId")).toString(); + if (!id.isEmpty()) + m_tokenIdsCache.append(id); + } + m_networkResolved = true; + } + snapshot.ammProgramId = m_ammProgramIdCache; // Bind a quote to this AMM deployment: the program id changes per deployment, // so it doubles as the network fingerprint (a quote can't be replayed against // a different program). Empty when AMM_PROGRAM_BIN is unset — status gates it. - snapshot.fingerprint = snapshot.ammProgramId; - // Configured token set = the TOKENS_CONFIG definition ids, the same source - // the Swap view's token picker uses (tokenList normalizes them to hex). - const QVariantList tokens = tokenList(); - for (const QVariant& entry : tokens) { - const QString id = entry.toMap().value(QStringLiteral("definitionId")).toString(); - if (!id.isEmpty()) - snapshot.tokenIds.append(id); - } - snapshot.status = snapshot.ammProgramId.isEmpty() + snapshot.fingerprint = m_ammProgramIdCache; + snapshot.tokenIds = m_tokenIdsCache; + snapshot.status = m_ammProgramIdCache.isEmpty() ? QStringLiteral("config_missing") : QStringLiteral("ready"); return snapshot; diff --git a/apps/amm/src/AmmUiBackend.h b/apps/amm/src/AmmUiBackend.h index a95cff5..854a105 100644 --- a/apps/amm/src/AmmUiBackend.h +++ b/apps/amm/src/AmmUiBackend.h @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -101,6 +102,14 @@ private: std::unique_ptr m_newPosition; QVariantMap m_newPositionHints; + + // Network context is derived from $AMM_PROGRAM_BIN + $TOKENS_CONFIG, which are + // fixed for the process lifetime — resolve them once and cache. networkSnapshot() + // runs on the hot path (every quote) and from inside runtime callbacks, and + // tokenList() makes remote base58 conversions, so it must not recompute each call. + bool m_networkResolved = false; + QString m_ammProgramIdCache; + QStringList m_tokenIdsCache; }; #endif // AMM_UI_BACKEND_H