Updated on 2026-08-14
This commit is contained in:
parent
22fc180d9e
commit
b004f8df6b
5 changed files with 83 additions and 14 deletions
|
|
@ -1,7 +1,9 @@
|
|||
package com.tangem.data.networks.converters
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchainsdk.utils.toBlockchain
|
||||
import com.tangem.blockchainsdk.utils.toCoinId
|
||||
import com.tangem.blockchainsdk.utils.toNetworkId
|
||||
import com.tangem.datasource.local.network.entity.NetworkStatusDM.CurrencyId
|
||||
import com.tangem.datasource.local.network.entity.NetworkStatusDM.CurrencyId.Companion.CONTRACT_ADDRESS_DELIMITER
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
|
|
@ -22,6 +24,12 @@ internal class NetworkCurrencyIdConverter(
|
|||
private val derivationPath: Network.DerivationPath,
|
||||
) : TwoWayConverter<CurrencyId, CryptoCurrency.ID> {
|
||||
|
||||
// Cache stores blockchainId in legacy format (e.g. "BTC"), but runtime
|
||||
// CryptoCurrency.ID expects the new network rawId (e.g. "bitcoin") matching
|
||||
// Network.rawId built from Blockchain.toNetworkId(). Convert once on construction
|
||||
// so that IDs reconstructed from cache match those built at runtime.
|
||||
private val networkRawId: String = Blockchain.fromId(blockchainId).toNetworkId()
|
||||
|
||||
override fun convert(value: CurrencyId): CryptoCurrency.ID {
|
||||
val suffixParts = value.value.split(CONTRACT_ADDRESS_DELIMITER)
|
||||
|
||||
|
|
@ -80,17 +88,17 @@ internal class NetworkCurrencyIdConverter(
|
|||
return when (derivationPath) {
|
||||
is Network.DerivationPath.Card -> {
|
||||
CryptoCurrency.ID.Body.NetworkIdWithDerivationPath(
|
||||
rawId = blockchainId,
|
||||
rawId = networkRawId,
|
||||
derivationPath = derivationPath.value,
|
||||
)
|
||||
}
|
||||
is Network.DerivationPath.Custom -> {
|
||||
CryptoCurrency.ID.Body.NetworkIdWithDerivationPath(
|
||||
rawId = blockchainId,
|
||||
rawId = networkRawId,
|
||||
derivationPath = derivationPath.value,
|
||||
)
|
||||
}
|
||||
is Network.DerivationPath.None -> CryptoCurrency.ID.Body.NetworkId(blockchainId)
|
||||
is Network.DerivationPath.None -> CryptoCurrency.ID.Body.NetworkId(networkRawId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,10 +16,14 @@ import java.math.BigDecimal
|
|||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
internal class NetworkAmountsConverterTest {
|
||||
|
||||
private val rawNetworkId = "ethereum"
|
||||
// Cache stores the SDK-level Blockchain.id (legacy format, e.g. "ETH").
|
||||
// The converter normalizes it to the canonical network rawId ("ethereum") via
|
||||
// Blockchain.fromId(...).toNetworkId() so that resulting CryptoCurrency.IDs match those
|
||||
// built at runtime from Network.rawId.
|
||||
private val blockchainId = "ETH"
|
||||
private val derivationPath = Network.DerivationPath.Card(value = "m/44'/60'/0'/0/0")
|
||||
private val derivationPathHashCode = "-1843072795"
|
||||
private val converter = NetworkAmountsConverter(blockchainId = rawNetworkId, derivationPath = derivationPath)
|
||||
private val converter = NetworkAmountsConverter(blockchainId = blockchainId, derivationPath = derivationPath)
|
||||
|
||||
@Test
|
||||
fun convert() {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.domain.models.currency.CryptoCurrency
|
|||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.test.core.ProvideTestModels
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
|
||||
|
|
@ -15,10 +16,14 @@ import org.junit.jupiter.params.ParameterizedTest
|
|||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class NetworkCurrencyIdConverterTest {
|
||||
|
||||
private val rawNetworkId = "ethereum"
|
||||
// Legacy SDK format stored in cache (see NetworkStatusDataModelConverter:
|
||||
// `value.network.toBlockchain().id`). Runtime CryptoCurrency.ID expects the canonical
|
||||
// network rawId ("ethereum"), so the converter normalizes via Blockchain.fromId(...).toNetworkId().
|
||||
private val blockchainId = "ETH"
|
||||
private val canonicalNetworkRawId = "ethereum"
|
||||
private val derivationPath = Network.DerivationPath.Card(value = "m/44'/60'/0'/0/0")
|
||||
private val derivationPathHashCode = "-1843072795"
|
||||
private val converter = NetworkCurrencyIdConverter(blockchainId = rawNetworkId, derivationPath = derivationPath)
|
||||
private val converter = NetworkCurrencyIdConverter(blockchainId = blockchainId, derivationPath = derivationPath)
|
||||
|
||||
@Nested
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
|
|
@ -54,13 +59,13 @@ class NetworkCurrencyIdConverterTest {
|
|||
ConvertModel(
|
||||
value = CurrencyId.createCoinId(""),
|
||||
expected = Result.failure(
|
||||
IllegalStateException("Coin id is null for $rawNetworkId with $derivationPath"),
|
||||
IllegalStateException("Coin id is null for $blockchainId with $derivationPath"),
|
||||
),
|
||||
),
|
||||
ConvertModel(
|
||||
value = CurrencyId.createCoinId(" "),
|
||||
expected = Result.failure(
|
||||
IllegalStateException("Coin id is null for $rawNetworkId with $derivationPath"),
|
||||
IllegalStateException("Coin id is null for $blockchainId with $derivationPath"),
|
||||
),
|
||||
),
|
||||
// create token id
|
||||
|
|
@ -184,6 +189,54 @@ class NetworkCurrencyIdConverterTest {
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Regression coverage for [REDACTED_TASK_KEY]. Cache stores `blockchainId` in the legacy SDK format
|
||||
* (`Blockchain.id`, e.g. "ETH"), but runtime [CryptoCurrency.ID] is built using the canonical
|
||||
* network rawId (`Blockchain.toNetworkId()`, e.g. "ethereum"). The converter must bridge the
|
||||
* two formats so that IDs reconstructed from cache equal those built at runtime — otherwise
|
||||
* `NetworkStatus.Verified.amounts[currency.id]` returns null and the wallet shimmer never clears.
|
||||
*/
|
||||
@Nested
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
inner class LegacyBlockchainIdNormalization {
|
||||
|
||||
@Test
|
||||
fun `convert with legacy ETH blockchainId produces id with canonical ethereum rawId`() {
|
||||
val cached = CurrencyId.createCoinId("ethereum")
|
||||
|
||||
val result = converter.convert(cached)
|
||||
|
||||
Truth.assertThat(result)
|
||||
.isEqualTo(CryptoCurrency.ID.fromValue("coin⟨$canonicalNetworkRawId→$derivationPathHashCode⟩ethereum"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `convert with legacy BTC blockchainId produces id with canonical bitcoin rawId`() {
|
||||
val btcDerivationPath = Network.DerivationPath.Card(value = "m/44'/0'/0'/0/0")
|
||||
val btcDerivationHash = btcDerivationPath.value.hashCode()
|
||||
val btcConverter = NetworkCurrencyIdConverter(
|
||||
blockchainId = "BTC",
|
||||
derivationPath = btcDerivationPath,
|
||||
)
|
||||
val cached = CurrencyId.createCoinId("bitcoin")
|
||||
|
||||
val result = btcConverter.convert(cached)
|
||||
|
||||
Truth.assertThat(result)
|
||||
.isEqualTo(CryptoCurrency.ID.fromValue("coin⟨bitcoin→$btcDerivationHash⟩bitcoin"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `convert and convertBack roundtrip preserves CurrencyId`() {
|
||||
val cached = CurrencyId.createCoinId("ethereum")
|
||||
|
||||
val runtimeId = converter.convert(cached)
|
||||
val roundTrip = converter.convertBack(runtimeId)
|
||||
|
||||
Truth.assertThat(roundTrip).isEqualTo(cached)
|
||||
}
|
||||
}
|
||||
|
||||
data class ConvertModel(val value: CurrencyId, val expected: Result<CryptoCurrency.ID>)
|
||||
|
||||
data class ConvertBackModel(val value: CryptoCurrency.ID, val expected: Result<CurrencyId>)
|
||||
|
|
|
|||
|
|
@ -13,10 +13,14 @@ import java.math.BigDecimal
|
|||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
internal class NetworkYieldSupplyStatusConverterTest {
|
||||
|
||||
private val rawNetworkId = "ethereum"
|
||||
// Cache stores the SDK-level Blockchain.id (legacy format, e.g. "ETH").
|
||||
// The converter normalizes it to the canonical network rawId ("ethereum") via
|
||||
// Blockchain.fromId(...).toNetworkId() so that resulting CryptoCurrency.IDs match those
|
||||
// built at runtime from Network.rawId.
|
||||
private val blockchainId = "ETH"
|
||||
private val derivationPath = Network.DerivationPath.Card(value = "m/44'/60'/0'/0/0")
|
||||
private val derivationPathHashCode = "-1843072795"
|
||||
private val converter = NetworkYieldSupplyStatusConverter(rawNetworkId, derivationPath)
|
||||
private val converter = NetworkYieldSupplyStatusConverter(blockchainId, derivationPath)
|
||||
|
||||
private val domainStatus = YieldSupplyStatus(
|
||||
isActive = true,
|
||||
|
|
|
|||
|
|
@ -96,12 +96,12 @@ internal class SimpleNetworkStatusConverterTest {
|
|||
),
|
||||
),
|
||||
amounts = mapOf(
|
||||
ID.fromValue("coin⟨ETH→3046160⟩ethereum") to Amount.Loaded(value = BigDecimal.ZERO),
|
||||
ID.fromValue("token⟨ETH→3046160⟩usdt⚓0x1") to Amount.Loaded(value = BigDecimal.ZERO),
|
||||
ID.fromValue("coin⟨ethereum→3046160⟩ethereum") to Amount.Loaded(value = BigDecimal.ZERO),
|
||||
ID.fromValue("token⟨ethereum→3046160⟩usdt⚓0x1") to Amount.Loaded(value = BigDecimal.ZERO),
|
||||
),
|
||||
pendingTransactions = emptyMap(),
|
||||
yieldSupplyStatuses = mapOf(
|
||||
ID.fromValue("coin⟨ETH→3046160⟩ethereum") to YieldSupplyStatus(
|
||||
ID.fromValue("coin⟨ethereum→3046160⟩ethereum") to YieldSupplyStatus(
|
||||
isActive = false,
|
||||
isInitialized = false,
|
||||
isAllowedToSpend = false,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue