Skip to content

fix: stabilize wallet home asset refresh(OK-61576) - #13103

Open
weatherstar wants to merge 7 commits into
release/v6.5.2from
fix/ios-wallet-home-asset-refresh-v6.5.2
Open

fix: stabilize wallet home asset refresh(OK-61576)#13103
weatherstar wants to merge 7 commits into
release/v6.5.2from
fix/ios-wallet-home-asset-refresh-v6.5.2

Conversation

@weatherstar

@weatherstar weatherstar commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

OK-61576


Summary

  • Commit the authoritative Home asset snapshot before running non-critical wallet asset-status analytics.
  • Serialize Home all-network refresh requests across debounce and in-flight windows so explicit refreshes are not dropped.
  • Introduce per-key asset snapshot freshness metadata (localSeq + HTTP Date marker) and apply last-writer-wins admission at every persistence/state layer, so an out-of-order stale response can no longer overwrite newer data.
  • Harden the failure paths surfaced by review: restore the last-good published result when an accepted refresh fails, guard against stale debounced runners from a previous owner, and self-heal the sequence counter after a device clock rollback.

Intent & Context

Users reported that wallet balances and prices could remain stale or inconsistent after repeated refreshes, app background/foreground transitions, and switching between mobile and desktop. The investigation showed successful token-list API responses followed by delayed or missing UI publication.

Root Cause

  1. The Home refresh path awaited a slow asset-status analytics workflow before publishing the already-built authoritative snapshot. A logged getAllHdHwQrWallets call took about 93 seconds, and iOS suspension amplified the delay.
  2. useAllNetworkRequests allowed manual/event refreshes to overlap its internal debounce and in-flight queue; queued must-run intent could be lost or filtered as a redundant run while the previous result remained visible.
  3. With refreshes now firing more aggressively, out-of-order responses could overwrite newer persisted data (token-list cache, account values, overview worth) with stale payloads.

Design Decisions

  • Move the non-critical analytics work after the authoritative snapshot commit and refresh-state update so UI freshness does not depend on analytics latency.
  • Route Home refreshes through the existing queue and preserve explicit refresh flags, without changing the generic usePromiseResult behavior or unrelated consumers. The Home-only flag is named clearRetainedResultOnAcceptedRun to avoid confusion with usePromiseResult's same-named-but-different undefinedResultIfReRun option.
  • Mint one monotonic localSeq per token fetch in the background runtime (the single sequencer) and attach it to responses as assetSnapshotMeta. Every write layer (SimpleDbEntityLocalTokens, SimpleDbEntityAccountValue, activeAccountValueAtom via ServiceAccountProfile, accountWorthAtom via accountOverview actions) admits a write only when it is newer than the stored marker; unversioned legacy writes may initialize a key but never clobber versioned data.
  • A full-snapshot replacement (which may delete omitted keys) requires an aggregate marker proving every enabled network was observed by the same refresh; otherwise the write degrades to a per-network merge.
  • The freshness admission helpers live in @onekeyhq/shared/src/utils/assetSnapshotFreshness and are shared by all layers, so the comparison semantics cannot drift.
  • Clock-rollback resilience: comparing against a persisted marker lifts the in-memory sequence watermark, so after a backward clock jump the very next refresh mints a newer sequence instead of being rejected indefinitely.
  • Keep the OTA change limited to shared JavaScript; no persistence schema (SimpleDB fields are additive/optional), native watchdog, dependency, or unrelated refactor changes are included.

Changes Detail

Refresh scheduling and publication:

  • packages/kit/src/views/Home/components/TokenListBlock/TokenListBlock.tsx: opt Home into retained-result handling, publish the authoritative snapshot before asset-status analytics, and drop the duplicate AddDBAccountsToWallet refresh (the hook-level wallet-scoped listener already forces one fan-out with an accounts-cache bypass; only the LP token list keeps a dedicated trigger).
  • packages/kit/src/hooks/useAllNetwork.ts: reserve debounce windows, merge queued must-run configuration, distinguish accepted refreshes from redundant runs; restore the last-good published result when an accepted fan-out fails before publication; bail out stale runners whose closure belongs to a previous owner (they could otherwise clear the new owner's result and run a ghost fan-out).
  • packages/kit/src/hooks/allNetworkRunResultUtils.ts: pure resolveAllNetworkFailedRunRestore decision + tests.

Snapshot freshness admission:

  • packages/shared/src/utils/assetSnapshotFreshness.ts (+ packages/shared/types/assetSnapshot.ts): sequence minting, header parsing, tolerant comparison, shared admission helpers (canApplyAssetSnapshotMeta, getNewestAssetSnapshotMeta, …), clock-rollback watermark self-heal.
  • packages/kit-bg/src/services/ServiceToken.ts: mint the marker before each fetch, thread it through responses and the local token cache; failed debounced cache flushes merge back and reschedule persistence.
  • packages/kit-bg/src/dbs/simple/entity/SimpleDbEntityLocalTokens.ts / SimpleDbEntityAccountValue.ts: versioned admission inside the entity mutex for token-list slices and account values (full-replace vs per-network merge).
  • packages/kit-bg/src/services/ServiceAccountProfile.ts: mutex-serialized active-account-value atom updates with owner-aware freshness admission; the old "value can only go up" heuristic is replaced by the freshness gate (legitimate balance decreases now propagate).
  • packages/kit/src/states/jotai/contexts/accountOverview/actions.ts / atoms.ts: worth-map admission with per-key and aggregate markers; create-at-network scalar recomputed from materialized absolute values.
  • packages/kit/src/views/Home/pages/HomeOverviewContainer.tsx: persist per-network values by compound key with their markers; filtered TokenSelector responses no longer persist as canonical network totals (packages/kit/src/views/AssetSelector/pages/TokenSelector.tsx).

Risk Assessment

  • Risk Level: Medium
  • Affected Platforms: Mobile / Desktop / Web / Extension (shared Home, all-network, and persistence code paths)
  • Risk Areas: Refresh scheduling and result publication during account/network switches, app lifecycle transitions, and concurrent manual/dependency triggers; freshness admission on the token-list cache and account-value persistence (stale writes are now rejected by design). Native runtime suspension can still delay JavaScript execution until resume.

Test plan

  • yarn jest packages/kit/src/views/Home/components/TokenListBlock packages/kit-bg/src/dbs/simple/entity/SimpleDbEntityAssetSnapshot.test.ts packages/kit-bg/src/services/ServiceAccountProfile.updateAllNetworkAccountValue.test.ts packages/kit/src/states/jotai/contexts/accountOverview/actions.test.tsx packages/shared/src/utils/assetSnapshotFreshness.test.ts packages/kit/src/hooks/allNetworkRunResultUtils.test.ts --runInBand (12 suites, 96 tests passed)
  • yarn agent:check --profile commit (lint-worktree-ts, lint-staged, tsc-staged all passed)
  • Verify repeated refresh and background/foreground recovery on iOS and desktop release builds
  • Failure recovery: force getAllNetworkAccounts / onStarted to fail mid-refresh; the list must keep the last authoritative snapshot and later pull-to-refresh must still commit
  • Switch accounts within 1s of a pull-to-refresh; the new account's data must not be cleared
  • Clock rollback: set the device clock forward, refresh, set it back, restart; balances must keep updating
  • Single-network balance decrease propagates after the removal of the "only increase" guard; OTA upgrade from a build with unversioned caches admits the first versioned write

@sidmorizon

Copy link
Copy Markdown
Contributor

@codex review

@sidmorizon

Copy link
Copy Markdown
Contributor

@codex security review

@sidmorizon

Copy link
Copy Markdown
Contributor

@cursoragent review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for security reviews. Please try again later.

@cursor

cursor Bot commented Sep 1, 2026

Copy link
Copy Markdown

PR #13103 代码审查报告

审查概要 [REQUIRED]

  • 变更范围: 3 个文件, +227 / -130 行
  • 风险等级: Medium
  • 涉及平台: Mobile / Desktop / Web / Extension(共享 Home + all-network 路径)
  • Codex 交叉验证: ⏭️ 未启用
  • PR 评论分析: ✅ 已分析 (6 条评论, 其中 3 条来自 Bot)

评分 [REQUIRED — NEVER SKIP THIS SECTION]

维度 得分 说明
🔒 安全性 9/10 无密钥/鉴权/供应链变更;资产状态埋点仍走既有 logger,未扩大敏感面
💎 代码质量 6.5/10 主修复方向正确,但 accepted fan-out 在失败时会丢掉 last-good 快照;队列逻辑过密且缺少行为测试
🏛️ 架构合理性 8/10 Home 用 opt-in 旗标,未改 usePromiseResult 通性、未波及 NFT/DeFi;旗标与 hook 同名容易误用
✅ 完整性 6/10 新增测试只锁源码顺序;debounce 预占、must-run 合并、失败恢复均无单测
总分 7.5/10 ⚠️ 需修改后复审

PR 评论分析 [REQUIRED if comments exist, OMIT if none]

来源 类型 发现 判定 说明
@sidmorizon 👤 Human @codex review / @codex security review / @cursoragent review ❌ Noise 仅触发审查,无具体缺陷
chatgpt-codex-connector[bot] 🤖 Bot security review 额度用尽 ❌ Noise 无审查结论
cursor[bot] 🤖 Bot “Taking a look!” ❌ Noise 本审查的占位回复
chatgpt-codex-connector[bot] 🤖 Bot Codex Code Review Running ❌ Noise 审查仍在进行,尚无 findings

评论误报分析

  • 触发评论 / Bot 状态: 不含可验证的代码问题,不计入 findings。

发现的问题 [REQUIRED]

[🟡 中] [🔵 High] Accepted refresh 失败后会丢掉 last-good 结果

文件: packages/kit/src/hooks/useAllNetwork.ts:610
类型: 运行时
描述: Home 开启 undefinedResultIfReRun 后,runner 一旦通过 redundant-run gate,就会立刻 setResult(undefined) 并把 lastPublishedResultRef 置空。这发生在 accountsTask / onStarted 之前。随后 try 里若抛错(账号列表拉取失败、onStarted 失败),finally 只会排空队列,不会走到 resolveAllNetworkPublishedResultusePromiseResult 也没有 undefinedResultIfError,成功路径的 setResult 不会回写。

后果:

  • React 结果停在 undefinedupdateAllNetworksTokenList!allNetworksResult?.length 直接返回,权威快照不再提交。
  • skip 路径本来靠 lastPublishedResultRef 恢复稳定结果,但 ref 已被清空,后续同 owner 的依赖重入只能继续返回 undefined
  • 在此之前,失败会保留上一份已发布结果;这是回归。屏幕上的 cells 可能仍是上次 commitAuthoritativeIngest 的数据,但权威提交链路会卡住,直到下一次 must-run 成功。

onStarted 明确会把错误重新抛出:

        if (onStartedTask) {
          await onStartedTask;
          if (onStartedError) {
            if (onStartedError instanceof Error) {
              // oxlint-disable-next-line no-throw-literal
              throw onStartedError;
            }
            const err = new Error('onStarted failed');
            throw err;
          }
        }

修复建议: 只在成功 resolve 后丢弃上一份 published result;失败时回滚。不要靠 setResult(undefined) 单独承担“作废旧结果”——那条路径不受 usePromiseResult nonce 保护。

Auto-fix:

       lastRunSignatureRef.current = currentRunSignature;

+      const previousPublishedResult = lastPublishedResultRef.current;
       if (undefinedResultIfReRun) {
         // Keep a queued refresh from restoring the prior published result
         // after the new run has already invalidated it.
         clearResultRef.current?.();
         lastPublishedResultRef.current = undefined;
       }
+      const restorePublishedResultAfterFailure = () => {
+        if (!undefinedResultIfReRun) {
+          return;
+        }
+        lastPublishedResultRef.current = previousPublishedResult;
+        if (
+          previousPublishedResult?.runSignature === currentRunSignature
+        ) {
+          clearResultRef.current = undefined;
+        }
+      };

更干净的写法是把 fan-out 包进独立 try/catch:失败时恢复 lastPublishedResultRef,并用 setResult(previousPublishedResult.result) 写回;成功且 hasQueuedMustRun 时再作废旧结果。不要把 clearResultRef.current 赋成 undefined 函数,上面的 patch 只表达意图。

推荐实现:

       lastRunSignatureRef.current = currentRunSignature;

+      const previousPublishedResult = lastPublishedResultRef.current;
       if (undefinedResultIfReRun) {
         clearResultRef.current?.();
         lastPublishedResultRef.current = undefined;
       }

       runCountRef.current += 1;
       // ...
       try {
         // existing fan-out
       } finally {
         isFetching.current = false;
         hasQueuedRerun = scheduleQueuedRerun();
       }
+      } catch (error) {
+        if (undefinedResultIfReRun) {
+          lastPublishedResultRef.current = previousPublishedResult;
+          if (
+            previousPublishedResult?.runSignature === currentRunSignature
+          ) {
+            setResult(previousPublishedResult.result);
+          }
+        }
+        throw error;
+      }

注意:现有 try/finally 后面还有 resolveAllNetworkPublishedResult,catch 必须包住整个 publish 段,或在 finally 之外用嵌套 try/catch。当前结构下 throw 会跳过 resolve,这正是要修的点。


[🟡 中] [🟠 Medium] 新增队列语义没有行为测试

文件: packages/kit/src/hooks/useAllNetwork.ts:506 / TokenListBlock.portfolioSync.test.ts:47
类型: 规范
描述: 这次真正改调度的是三块纯决策:

  1. debounce 窗口内 runWithQueue 预占,避免再开一条 usePromiseResult runner、冲掉 nonce
  2. 排队配置按 alwaysSetState | skipAccountsCache | ignoreDisabled 做 OR 合并
  3. scheduleQueuedRerun 在 Home 上只把 must-run 当成“作废刚完成结果”的信号

仓库里对同类逻辑已经抽过 resolveAllNetworkPublishedResultshouldSkipRedundantAllNetworkRun 并配了单测。新逻辑仍堆在 hook 闭包里;新增测试只断言 TokenListBlock.tsx 源码字符串顺序,改个函数名或加一行同名调用就会误报/漏报,也测不到失败回滚、debounce 丢刷新、依赖重入误升 must-run。

修复建议: 抽出纯函数(例如 shouldQueueAllNetworkRunDuringDebouncemergeAllNetworkRerunConfigshouldSuppressPublishedResultForQueuedRerun),补上:

  • debounce 中的手动刷新被 queue,而不是再 run()
  • 两次 queue 的 must-run flag 会合并
  • 依赖重入(无 config)drain 后仍发布刚完成的结果
  • accepted run 抛错后恢复 lastPublished

analytics 的源码顺序测试可以留作锁栏,但不能代替这些。


[🟢 低] [🟠 Medium] undefinedResultIfReRunusePromiseResult 同名不同义

文件: packages/kit/src/hooks/useAllNetwork.ts:344
类型: 规范
描述: usePromiseResult 的同名选项会在 每次 runner 启动时清空 result。本 PR 有意不转发,只在 gate 接受新 fan-out 时清空,skip 的 duplicate 要保留稳定结果。注释写了,但后续很容易有人把该旗标传进 usePromiseResult,Home 会在每次依赖抖动时闪成空列表。

修复建议: 改名为 clearRetainedResultWhenFanOutAcceptedretainResultOnRedundantRun,避免和 usePromiseResult 对齐。


修改清单 [REQUIRED]

优先级 置信度 文件 类型 描述 Auto-fix
🟡 中 🔵 High useAllNetwork.ts:610 运行时 accepted fan-out 失败后 last-good 结果无法恢复
🟡 中 🟠 Medium useAllNetwork.ts:506 / TokenListBlock.portfolioSync.test.ts:47 规范 队列/失败恢复缺少行为测试
🟢 低 🟠 Medium useAllNetwork.ts:344 规范 旗标与 usePromiseResult 同名不同义

测试建议 [REQUIRED]

  1. All-networks Home:连续下拉刷新,第二次落在 1s debounce 内,第二次必须真正发请求,且第一次成功结果不能被依赖重入吃掉。
  2. 刷新开始后让 getAllNetworkAccounts / onStarted 失败:列表应保留上一份权威快照,随后的依赖重入不应把 allNetworksResult 钉死在 undefined
  3. 后台/前台、账户切换、HW AddDBAccountsToWallet:must-run flag 合并后仍能穿过 redundant-run gate。
  4. 回归:yarn jest packages/kit/src/hooks/allNetworkRunResultUtils.test.ts packages/kit/src/hooks/shouldSkipRedundantAllNetworkRun.test.ts packages/kit/src/views/Home/components/TokenListBlock --runInBand
  5. 手工:iOS 挂起仍可能拖住 JS,PR 已说明;重点看 resume 后下拉刷新是否还能提交,而不是只看 spinner。
  6. NFT / DeFi 未开启该旗标,抽查一次确认调度行为与 release/v6.5.2 一致。

GH 评论操作 [REQUIRED if qualifying findings exist, OMIT if none]

以下问题(🔵 High 置信度 + 🟡 中及以上)建议直接评论到 PR:

  • Accepted refresh 失败后丢掉 last-good 结果 — packages/kit/src/hooks/useAllNetwork.ts:610

确认后将通过 gh CLI 发送 inline comments。


主修复是对的:getAllHdHwQrWallets 那条慢路径不再挡住 commitAuthoritativeIngest / updateTokenListState,Home 的手动刷新也不会在 debounce 里再开一条 runner 冲掉 nonce。NFT/DeFi 默认关旗标,影响面可控。

合入前建议先补上失败回滚,并把队列决策抽成可测的纯函数。需要的话我可以直接改并补测试。

Open in Web Open in Cursor 

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 1, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-01T08:19:50.180933Z d2678b4 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d2678b492a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/kit/src/hooks/useAllNetwork.ts Outdated
@originalix

originalix commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Automated code review found blocking issues

@weatherstar

Reviewed commit 604901406225. This report always reflects the latest reviewed changes.

Review summary

The change adds freshness metadata to wallet asset snapshots across the background fetch, persistence, and foreground account-overview paths. Before, each settled response could replace shared worth/cache state without a durable ordering marker; after, background fetches mint request-order metadata, HTTP Date is retained as a tie-breaker, and the active atom plus SimpleDB admit or reject writes by snapshot freshness. Full all-network replacements additionally require a complete marker and preserve newer omitted networks. Cache migration tolerance, no-op writes, token-list propagation, and existing token rendering/filter behavior remain otherwise unchanged. The foreground and background runtimes each hold their own JavaScript copies while the background runtime persists through shared native storage, so marker propagation is the synchronization boundary.

What needs attention: Verify that a versioned merge:false single-network refresh replaces the scoped worth map while retaining only a stale-safe value for the requested key.

Issues to address

  • P1 · Versioned single-network updates retain previous-network balances
    • Impact: A merge:false single-network response carries only a per-key marker, but the replacement gate requires an aggregate marker. When the account ID is shared across networks, omitted entries from the previously selected network remain in accountWorth. Consumers such as useHomeBalanceState and HomeOverviewContainer aggregate all entries, so a zero-balance network can appear funded or exceed thresholds using stale data.
    • Suggested action: Handle merge:false single-network updates as scoped replacements: apply freshness only to supplied keys, preserve a newer value for the same key when necessary, and evict omitted network keys without requiring an all-network aggregate marker.

Validation gaps

  • Targeted Jest tests were not executed because the checkout has no installed node_modules state (Couldn't find the node_modules state file).
  • GitHub review/comment surfaces could not be fetched from the current environment, so the inline candidate is marked for human review rather than automatic publication.

Comment on lines +263 to +269
const preserveCurrentValues =
sameAccount && (!isCompleteSnapshot || !canReplaceFullSnapshot);
const nextWorth: Record<string, string> = preserveCurrentValues
? { ...currentValue }
: {};
const nextMetaByKey: Record<string, IAssetSnapshotMeta> =
preserveCurrentValues ? { ...currentMetaByKey } : {};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 P1: Single-network switches retain prior balances

Severity: severe

In the main-runtime Jotai copy, preserveCurrentValues retains the previous network when a versioned account switches networks. Merge-derived views sum both values and inflate the balance; no shared native resource or background copy participates.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Analyzed with full codebase context — keeping this behavior as designed, no code change for now. Reasoning:

  1. The retention is the atom's intended cross-network-map semantics (codified by the new tests, e.g. retains omitted networks when an unversioned all-network cache is partial). worth is keyed by (accountId, networkId), so a retained entry is the other network's real balance under its own key — never a second copy of the current network's value, so per-key consumers cannot double count.
  2. The displayed Home total does not sum this map. It reads lastConfirmedOverviewBalance.byOwner[ownerKey] (keyed per owner+network, HomeOverviewContainer.tsx), so the visible balance is unaffected by retained sibling-network keys.
  3. The only consumers that sum the whole map are the walletStatus hasValue threshold (HomeOverviewContainer.tsx allWorth) and useHomeBalanceState's funded-positivity bucket. Both are wallet/account-level signals where cross-network aggregation is semantically acceptable, and both already saw the same values whenever the all-network path had run.
  4. HD accounts switching across impls (e.g. ETH -> BTC) change the payload accountId, so sameAccount is false and a full replacement clears the map. The retention window is limited to same-account-id families (EVM networks, Others accounts) — exactly where the values remain valid balances.

If we later want single-network views to drop sibling-network keys, that should be a deliberate change on the reset path in HomeOverviewContainer, not in the freshness admission logic. Leaving this thread open for your confirmation — happy to follow up if there is a concrete surface where the summed value is user-visible.

Comment thread packages/kit/src/states/jotai/contexts/accountOverview/actions.ts
Comment thread packages/kit/src/states/jotai/contexts/accountOverview/actions.ts Outdated
Comment thread packages/kit/src/hooks/useAllNetwork.ts
Comment thread packages/kit-bg/src/dbs/simple/entity/SimpleDbEntityAccountValue.ts Outdated
Comment thread packages/kit/src/hooks/useAllNetwork.ts
Comment thread packages/kit-bg/src/dbs/simple/entity/SimpleDbEntityAccountValue.ts Outdated
Comment thread packages/shared/src/utils/assetSnapshotFreshness.ts
@weatherstar

Copy link
Copy Markdown
Contributor Author

Status update after re-analysing the customer's iOS log (6.5.2, 2026-09-01):

The header/list mismatch in the screenshot is the shouldHoldCurrentConfirmedBalance gate pinning a persisted total until DeFi readiness arrives, and the cache-only DeFi hook that produces that readiness ran in only 2 of 8 cold starts that day. None of the freshness-marker work in this PR touches that gate.

To keep the 6.5.2 hotfix small, the evidence-backed parts of this PR (refresh queue race, analytics-after-commit, deFiOverviewInitPlan, selector/Others guards) were re-based onto a new branch together with a bounded header hold and a focus-independent DeFi readiness probe: #13124.

This PR keeps the full IAssetSnapshotMeta freshness system. Plan: leave it open, and once #13124 lands on release/v6.5.2 and flows to x, rebase this PR onto x so it only carries the freshness delta and can soak there.

Stacked on fix/wallet-home-header-hold-v6.5.2 (#13124). This commit carries
only the IAssetSnapshotMeta freshness system so it can soak separately:

- shared: assetSnapshotFreshness (localSeq primary, HTTP Date tie-break,
  watermark self-heal), IAssetSnapshotMeta types, resp.assetSnapshotMeta
- bg: ServiceToken mints one marker per fetch; ServiceAccountProfile admits
  active-account-value writes under a mutex; SimpleDb accountValue /
  localTokens admit same-or-newer supplied keys, strictly newer for omitted
  keys, tolerate pre-migration legacy buckets, skip no-op writes
- main: accountOverview.updateAccountWorth admission (equal markers admitted
  for full replacements, retained currency when every value is rejected,
  createAtNetworkWorth recomputed from absolute values, reset flag),
  buildMergedAllNetworkSnapshot / TokenListBlock / HomeOverviewContainer /
  TokenSelector thread the markers through to persistence
@weatherstar
weatherstar force-pushed the fix/ios-wallet-home-asset-refresh-v6.5.2 branch from 7a96275 to 6049014 Compare September 2, 2026 07:24
@weatherstar
weatherstar changed the base branch from release/v6.5.2 to fix/wallet-home-header-hold-v6.5.2 September 2, 2026 07:24
@weatherstar

Copy link
Copy Markdown
Contributor Author

Restacked: this branch was rewritten on top of fix/wallet-home-header-hold-v6.5.2 (#13124) and the PR base was changed accordingly. The diff now contains only the IAssetSnapshotMeta freshness system (20 files); every other fix from the previous history lives in #13124, so the two PRs no longer duplicate code and this one can be rebased onto x without conflicts once the hotfix lands.

The previous head (7a96275, full history incl. review-round commits) is preserved at backup/ios-wallet-home-asset-refresh-v6.5.2-full.

@originalix originalix left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@weatherstar

Automated code review found blocking issues

Reviewed commit 604901406225.

  • P1 · Versioned single-network updates retain previous-network balances

View the full review report

Base automatically changed from fix/wallet-home-header-hold-v6.5.2 to release/v6.5.2 September 4, 2026 08:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants