fix(thorchain): skip /status fetch when no vault uses THORChain#4376
Conversation
InitializeThorChainNetworkIdUseCase only gated on hasVaults(): a user with vaults but no THORChain enabled still triggered GET .../thorchain_rpc/status on every cold start. Extend the gating to also short-circuit when no vault has Chain.ThorChain in its enabled coins. Closes #4366 Co-Authored-By: aminsato <Amin.saradar@yahoo.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughinvoke() now gates THORChain network-id initialization on whether any vault coin is on Chain.ThorChain via vaultRepository.hasAnyCoinOnChain(Chain.ThorChain). Vault/DAO/repository APIs, ViewModel trigger, and tests were updated accordingly; the cached-then-fetch logic and exception behavior remain unchanged. ChangesTHORChain Network ID Conditional Initialization
Sequence DiagramsequenceDiagram
participant VM as MainViewModel
participant VaultRepo as VaultRepository
participant UseCase as InitializeThorChainNetworkIdUseCase
participant ThorRepo as ThorChainRepository
participant Helper as ThorChainHelper
VM->>VaultRepo: observe getAllAsFlow() -> map/distinctUntilChanged/filter/first
VaultRepo-->>VM: emits "has THORChain == true"
VM->>UseCase: initializeThorChainNetworkId()
UseCase->>VaultRepo: hasAnyCoinOnChain(Chain.ThorChain)
alt no THORChain coins
VaultRepo-->>UseCase: false
UseCase->>UseCase: log "no vault uses THORChain" (return)
else has THORChain coins
VaultRepo-->>UseCase: true
UseCase->>ThorRepo: getCachedNetworkChainId()
ThorRepo-->>UseCase: cachedId / null
alt cachedId present
UseCase->>Helper: set THORCHAIN_NETWORK_ID (cachedId)
end
UseCase->>ThorRepo: fetchNetworkChainId()
ThorRepo-->>UseCase: fetchedId / throws
alt fetchedId
UseCase->>Helper: set THORCHAIN_NETWORK_ID (fetchedId)
else throws
ThorRepo-->>UseCase: CancellationException or other
UseCase-->>UseCase: rethrow CancellationException / log others
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
data/src/main/kotlin/com/vultisig/wallet/data/usecases/InitializeThorChainNetworkIdUseCase.kt (1)
20-29: ⚡ Quick winConsider removing the
hasVaults()+getAll()double readLine 21 and Line 53 both hit the repository. You can read vaults once and derive both checks from that list, which reduces I/O and avoids state drift between calls.
Diff suggestion
override suspend fun invoke() { - if (!vaultRepository.hasVaults()) { + val vaults = vaultRepository.getAll() + if (vaults.isEmpty()) { Timber.d("Skipping THORChain network id init: no vaults") return } - if (!isThorChainEnabledInAnyVault()) { + if (!vaults.any { vault -> vault.coins.any { it.chain == Chain.ThorChain } }) { Timber.d("Skipping THORChain network id init: no vault uses THORChain") return } @@ - private suspend fun isThorChainEnabledInAnyVault(): Boolean = - vaultRepository.getAll().any { vault -> vault.coins.any { it.chain == Chain.ThorChain } } + // helper can be removed if not reusedAlso applies to: 52-53
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@data/src/main/kotlin/com/vultisig/wallet/data/usecases/InitializeThorChainNetworkIdUseCase.kt` around lines 20 - 29, Read the vaults once instead of calling vaultRepository.hasVaults() and then isThorChainEnabledInAnyVault(); in InitializeThorChainNetworkIdUseCase.invoke() call vaultRepository.getAll() into a local variable, check if that list is empty to replace hasVaults(), and use that same list to determine if any vault uses THORChain (the logic currently in isThorChainEnabledInAnyVault()) before proceeding; remove the separate hasVaults() call to avoid double repository access and possible state drift.data/src/test/kotlin/com/vultisig/wallet/data/usecases/InitializeThorChainNetworkIdUseCaseImplTest.kt (1)
51-62: ⚡ Quick winTighten branch assertion with repository interaction checks
Since this test targets the “vaults exist but none use THORChain” branch, also verify
getAll()is called once (andhasVaults()once) to make the branch intent explicit.Diff suggestion
useCase() + coVerify(exactly = 1) { vaultRepository.hasVaults() } + coVerify(exactly = 1) { vaultRepository.getAll() } coVerify(exactly = 0) { thorChainRepository.getCachedNetworkChainId() } coVerify(exactly = 0) { thorChainRepository.fetchNetworkChainId() } assertEquals("default-id", ThorChainHelper.THORCHAIN_NETWORK_ID)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@data/src/test/kotlin/com/vultisig/wallet/data/usecases/InitializeThorChainNetworkIdUseCaseImplTest.kt` around lines 51 - 62, Update the test "skips fetch and cache when no vault uses THORChain" to assert repository interactions explicitly: after calling useCase(), add coVerify(exactly = 1) { vaultRepository.hasVaults() } and coVerify(exactly = 1) { vaultRepository.getAll() } so the branch where vaults exist but none use THORChain is tightened while keeping the existing coVerify checks for thorChainRepository.getCachedNetworkChainId() and fetchNetworkChainId().
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In
`@data/src/main/kotlin/com/vultisig/wallet/data/usecases/InitializeThorChainNetworkIdUseCase.kt`:
- Around line 20-29: Read the vaults once instead of calling
vaultRepository.hasVaults() and then isThorChainEnabledInAnyVault(); in
InitializeThorChainNetworkIdUseCase.invoke() call vaultRepository.getAll() into
a local variable, check if that list is empty to replace hasVaults(), and use
that same list to determine if any vault uses THORChain (the logic currently in
isThorChainEnabledInAnyVault()) before proceeding; remove the separate
hasVaults() call to avoid double repository access and possible state drift.
In
`@data/src/test/kotlin/com/vultisig/wallet/data/usecases/InitializeThorChainNetworkIdUseCaseImplTest.kt`:
- Around line 51-62: Update the test "skips fetch and cache when no vault uses
THORChain" to assert repository interactions explicitly: after calling
useCase(), add coVerify(exactly = 1) { vaultRepository.hasVaults() } and
coVerify(exactly = 1) { vaultRepository.getAll() } so the branch where vaults
exist but none use THORChain is tightened while keeping the existing coVerify
checks for thorChainRepository.getCachedNetworkChainId() and
fetchNetworkChainId().
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 2e425fad-c2d5-4e8c-a491-f48e2c70a491
📒 Files selected for processing (2)
data/src/main/kotlin/com/vultisig/wallet/data/usecases/InitializeThorChainNetworkIdUseCase.ktdata/src/test/kotlin/com/vultisig/wallet/data/usecases/InitializeThorChainNetworkIdUseCaseImplTest.kt
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
Read vaults once and derive both empty/ThorChain checks from that list, removing the redundant hasVaults() repository call and inlining the helper. Co-Authored-By: aminsato <Amin.saradar@yahoo.com>
Production code now does a single vaultRepository.getAll() read; the hasVaults() mocks were dead setups. Mock getAll() returning emptyList() explicitly for the no-vaults branch and add coVerify(exactly = 1) for getAll() to lock in the single-read contract. Co-Authored-By: aminsato <Amin.saradar@yahoo.com>
|
@coderabbitai both nitpicks addressed in 88d490f:
All four tests still pass: |
|
Tip For best results, initiate chat on the files or code changes.
All four cases passing confirms the implementation is solid. ✅ |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
data/src/test/kotlin/com/vultisig/wallet/data/usecases/InitializeThorChainNetworkIdUseCaseImplTest.kt (1)
81-88: ⚡ Quick winAssert repository interactions in the fetch-failure test as well.
Right now this test only asserts the final state. Adding call-count checks will ensure the fetch-failure branch is actually exercised (and not silently skipped in a future regression).
Proposed test hardening
`@Test` fun `keeps cached value when fetch fails`() = runTest { coEvery { vaultRepository.getAll() } returns listOf(vaultWithChains(Chain.ThorChain)) coEvery { thorChainRepository.getCachedNetworkChainId() } returns "thorchain-cached" coEvery { thorChainRepository.fetchNetworkChainId() } throws RuntimeException("boom") useCase() + coVerify(exactly = 1) { vaultRepository.getAll() } + coVerify(exactly = 1) { thorChainRepository.getCachedNetworkChainId() } + coVerify(exactly = 1) { thorChainRepository.fetchNetworkChainId() } assertEquals("thorchain-cached", ThorChainHelper.THORCHAIN_NETWORK_ID) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@data/src/test/kotlin/com/vultisig/wallet/data/usecases/InitializeThorChainNetworkIdUseCaseImplTest.kt` around lines 81 - 88, Update the test "keeps cached value when fetch fails" in InitializeThorChainNetworkIdUseCaseImplTest to verify repository interactions so the failure branch is exercised: after invoking useCase(), add coVerify checks that vaultRepository.getAll() was called once, thorChainRepository.getCachedNetworkChainId() was called once, and thorChainRepository.fetchNetworkChainId() was called once (use coVerify(exactly = 1) for each) to assert the fetch was attempted and the cached value was read.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In
`@data/src/test/kotlin/com/vultisig/wallet/data/usecases/InitializeThorChainNetworkIdUseCaseImplTest.kt`:
- Around line 81-88: Update the test "keeps cached value when fetch fails" in
InitializeThorChainNetworkIdUseCaseImplTest to verify repository interactions so
the failure branch is exercised: after invoking useCase(), add coVerify checks
that vaultRepository.getAll() was called once,
thorChainRepository.getCachedNetworkChainId() was called once, and
thorChainRepository.fetchNetworkChainId() was called once (use coVerify(exactly
= 1) for each) to assert the fetch was attempted and the cached value was read.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 87fe7a5d-2229-43a6-83d8-9b21f8157912
📒 Files selected for processing (1)
data/src/test/kotlin/com/vultisig/wallet/data/usecases/InitializeThorChainNetworkIdUseCaseImplTest.kt
Co-Authored-By: aminsato <Amin.saradar@yahoo.com>
…ain coin - Replace `vaultRepository.getAll()` (5 SQL + per-coin token hydration) with a single `SELECT EXISTS(...)` against the coin table for the THORChain presence check, so non-THORChain users no longer pay full vault hydration on cold start. - Wire MainViewModel to await the first vault-list emission containing Chain.ThorChain and re-invoke the use case, so adding a THORChain coin (or importing a THORChain vault) mid-session initializes the live network id instead of silently relying on the default `thorchain-1` constant. - Add a fresh-install test (`getCachedNetworkChainId() == null` + successful fetch) to lock down the path that wasn't covered by the existing tests. Co-Authored-By: aminsato <Amin.saradar@yahoo.com>
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/src/main/java/com/vultisig/wallet/app/activity/MainViewModel.kt`:
- Around line 107-118: The current block in viewModelScope.safeLaunch uses
vaultRepository.getAllAsFlow() which hydrates full Vault objects; replace that
call with a lightweight DAO/Repository flow that only observes presence of a
chain (e.g., add a method like vaultRepository.hasVaultWithChainFlow(chain:
Chain): Flow<Boolean> or getAnyVaultContainsChainFlow(Chain.ThorChain)) and
subscribe to that flow instead, then keep the same distinctUntilChanged().filter
{ it }.first() and call initializeThorChainNetworkId(); update references in
MainViewModel to use the new hasVaultWithChainFlow(Chain.ThorChain) rather than
getAllAsFlow() to avoid full vault hydration.
In
`@data/src/main/kotlin/com/vultisig/wallet/data/repositories/VaultRepository.kt`:
- Around line 95-96: The hasAnyCoinOnChain implementation uses chain.id but
CoinEntity stores the chain key as chain.raw (see toCoinEntity() writing
CoinEntity.chain from chain.raw), so change VaultRepository.hasAnyCoinOnChain to
query the DAO with chain.raw instead of chain.id (i.e., call
vaultDao.hasCoinOnChain(chain.raw)); ensure the DAO signature/column matches the
raw representation used by CoinEntity so the query and stored values use the
same key.
In
`@data/src/main/kotlin/com/vultisig/wallet/data/usecases/InitializeThorChainNetworkIdUseCase.kt`:
- Around line 21-23: The current invoke() in InitializeThorChainNetworkIdUseCase
only skips initialization when no vault coin exists but does not check backend
feature/config; add a pre-check for the backend config/feature flag for
THORChain before calling vaultRepository.hasAnyCoinOnChain so invoke() returns
early if THORChain is disabled by backend. Specifically, in
InitializeThorChainNetworkIdUseCase.invoke(), query the appropriate
feature/config provider (e.g., a backendConfig or featureToggle repository
method that reports whether Chain.ThorChain is enabled) and if it reports
disabled, log and return before making any network /status calls or checking
vaultRepository.hasAnyCoinOnChain. Ensure the new check uses the same
Chain.ThorChain symbol and short-circuits execution when disabled.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 94d9e012-416f-4d17-8ad6-5b7f9eed2569
📒 Files selected for processing (5)
app/src/main/java/com/vultisig/wallet/app/activity/MainViewModel.ktdata/src/main/kotlin/com/vultisig/wallet/data/db/dao/VaultDao.ktdata/src/main/kotlin/com/vultisig/wallet/data/repositories/VaultRepository.ktdata/src/main/kotlin/com/vultisig/wallet/data/usecases/InitializeThorChainNetworkIdUseCase.ktdata/src/test/kotlin/com/vultisig/wallet/data/usecases/InitializeThorChainNetworkIdUseCaseImplTest.kt
Previously MainViewModel collected `vaultRepository.getAllAsFlow()` to wait for the first emission containing THORChain. That hydrates the full vault graph (coins, signers, keyshares, chainPublicKeys + per-coin token logos) on every emission for users who never use THORChain — undoing the cold-start cost reduction the new `EXISTS` query was meant to deliver. Add a flow variant of the targeted query (`Flow<Boolean>` from `SELECT EXISTS(SELECT 1 FROM coin WHERE chain = :chainId)`), expose it via `VaultRepository.observeHasAnyCoinOnChain`, and use it from MainViewModel. Room re-emits when the `coin` table changes, so adding a THORChain coin or importing a THORChain vault still flips the flow and re-triggers init — without ever building a `Vault` object on this path. Co-Authored-By: aminsato <Amin.saradar@yahoo.com>
Summary
InitializeThorChainNetworkIdUseCaseonly gated the THORChain/statuscall onvaultRepository.hasVaults()(from fix: skip THORChain network id fetch on startup when no vaults exist #4321). A user with vaults but no THORChain enabled still triggeredGET https://gateway.liquify.com/chain/thorchain_rpc/statuson every cold start.Chain.ThorChainin its enabled coins, skip both the cache read and the network fetch. Cached/defaultTHORCHAIN_NETWORK_IDis fine because nothing in the app consumes it without a THORChain-enabled vault.Closes #4366
Test plan
./gradlew :data:testDebugUnitTest --tests "*.InitializeThorChainNetworkIdUseCaseImplTest"— added "skips when no vault uses THORChain"; all four cases pass../gradlew :data:ktfmtFormatGET .../thorchain_rpc/statusrequest fires./statusstill fires and the network id initializes.Summary by CodeRabbit
New Features
Tests