Updated on 2026-08-14

This commit is contained in:
Tangem 2025-05-20 18:38:01 +04:00
parent ea3cbd0648
commit fbace5ed35
6 changed files with 233 additions and 19 deletions

View file

@ -4,7 +4,7 @@ import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.tangem.datasource.local.network.entity.NetworkStatusDM.NoAccount
import com.tangem.datasource.local.network.entity.NetworkStatusDM.Verified
import com.tangem.domain.models.network.Network
import dev.onenowy.moshipolymorphicadapter.PolymorphicAdapterType
import dev.onenowy.moshipolymorphicadapter.annotations.NameLabel
import java.math.BigDecimal
@ -13,10 +13,11 @@ import java.math.BigDecimal
*
* @see [com.tangem.domain.tokens.model.NetworkStatus]
*/
@JsonClass(generateAdapter = true, generator = PolymorphicAdapterType.NAME_POLYMORPHIC_ADAPTER)
sealed interface NetworkStatusDM {
/** Network id */
val networkId: Network.ID
val networkId: ID
/** Derivation path */
val derivationPath: DerivationPath
@ -38,7 +39,7 @@ sealed interface NetworkStatusDM {
*/
@NameLabel("amounts")
data class Verified(
@Json(name = "network_id") override val networkId: Network.ID,
@Json(name = "network_id") override val networkId: ID,
@Json(name = "derivation_path") override val derivationPath: DerivationPath,
@Json(name = "selected_address") override val selectedAddress: String,
@Json(name = "available_addresses") override val availableAddresses: Set<Address>,
@ -57,7 +58,7 @@ sealed interface NetworkStatusDM {
*/
@NameLabel("amount_to_create_account")
data class NoAccount(
@Json(name = "network_id") override val networkId: Network.ID,
@Json(name = "network_id") override val networkId: ID,
@Json(name = "derivation_path") override val derivationPath: DerivationPath,
@Json(name = "selected_address") override val selectedAddress: String,
@Json(name = "available_addresses") override val availableAddresses: Set<Address>,
@ -65,6 +66,11 @@ sealed interface NetworkStatusDM {
@Json(name = "error_message") val errorMessage: String,
) : NetworkStatusDM
@JsonClass(generateAdapter = true)
data class ID(
@Json(name = "value") val value: String,
)
@JsonClass(generateAdapter = true)
data class DerivationPath(
@Json(name = "value") val value: String,

View file

@ -0,0 +1,195 @@
package com.tangem.datasource.local.network.entity
import com.google.common.truth.Truth
import com.squareup.moshi.Moshi
import com.squareup.moshi.adapter
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import com.tangem.datasource.api.common.adapter.BigDecimalAdapter
import dev.onenowy.moshipolymorphicadapter.NamePolymorphicAdapterFactory
import org.junit.Test
import java.math.BigDecimal
/**
[REDACTED_AUTHOR]
*/
class NetworkStatusDMSerializationTest {
private val moshi = Moshi.Builder()
.add(
NamePolymorphicAdapterFactory.of(NetworkStatusDM::class.java)
.withSubtype(NetworkStatusDM.Verified::class.java, "amounts")
.withSubtype(NetworkStatusDM.NoAccount::class.java, "amount_to_create_account"),
)
.add(BigDecimalAdapter())
.addLast(KotlinJsonAdapterFactory())
.build()
@OptIn(ExperimentalStdlibApi::class)
private val adapter = moshi.adapter<NetworkStatusDM>()
@Test
fun `deserialize JSON to Verified`() {
// Arrange
val json = """
{
"network_id": { "value": "ETH" },
"derivation_path": {
"value": "m/44'/60'/0'/0/0",
"type": "card"
},
"selected_address": "0x123456",
"available_addresses": [
{ "value": "0x123456", "type": "primary" },
{ "value": "0xabcdef", "type": "secondary" }
],
"amounts": { "ETH": "1.2345" }
}
""".trimIndent()
// Act
val result = adapter.fromJson(json)
// Assert
val expected = NetworkStatusDM.Verified(
networkId = NetworkStatusDM.ID("ETH"),
derivationPath = NetworkStatusDM.DerivationPath(
value = "m/44'/60'/0'/0/0",
type = NetworkStatusDM.DerivationPath.Type.CARD,
),
selectedAddress = "0x123456",
availableAddresses = setOf(
NetworkStatusDM.Address("0x123456", NetworkStatusDM.Address.Type.Primary),
NetworkStatusDM.Address("0xabcdef", NetworkStatusDM.Address.Type.Secondary),
),
amounts = mapOf("ETH" to BigDecimal("1.2345")),
)
Truth.assertThat(result).isEqualTo(expected)
}
@Test
fun `serialize Verified to JSON`() {
// Arrange
val model = NetworkStatusDM.Verified(
networkId = NetworkStatusDM.ID("ETH"),
derivationPath = NetworkStatusDM.DerivationPath(
value = "m/44'/60'/0'/0/0",
type = NetworkStatusDM.DerivationPath.Type.CARD,
),
selectedAddress = "0x123456",
availableAddresses = setOf(
NetworkStatusDM.Address("0x123456", NetworkStatusDM.Address.Type.Primary),
NetworkStatusDM.Address("0xabcdef", NetworkStatusDM.Address.Type.Secondary),
),
amounts = mapOf("ETH" to BigDecimal("1.2345")),
)
// Act
val actual = adapter.toJson(model)
// Assert
val expected = """
{
"network_id": { "value": "ETH" },
"derivation_path": {
"value": "m/44'/60'/0'/0/0",
"type": "card"
},
"selected_address": "0x123456",
"available_addresses": [
{ "value": "0x123456", "type": "primary" },
{ "value": "0xabcdef", "type": "secondary" }
],
"amounts": { "ETH": "1.2345" }
}
""".stripJsonWhitespace()
Truth.assertThat(actual).isEqualTo(expected)
}
@Test
fun `deserialize JSON to NoAccount`() {
// Arrange
val json = """
{
"network_id": { "value": "ETH" },
"derivation_path": {
"value": "m/44'/60'/0'/0/0",
"type": "card"
},
"selected_address": "0x123456",
"available_addresses": [
{ "value": "0x123456", "type": "primary" },
{ "value": "0xabcdef", "type": "secondary" }
],
"amount_to_create_account": "0.05",
"error_message": "Account not found"
}
""".trimIndent()
// Act
val result = adapter.fromJson(json)
// Assert
val expected = NetworkStatusDM.NoAccount(
networkId = NetworkStatusDM.ID("ETH"),
derivationPath = NetworkStatusDM.DerivationPath(
value = "m/44'/60'/0'/0/0",
type = NetworkStatusDM.DerivationPath.Type.CARD,
),
selectedAddress = "0x123456",
availableAddresses = setOf(
NetworkStatusDM.Address("0x123456", NetworkStatusDM.Address.Type.Primary),
NetworkStatusDM.Address("0xabcdef", NetworkStatusDM.Address.Type.Secondary),
),
amountToCreateAccount = BigDecimal("0.05"),
errorMessage = "Account not found",
)
Truth.assertThat(result).isEqualTo(expected)
}
@Test
fun `serialize NoAccount to JSON`() {
// Arrange
val model = NetworkStatusDM.NoAccount(
networkId = NetworkStatusDM.ID("ETH"),
derivationPath = NetworkStatusDM.DerivationPath(
value = "m/44'/60'/0'/0/0",
type = NetworkStatusDM.DerivationPath.Type.CARD,
),
selectedAddress = "0x123456",
availableAddresses = setOf(
NetworkStatusDM.Address("0x123456", NetworkStatusDM.Address.Type.Primary),
NetworkStatusDM.Address("0xabcdef", NetworkStatusDM.Address.Type.Secondary),
),
amountToCreateAccount = BigDecimal("0.05"),
errorMessage = "error",
)
// Act
val actual = adapter.toJson(model)
// Assert
val expected = """
{
"network_id": { "value": "ETH" },
"derivation_path": {
"value": "m/44'/60'/0'/0/0",
"type": "card"
},
"selected_address": "0x123456",
"available_addresses": [
{ "value": "0x123456", "type": "primary" },
{ "value": "0xabcdef", "type": "secondary" }
],
"amount_to_create_account": "0.05",
"error_message": "error"
}
""".stripJsonWhitespace()
Truth.assertThat(actual).isEqualTo(expected)
}
private fun String.stripJsonWhitespace(): String = replace(regex = "\\s".toRegex(), replacement = "")
}

View file

@ -17,7 +17,7 @@ internal object NetworkStatusDataModelConverter : Converter<NetworkStatus, Netwo
val address = NetworkAddressConverter.convertBack(value = status.address)
NetworkStatusDM.Verified(
networkId = value.network.id,
networkId = NetworkStatusDM.ID(value = value.network.rawId),
derivationPath = NetworkDerivationPathConverter.convertBack(value = value.network.derivationPath),
selectedAddress = address.selectedAddress,
availableAddresses = address.addresses,
@ -28,7 +28,7 @@ internal object NetworkStatusDataModelConverter : Converter<NetworkStatus, Netwo
val address = NetworkAddressConverter.convertBack(value = status.address)
NetworkStatusDM.NoAccount(
networkId = value.network.id,
networkId = NetworkStatusDM.ID(value = value.network.rawId),
derivationPath = NetworkDerivationPathConverter.convertBack(value = value.network.derivationPath),
selectedAddress = address.selectedAddress,
availableAddresses = address.addresses,

View file

@ -3,6 +3,7 @@ package com.tangem.data.networks.converters
import com.tangem.data.networks.models.SimpleNetworkStatus
import com.tangem.datasource.local.network.entity.NetworkStatusDM
import com.tangem.domain.models.StatusSource
import com.tangem.domain.models.network.Network
import com.tangem.domain.tokens.model.NetworkStatus
import com.tangem.utils.converter.Converter
@ -40,6 +41,12 @@ internal object SimpleNetworkStatusConverter : Converter<NetworkStatusDM, Simple
}
}
return SimpleNetworkStatus(id = value.networkId, value = status)
return SimpleNetworkStatus(
id = Network.ID(
value = value.networkId.value,
derivationPath = NetworkDerivationPathConverter.convert(value = value.derivationPath),
),
value = status,
)
}
}

View file

@ -63,7 +63,7 @@ internal class NetworkStatusDataModelConverterTest {
),
),
expected = NetworkStatusDM.Verified(
networkId = network.id,
networkId = NetworkStatusDM.ID(network.rawId),
derivationPath = NetworkStatusDM.DerivationPath(
value = "",
type = NetworkStatusDM.DerivationPath.Type.NONE,
@ -97,7 +97,7 @@ internal class NetworkStatusDataModelConverterTest {
),
),
expected = NetworkStatusDM.NoAccount(
networkId = network.id,
networkId = NetworkStatusDM.ID(network.rawId),
derivationPath = NetworkStatusDM.DerivationPath(
value = "",
type = NetworkStatusDM.DerivationPath.Type.NONE,

View file

@ -48,7 +48,7 @@ internal class SimpleNetworkStatusConverterTest {
// region Verified
ConvertModel(
value = NetworkStatusDM.Verified(
networkId = network.id,
networkId = NetworkStatusDM.ID(network.rawId),
derivationPath = NetworkStatusDM.DerivationPath(
value = "card",
type = NetworkStatusDM.DerivationPath.Type.CARD,
@ -70,7 +70,10 @@ internal class SimpleNetworkStatusConverterTest {
),
),
expected = SimpleNetworkStatus(
id = network.id,
id = Network.ID(
value = network.rawId,
derivationPath = Network.DerivationPath.Card("card"),
),
value = NetworkStatus.Verified(
address = NetworkAddress.Selectable(
defaultAddress = NetworkAddress.Address(
@ -110,7 +113,7 @@ internal class SimpleNetworkStatusConverterTest {
// region NoAccount
ConvertModel(
value = NetworkStatusDM.NoAccount(
networkId = network.id,
networkId = NetworkStatusDM.ID(network.rawId),
derivationPath = NetworkStatusDM.DerivationPath(
value = "card",
type = NetworkStatusDM.DerivationPath.Type.CARD,
@ -130,7 +133,10 @@ internal class SimpleNetworkStatusConverterTest {
errorMessage = "errorMessage",
),
expected = SimpleNetworkStatus(
id = network.id,
id = Network.ID(
value = network.rawId,
derivationPath = Network.DerivationPath.Card("card"),
),
value = NetworkStatus.NoAccount(
address = NetworkAddress.Selectable(
defaultAddress = NetworkAddress.Address(
@ -159,7 +165,7 @@ internal class SimpleNetworkStatusConverterTest {
// region Error
ConvertModel(
value = NetworkStatusDM.Verified(
networkId = network.id,
networkId = NetworkStatusDM.ID(network.rawId),
derivationPath = NetworkStatusDM.DerivationPath(
value = "card",
type = NetworkStatusDM.DerivationPath.Type.CARD,
@ -179,7 +185,7 @@ internal class SimpleNetworkStatusConverterTest {
),
ConvertModel(
value = NetworkStatusDM.Verified(
networkId = network.id,
networkId = NetworkStatusDM.ID(network.rawId),
derivationPath = NetworkStatusDM.DerivationPath(
value = "card",
type = NetworkStatusDM.DerivationPath.Type.CARD,
@ -194,7 +200,7 @@ internal class SimpleNetworkStatusConverterTest {
),
ConvertModel(
value = NetworkStatusDM.Verified(
networkId = network.id,
networkId = NetworkStatusDM.ID(network.rawId),
derivationPath = NetworkStatusDM.DerivationPath(
value = "card",
type = NetworkStatusDM.DerivationPath.Type.CARD,
@ -218,7 +224,7 @@ internal class SimpleNetworkStatusConverterTest {
),
ConvertModel(
value = NetworkStatusDM.NoAccount(
networkId = network.id,
networkId = NetworkStatusDM.ID(network.rawId),
derivationPath = NetworkStatusDM.DerivationPath(
value = "card",
type = NetworkStatusDM.DerivationPath.Type.CARD,
@ -243,7 +249,7 @@ internal class SimpleNetworkStatusConverterTest {
),
ConvertModel(
value = NetworkStatusDM.NoAccount(
networkId = network.id,
networkId = NetworkStatusDM.ID(network.rawId),
derivationPath = NetworkStatusDM.DerivationPath(
value = "card",
type = NetworkStatusDM.DerivationPath.Type.CARD,
@ -264,7 +270,7 @@ internal class SimpleNetworkStatusConverterTest {
),
ConvertModel(
value = NetworkStatusDM.NoAccount(
networkId = network.id,
networkId = NetworkStatusDM.ID(network.rawId),
derivationPath = NetworkStatusDM.DerivationPath(
value = "card",
type = NetworkStatusDM.DerivationPath.Type.CARD,