Updated on 2026-08-14

This commit is contained in:
Tangem 2025-11-19 09:16:46 +03:00
commit 6437018fc8
1160 changed files with 35466 additions and 6540 deletions

View file

@ -18,12 +18,11 @@ dependencies {
implementation(deps.moshi.kotlin)
implementation(deps.moshi.adapters)
implementation(deps.kotlin.datetime)
implementation(deps.jodatime)
implementation(deps.kotlin.serialization)
ksp(deps.moshi.kotlin.codegen)
implementation(deps.arrow.core)
testImplementation(deps.test.junit5)
testImplementation(projects.test.core)
testRuntimeOnly(deps.test.junit5.engine)
testImplementation(deps.test.truth)
testImplementation(deps.test.mockk)
}

View file

@ -36,7 +36,9 @@ data class MobileWallet(
if (!publicKey.contentEquals(other.publicKey)) return false
if (chainCode != null) {
if (other.chainCode == null || !chainCode.contentEquals(other.chainCode)) return false
} else if (other.chainCode != null) return false
} else if (other.chainCode != null) {
return false
}
if (curve != other.curve) return false
if (derivedKeys != other.derivedKeys) return false

View file

@ -40,6 +40,10 @@ data class AccountId private constructor(
private val sha256Digest: MessageDigest by lazy { MessageDigest.getInstance("SHA-256") }
private val hexRegex = Regex("^[a-fA-F0-9]{64}$")
fun forMainCryptoPortfolio(userWalletId: UserWalletId): AccountId {
return forCryptoPortfolio(userWalletId = userWalletId, derivationIndex = DerivationIndex.Main)
}
/**
* Creates a unique account identifier for a crypto portfolio
*

View file

@ -74,7 +74,8 @@ sealed interface AccountName {
companion object {
private const val MAX_LENGTH = 20
/** Maximum allowed length for an account name */
const val MAX_LENGTH = 20
/**
* Factory method to create an [AccountName] instance.

View file

@ -17,6 +17,10 @@ sealed interface AccountStatus {
/** The account associated with this status */
val account: Account
/** Unique identifier of the account */
val accountId: AccountId
get() = account.accountId
/**
* Represents the status of a crypto portfolio account
*
@ -34,4 +38,8 @@ sealed interface AccountStatus {
fun flattenCurrencies(): List<CryptoCurrencyStatus> = when (this) {
is CryptoPortfolio -> tokenList.flattenCurrencies()
}
fun getCryptoTokenList(): TokenList = when (this) {
is CryptoPortfolio -> tokenList
}
}

View file

@ -95,6 +95,14 @@ data class Network(
data object None : DerivationPath() {
override val value: String? get() = null
}
fun copySealed(value: String): DerivationPath {
return when (this) {
is Card -> Card(value)
is Custom -> Custom(value)
None -> None
}
}
}
/**

View file

@ -217,7 +217,9 @@ data class CardDTO(
if (signature != null) {
if (other.signature == null) return false
if (!signature.contentEquals(other.signature)) return false
} else if (other.signature != null) return false
} else if (other.signature != null) {
return false
}
return true
}

View file

@ -0,0 +1,24 @@
package com.tangem.domain.models.serialization
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import java.util.Currency
typealias SerializedCurrency = @Serializable(with = CurrencySerializer::class) Currency
object CurrencySerializer : KSerializer<Currency> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("java.util.Currency", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: Currency) {
encoder.encodeString(value.currencyCode)
}
override fun deserialize(decoder: Decoder): Currency {
return Currency.getInstance(decoder.decodeString())
}
}

View file

@ -0,0 +1,24 @@
package com.tangem.domain.models.serialization
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import org.joda.time.DateTime
typealias SerializedDateTime = @Serializable(with = JodaDateTimeSerializer::class) DateTime
object JodaDateTimeSerializer : KSerializer<DateTime> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("DateTime", PrimitiveKind.LONG)
override fun serialize(encoder: Encoder, value: DateTime) {
encoder.encodeLong(value.millis)
}
override fun deserialize(decoder: Decoder): DateTime {
return DateTime(decoder.decodeLong())
}
}

View file

@ -2,15 +2,15 @@ package com.tangem.domain.models.account
import com.google.common.truth.Truth
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.test.core.ProvideTestModels
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class AccountIdTest {
@ParameterizedTest
@MethodSource("provideTestModels")
@ProvideTestModels
fun forCryptoPortfolio(model: ForCryptoPortfolioModel) {
// Arrange
val userWalletId = UserWalletId("27163F47405CE73110837F24DF82607FF11C7AF9D78C93F409E4FEAFF3400C8F")

View file

@ -3,9 +3,9 @@ package com.tangem.domain.models.account
import arrow.core.Either
import arrow.core.left
import com.google.common.truth.Truth
import com.tangem.test.core.ProvideTestModels
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
/**
[REDACTED_AUTHOR]
@ -14,7 +14,7 @@ import org.junit.jupiter.params.provider.MethodSource
class AccountNameTest {
@ParameterizedTest
@MethodSource("provideTestModels")
@ProvideTestModels
fun invoke(model: InvokeTestModel) {
// Act
val actual = AccountName(value = model.value)

View file

@ -4,6 +4,7 @@ import com.google.common.truth.Truth
import com.tangem.domain.models.account.CryptoPortfolioIcon.Color
import com.tangem.domain.models.account.CryptoPortfolioIcon.Icon
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.test.core.ProvideTestModels
import io.mockk.every
import io.mockk.mockkObject
import io.mockk.unmockkObject
@ -11,7 +12,6 @@ import io.mockk.verifyOrder
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
import kotlin.random.Random
/**
@ -25,7 +25,7 @@ class CryptoPortfolioIconTest {
inner class OfMainAccount {
@ParameterizedTest
@MethodSource("provideTestModels")
@ProvideTestModels
fun ofMainAccount(model: OfMainAccountModel) {
// Act
val actual = CryptoPortfolioIcon.ofMainAccount(userWalletId = model.userWalletId)
@ -84,7 +84,7 @@ class CryptoPortfolioIconTest {
inner class OfDefaultCustomAccount {
@ParameterizedTest
@MethodSource("provideTestModels")
@ProvideTestModels
fun ofCustomAccount(model: OfDefaultCustomAccountModel) {
// Arrange
val availableIcons = Icon.entries - setOf(Icon.Letter, Icon.Star)
@ -139,7 +139,7 @@ class CryptoPortfolioIconTest {
inner class OfCustomAccountWithTypeAndColor {
@ParameterizedTest
@MethodSource("provideTestModels")
@ProvideTestModels
fun ofCustomAccount(model: OfCustomAccountModel) {
// Act
val actual = CryptoPortfolioIcon.ofCustomAccount(value = model.icon, color = model.color)

View file

@ -4,10 +4,10 @@ import arrow.core.Either
import arrow.core.left
import arrow.core.right
import com.google.common.truth.Truth
import com.tangem.test.core.ProvideTestModels
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
/**
[REDACTED_AUTHOR]
@ -27,7 +27,7 @@ class DerivationIndexTest {
}
@ParameterizedTest
@MethodSource("provideTestModels")
@ProvideTestModels
fun invoke(model: InvokeTestModel) {
// Act
val actual = DerivationIndex(model.index)