Updated on 2026-08-14
This commit is contained in:
parent
58909db262
commit
08ac0e23d8
4 changed files with 216 additions and 3 deletions
|
|
@ -150,7 +150,7 @@ internal class DefaultDynamicAddressesRepository(
|
|||
}
|
||||
|
||||
private suspend fun isXpubAvailable(userWalletId: UserWalletId, network: Network): Boolean {
|
||||
// Check if WalletManager is already in XPUB mode (dynamic addresses was previously enabled on this device)
|
||||
// Check if WalletManager is already in XPUB mode (dynamic addresses were previously enabled on this device)
|
||||
return walletManagersFacade.getDynamicAddressesReceiveAddress(userWalletId, network) != null
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -265,6 +265,219 @@ internal class DefaultMultiNetworkStatusFetcherTest {
|
|||
coVerify(inverse = true) { commonNetworkStatusFetcher.fetch(any(), any(), any(), any()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch passes xpub to correct network and null to others`() = runTest {
|
||||
// Arrange
|
||||
val xpub = "xpub_test_eth"
|
||||
val params = setupTwoNetworkParams()
|
||||
coEvery { dynamicAddressesInitializer.getXpubs(params.userWalletId, params.networks) } returns mapOf(ethereum.network to xpub)
|
||||
|
||||
coEvery {
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = ethereum.network,
|
||||
networkCurrencies = setOf(ethereum),
|
||||
xpub = xpub,
|
||||
)
|
||||
} returns Either.Right(Unit)
|
||||
coEvery {
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = cardano.network,
|
||||
networkCurrencies = setOf(cardano),
|
||||
xpub = null,
|
||||
)
|
||||
} returns Either.Right(Unit)
|
||||
|
||||
// Act
|
||||
val actual = fetcher(params)
|
||||
|
||||
// Assert
|
||||
val expected = Either.Right(Unit)
|
||||
assertEither(actual, expected)
|
||||
coVerify(exactly = 1) {
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = ethereum.network,
|
||||
networkCurrencies = setOf(ethereum),
|
||||
xpub = xpub,
|
||||
)
|
||||
}
|
||||
coVerify(exactly = 1) {
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = cardano.network,
|
||||
networkCurrencies = setOf(cardano),
|
||||
xpub = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch continues with null xpub for all networks if getXpubs throws`() = runTest {
|
||||
// Arrange
|
||||
val params = setupTwoNetworkParams()
|
||||
coEvery {
|
||||
dynamicAddressesInitializer.getXpubs(params.userWalletId, params.networks)
|
||||
} throws RuntimeException("XPUB derivation failed")
|
||||
|
||||
val fetchResult = Either.Right(Unit)
|
||||
coEvery {
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = ethereum.network,
|
||||
networkCurrencies = setOf(ethereum),
|
||||
xpub = null,
|
||||
)
|
||||
} returns fetchResult
|
||||
coEvery {
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = cardano.network,
|
||||
networkCurrencies = setOf(cardano),
|
||||
xpub = null,
|
||||
)
|
||||
} returns fetchResult
|
||||
|
||||
// Act
|
||||
val actual = fetcher(params)
|
||||
|
||||
// Assert
|
||||
val expected = Either.Right(Unit)
|
||||
assertEither(actual, expected)
|
||||
coVerify(exactly = 1) {
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = ethereum.network,
|
||||
networkCurrencies = setOf(ethereum),
|
||||
xpub = null,
|
||||
)
|
||||
}
|
||||
coVerify(exactly = 1) {
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = cardano.network,
|
||||
networkCurrencies = setOf(cardano),
|
||||
xpub = null,
|
||||
)
|
||||
}
|
||||
// getXpubs failure must not degrade network status to OnlyCache
|
||||
coVerify(inverse = true) { networksStatusesStore.setSourceAsOnlyCache(userWalletId = any(), networks = any()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch passes xpubs to all networks returned by getXpubs`() = runTest {
|
||||
// Arrange
|
||||
val ethXpub = "xpub_eth"
|
||||
val adaXpub = "xpub_ada"
|
||||
val params = setupTwoNetworkParams()
|
||||
coEvery {
|
||||
dynamicAddressesInitializer.getXpubs(params.userWalletId, params.networks)
|
||||
} returns mapOf(ethereum.network to ethXpub, cardano.network to adaXpub)
|
||||
|
||||
coEvery {
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = ethereum.network,
|
||||
networkCurrencies = setOf(ethereum),
|
||||
xpub = ethXpub,
|
||||
)
|
||||
} returns Either.Right(Unit)
|
||||
coEvery {
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = cardano.network,
|
||||
networkCurrencies = setOf(cardano),
|
||||
xpub = adaXpub,
|
||||
)
|
||||
} returns Either.Right(Unit)
|
||||
|
||||
// Act
|
||||
val actual = fetcher(params)
|
||||
|
||||
// Assert
|
||||
val expected = Either.Right(Unit)
|
||||
assertEither(actual, expected)
|
||||
coVerify(exactly = 1) {
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = ethereum.network,
|
||||
networkCurrencies = setOf(ethereum),
|
||||
xpub = ethXpub,
|
||||
)
|
||||
}
|
||||
coVerify(exactly = 1) {
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = cardano.network,
|
||||
networkCurrencies = setOf(cardano),
|
||||
xpub = adaXpub,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch calls getXpubs with exactly the networks from params`() = runTest {
|
||||
// Arrange
|
||||
val params = setupTwoNetworkParams()
|
||||
coEvery {
|
||||
commonNetworkStatusFetcher.fetch(userWalletId = any(), network = any(), networkCurrencies = any(), xpub = any())
|
||||
} returns Either.Right(Unit)
|
||||
|
||||
// Act
|
||||
fetcher(params)
|
||||
|
||||
// Assert
|
||||
coVerify(exactly = 1) { dynamicAddressesInitializer.getXpubs(params.userWalletId, params.networks) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch failure if network fetch fails when xpub is provided`() = runTest {
|
||||
// Arrange
|
||||
val xpub = "xpub_eth"
|
||||
val params = setupTwoNetworkParams()
|
||||
coEvery {
|
||||
dynamicAddressesInitializer.getXpubs(params.userWalletId, params.networks)
|
||||
} returns mapOf(ethereum.network to xpub)
|
||||
|
||||
val fetchFailure = Either.Left(IllegalStateException())
|
||||
coEvery {
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = ethereum.network,
|
||||
networkCurrencies = setOf(ethereum),
|
||||
xpub = xpub,
|
||||
)
|
||||
} returns fetchFailure
|
||||
coEvery {
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = cardano.network,
|
||||
networkCurrencies = setOf(cardano),
|
||||
xpub = null,
|
||||
)
|
||||
} returns Either.Right(Unit)
|
||||
|
||||
// Act
|
||||
val actual = fetcher(params)
|
||||
|
||||
// Assert
|
||||
val expected = Either.Left(IllegalStateException("Failed to fetch network statuses"))
|
||||
assertEither(actual, expected)
|
||||
}
|
||||
|
||||
private fun setupTwoNetworkParams(): MultiNetworkStatusFetcher.Params {
|
||||
val params = MultiNetworkStatusFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
networks = setOf(ethereum.network, cardano.network),
|
||||
)
|
||||
coEvery { cardCryptoCurrencyFactory.create(params.userWalletId, params.networks) } returns mapOf(
|
||||
ethereum.network to listOf(ethereum),
|
||||
cardano.network to listOf(cardano),
|
||||
)
|
||||
return params
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val userWalletId = UserWalletId("011")
|
||||
val cryptoCurrencyFactory = MockCryptoCurrencyFactory()
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class DisableDynamicAddressesUseCase(
|
|||
|
||||
/**
|
||||
* Returns true when consolidation is required before disabling (non-base balances exist),
|
||||
* or false when dynamic addresses was disabled immediately.
|
||||
* or false when dynamic addresses were disabled immediately.
|
||||
*/
|
||||
suspend operator fun invoke(userWalletId: UserWalletId, network: Network): Either<Throwable, Boolean> =
|
||||
Either.catch {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import com.tangem.blockchainsdk.utils.toNetworkId
|
|||
* List of blockchains that support Dynamic Addresses (XPUB-based multi-address mode).
|
||||
* Must match [Blockchain.isBip44DerivationStyleXPUB] from blockchain-sdk minus Kaspa (deferred).
|
||||
*
|
||||
* Dynamic addresses is NOT used for Legacy (m/44' for BTC/LTC) or Taproot (m/86') addresses.
|
||||
* Dynamic addresses are NOT used for Legacy (m/44' for BTC/LTC) or Taproot (m/86') addresses.
|
||||
* Only the default derivation style per blockchain is supported.
|
||||
*/
|
||||
object DynamicAddressesSupportedBlockchains {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue