Updated on 2026-08-14

This commit is contained in:
Tangem 2025-07-16 13:35:39 +03:00
parent 8541957ee3
commit 189ffd9927
73 changed files with 547 additions and 409 deletions

View file

@ -2,7 +2,6 @@ package com.tangem.data.common.currency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
@ -57,23 +56,23 @@ interface CardCryptoCurrencyFactory {
/**
* Create default coins for multi currency card
*
* @param scanResponse scan response
* @param userWallet user wallet
*/
fun createDefaultCoinsForMultiCurrencyCard(scanResponse: ScanResponse): List<CryptoCurrency.Coin>
fun createDefaultCoinsForMultiCurrencyWallet(userWallet: UserWallet): List<CryptoCurrency.Coin>
/**
* Create primary currency for single currency card
*
* @param scanResponse scan response
* @param userWallet user wallet
*/
@Throws
fun createPrimaryCurrencyForSingleCurrencyCard(scanResponse: ScanResponse): CryptoCurrency
fun createPrimaryCurrencyForSingleCurrencyCard(userWallet: UserWallet.Cold): CryptoCurrency
/**
* Create currencies for single currency card with token (like, NODL)
*
* @param scanResponse scan response
* @param userWallet user wallet
*/
@Throws
fun createCurrenciesForSingleCurrencyCardWithToken(scanResponse: ScanResponse): List<CryptoCurrency>
fun createCurrenciesForSingleCurrencyCardWithToken(userWallet: UserWallet.Cold): List<CryptoCurrency>
}

View file

@ -8,7 +8,7 @@ import com.tangem.blockchainsdk.utils.toCoinId
import com.tangem.data.common.network.NetworkFactory
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.models.UserWallet
import timber.log.Timber
import com.tangem.blockchain.common.Token as SdkToken
@ -46,7 +46,7 @@ class CryptoCurrencyFactory(
sdkToken: SdkToken,
blockchain: Blockchain,
extraDerivationPath: String?,
scanResponse: ScanResponse,
userWallet: UserWallet,
): CryptoCurrency.Token? {
if (blockchain == Blockchain.Unknown) {
Timber.e("Unable to map the SDK token to the domain token with Unknown blockchain")
@ -56,7 +56,7 @@ class CryptoCurrencyFactory(
val network = networkFactory.create(
blockchain = blockchain,
extraDerivationPath = extraDerivationPath,
scanResponse = scanResponse,
userWallet = userWallet,
) ?: return null
val id = getTokenId(network, sdkToken)
@ -76,7 +76,7 @@ class CryptoCurrencyFactory(
fun createCoin(
blockchain: Blockchain,
extraDerivationPath: String?,
scanResponse: ScanResponse,
userWallet: UserWallet,
): CryptoCurrency.Coin? {
if (blockchain == Blockchain.Unknown) {
Timber.e("Unable to map the SDK token to the domain token with Unknown blockchain")
@ -86,15 +86,15 @@ class CryptoCurrencyFactory(
val network = networkFactory.create(
blockchain = blockchain,
extraDerivationPath = extraDerivationPath,
scanResponse = scanResponse,
userWallet = userWallet,
) ?: return null
return createCoin(network)
}
fun createCoin(networkId: String, extraDerivationPath: String?, scanResponse: ScanResponse): CryptoCurrency.Coin? {
fun createCoin(networkId: String, extraDerivationPath: String?, userWallet: UserWallet): CryptoCurrency.Coin? {
val blockchain = Blockchain.fromNetworkId(networkId) ?: Blockchain.Unknown
return createCoin(blockchain, extraDerivationPath, scanResponse)
return createCoin(blockchain, extraDerivationPath, userWallet)
}
fun createCoin(network: Network): CryptoCurrency.Coin {
@ -115,7 +115,7 @@ class CryptoCurrencyFactory(
token: Token,
networkId: String,
extraDerivationPath: String?,
scanResponse: ScanResponse,
userWallet: UserWallet,
): CryptoCurrency.Token? {
val sdkToken = SdkToken(
name = token.name,
@ -129,7 +129,7 @@ class CryptoCurrencyFactory(
sdkToken = sdkToken,
blockchain = blockchain,
extraDerivationPath = extraDerivationPath,
scanResponse = scanResponse,
userWallet = userWallet,
)
}
@ -141,7 +141,8 @@ class CryptoCurrencyFactory(
decimals = cryptoCurrency.decimals,
id = cryptoCurrency.id.rawCurrencyId?.value,
)
val blockchain = Blockchain.fromNetworkId(cryptoCurrency.network.backendId) ?: Blockchain.Unknown
val blockchain =
Blockchain.fromNetworkId(cryptoCurrency.network.backendId) ?: Blockchain.Unknown
val id = getTokenId(network, sdkToken)
return CryptoCurrency.Token(
id = id,

View file

@ -11,11 +11,9 @@ import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.demo.DemoConfig
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.isMultiCurrency
import com.tangem.domain.wallets.models.requireColdWallet
/**
* Default implementation of factory for creating list of [CryptoCurrency] for selected card
@ -54,12 +52,12 @@ internal class DefaultCardCryptoCurrencyFactory(
// single-currency wallet with token (NODL)
if (userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()) {
val currencies = createCurrenciesForSingleCurrencyCardWithToken(userWallet.scanResponse)
val currencies = createCurrenciesForSingleCurrencyCardWithToken(userWallet)
return mapOf(cardNetwork to currencies)
}
// single-currency wallet
val primaryCurrency = createPrimaryCurrencyForSingleCurrencyCard(userWallet.scanResponse)
val primaryCurrency = createPrimaryCurrencyForSingleCurrencyCard(userWallet)
return mapOf(cardNetwork to listOf(primaryCurrency))
}
@ -82,11 +80,11 @@ internal class DefaultCardCryptoCurrencyFactory(
// single-currency wallet with token (NODL)
if (userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()) {
return createCurrenciesForSingleCurrencyCardWithToken(userWallet.scanResponse)
return createCurrenciesForSingleCurrencyCardWithToken(userWallet)
}
// single-currency wallet
return createPrimaryCurrencyForSingleCurrencyCard(userWallet.scanResponse).let(::listOf)
return createPrimaryCurrencyForSingleCurrencyCard(userWallet).let(::listOf)
}
override suspend fun createCurrenciesForMultiCurrencyCard(
@ -98,44 +96,54 @@ internal class DefaultCardCryptoCurrencyFactory(
return getMultiWalletCurrencies(userWallet = userWallet, networks = networks)
}
override fun createDefaultCoinsForMultiCurrencyCard(scanResponse: ScanResponse): List<CryptoCurrency.Coin> {
require(scanResponse.cardTypesResolver.isMultiwalletAllowed()) { "It isn't multi-currency wallet" }
override fun createDefaultCoinsForMultiCurrencyWallet(userWallet: UserWallet): List<CryptoCurrency.Coin> {
require(userWallet.isMultiCurrency) { "It isn't multi-currency wallet" }
val card = scanResponse.card
val blockchains = when (userWallet) {
is UserWallet.Cold -> {
val card = userWallet.scanResponse.card
var blockchains = if (demoConfig.isDemoCardId(card.cardId)) {
demoConfig.demoBlockchains
} else {
listOf(Blockchain.Bitcoin, Blockchain.Ethereum)
}
var blockchainsInternal = if (demoConfig.isDemoCardId(card.cardId)) {
demoConfig.demoBlockchains
} else {
listOf(Blockchain.Bitcoin, Blockchain.Ethereum)
}
if (card.isTestCard) {
blockchains = blockchains.mapNotNull { it.getTestnetVersion() }
if (card.isTestCard) {
blockchainsInternal = blockchainsInternal.mapNotNull { it.getTestnetVersion() }
}
blockchainsInternal
}
is UserWallet.Hot -> listOf(Blockchain.Bitcoin, Blockchain.Ethereum)
}
return blockchains.mapNotNull {
cryptoCurrencyFactory.createCoin(
blockchain = it,
extraDerivationPath = null,
scanResponse = scanResponse,
userWallet = userWallet,
)
}
}
override fun createPrimaryCurrencyForSingleCurrencyCard(scanResponse: ScanResponse): CryptoCurrency {
require(scanResponse.cardTypesResolver.isSingleWallet()) { "It isn't single-currency wallet" }
override fun createPrimaryCurrencyForSingleCurrencyCard(userWallet: UserWallet.Cold): CryptoCurrency {
require(userWallet.scanResponse.cardTypesResolver.isSingleWallet()) {
"It isn't single-currency wallet"
}
return with(getSingleWalletCurrencies(scanResponse)) {
return with(getSingleWalletCurrencies(userWallet)) {
primaryToken ?: coin
}
}
override fun createCurrenciesForSingleCurrencyCardWithToken(scanResponse: ScanResponse): List<CryptoCurrency> {
require(scanResponse.cardTypesResolver.isSingleWalletWithToken()) {
override fun createCurrenciesForSingleCurrencyCardWithToken(userWallet: UserWallet.Cold): List<CryptoCurrency> {
require(userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()) {
"It isn't single-currency wallet with token"
}
return with(getSingleWalletCurrencies(scanResponse)) {
return with(getSingleWalletCurrencies(userWallet)) {
listOfNotNull(coin, primaryToken)
}
}
@ -151,7 +159,7 @@ internal class DefaultCardCryptoCurrencyFactory(
tokens = response.tokens.filter { token ->
networks.any { it.backendId == token.networkId && it.derivationPath.value == token.derivationPath }
},
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY]
userWallet = userWallet,
)
.groupBy(CryptoCurrency::network)
@ -169,19 +177,19 @@ internal class DefaultCardCryptoCurrencyFactory(
return responseCryptoCurrenciesFactory.createCurrencies(
tokens = response.tokens.filter { token -> token.networkId in networkIds },
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY]
userWallet = userWallet,
)
.groupBy { it.network.id.rawId }
}
private fun getSingleWalletCurrencies(scanResponse: ScanResponse): SingleWalletCurrencies {
val resolver = scanResponse.cardTypesResolver
private fun getSingleWalletCurrencies(userWallet: UserWallet.Cold): SingleWalletCurrencies {
val resolver = userWallet.cardTypesResolver
val blockchain = resolver.getBlockchain()
val coin = cryptoCurrencyFactory.createCoin(
blockchain = blockchain,
extraDerivationPath = null,
scanResponse = scanResponse,
userWallet = userWallet,
)
requireNotNull(coin) { "Coin for the single currency card cannot be null" }
@ -191,12 +199,15 @@ internal class DefaultCardCryptoCurrencyFactory(
sdkToken = token,
blockchain = blockchain,
extraDerivationPath = null,
scanResponse = scanResponse,
userWallet = userWallet,
)
}
return SingleWalletCurrencies(coin = coin, primaryToken = primaryToken)
}
private data class SingleWalletCurrencies(val coin: CryptoCurrency, val primaryToken: CryptoCurrency?)
private data class SingleWalletCurrencies(
val coin: CryptoCurrency,
val primaryToken: CryptoCurrency?,
)
}

View file

@ -8,7 +8,7 @@ import com.tangem.data.common.network.NetworkFactory
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.models.UserWallet
import timber.log.Timber
import javax.inject.Inject
import com.tangem.blockchain.common.Token as SdkToken
@ -17,41 +17,41 @@ class ResponseCryptoCurrenciesFactory @Inject constructor(
private val networkFactory: NetworkFactory,
) {
fun createCurrency(currencyId: String, response: UserTokensResponse, scanResponse: ScanResponse): CryptoCurrency {
fun createCurrency(currencyId: String, response: UserTokensResponse, userWallet: UserWallet): CryptoCurrency {
return response.tokens
.asSequence()
.mapNotNull { createCurrency(it, scanResponse) }
.mapNotNull { createCurrency(it, userWallet) }
.first { it.id.value == currencyId }
}
fun createCurrencies(response: UserTokensResponse, scanResponse: ScanResponse): List<CryptoCurrency> {
return createCurrencies(tokens = response.tokens, scanResponse = scanResponse)
fun createCurrencies(response: UserTokensResponse, userWallet: UserWallet): List<CryptoCurrency> {
return createCurrencies(tokens = response.tokens, userWallet = userWallet)
}
fun createCurrencies(tokens: List<UserTokensResponse.Token>, scanResponse: ScanResponse): List<CryptoCurrency> {
fun createCurrencies(tokens: List<UserTokensResponse.Token>, userWallet: UserWallet): List<CryptoCurrency> {
return tokens
.asSequence()
.mapNotNull { createCurrency(it, scanResponse) }
.mapNotNull { createCurrency(it, userWallet) }
.distinctBy(CryptoCurrency::id)
.toList()
}
fun createCurrency(responseToken: UserTokensResponse.Token, scanResponse: ScanResponse): CryptoCurrency? {
fun createCurrency(responseToken: UserTokensResponse.Token, userWallet: UserWallet): CryptoCurrency? {
var blockchain = Blockchain.fromNetworkId(responseToken.networkId)
if (blockchain == null || blockchain == Blockchain.Unknown) {
Timber.e("Unable to find a blockchain with the network ID: ${responseToken.networkId}")
return null
}
if (scanResponse.cardTypesResolver.isTestCard()) {
if (userWallet is UserWallet.Cold && userWallet.scanResponse.cardTypesResolver.isTestCard()) {
blockchain = blockchain.getTestnetVersion() ?: blockchain
}
val sdkToken = createSdkToken(responseToken)
return if (sdkToken == null) {
createCoin(blockchain, responseToken, scanResponse)
createCoin(blockchain, responseToken, userWallet)
} else {
createToken(blockchain, sdkToken, responseToken.derivationPath, scanResponse)
createToken(blockchain, sdkToken, responseToken.derivationPath, userWallet)
}
}
@ -70,12 +70,12 @@ class ResponseCryptoCurrenciesFactory @Inject constructor(
private fun createCoin(
blockchain: Blockchain,
responseToken: UserTokensResponse.Token,
scanResponse: ScanResponse,
userWallet: UserWallet,
): CryptoCurrency.Coin? {
val network = networkFactory.create(
blockchain = blockchain,
extraDerivationPath = responseToken.derivationPath,
scanResponse = scanResponse,
userWallet = userWallet,
) ?: return null
return CryptoCurrency.Coin(
@ -105,12 +105,12 @@ class ResponseCryptoCurrenciesFactory @Inject constructor(
blockchain: Blockchain,
sdkToken: Token,
responseDerivationPath: String?,
scanResponse: ScanResponse,
userWallet: UserWallet,
): CryptoCurrency.Token? {
val network = networkFactory.create(
blockchain = blockchain,
extraDerivationPath = responseDerivationPath,
scanResponse = scanResponse,
userWallet = userWallet,
) ?: return null
val id = getTokenId(network, sdkToken)

View file

@ -8,10 +8,9 @@ import com.tangem.blockchainsdk.utils.toBlockchain
import com.tangem.blockchainsdk.utils.toNetworkId
import com.tangem.domain.common.DerivationStyleProvider
import com.tangem.domain.common.extensions.canHandleToken
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.models.UserWallet
import timber.log.Timber
import javax.inject.Inject
@ -31,19 +30,18 @@ class NetworkFactory @Inject constructor(
*
* @param blockchain blockchain
* @param extraDerivationPath extra derivation path
* @param scanResponse scan response
* @param userWallet user wallet
*/
fun create(blockchain: Blockchain, extraDerivationPath: String?, scanResponse: ScanResponse): Network? {
fun create(blockchain: Blockchain, extraDerivationPath: String?, userWallet: UserWallet): Network? {
return create(
blockchain = blockchain,
derivationPath = createDerivationPath(
blockchain = blockchain,
extraDerivationPath = extraDerivationPath,
cardDerivationStyleProvider = scanResponse.derivationStyleProvider,
cardDerivationStyleProvider = userWallet.derivationStyleProvider,
),
canHandleTokens = scanResponse.card.canHandleToken(
canHandleTokens = userWallet.canHandleToken(
blockchain = blockchain,
cardTypesResolver = scanResponse.cardTypesResolver,
excludedBlockchains = excludedBlockchains,
),
)
@ -54,17 +52,16 @@ class NetworkFactory @Inject constructor(
*
* @param networkId network id
* @param derivationPath derivation path
* @param scanResponse scan response
* @param userWallet user wallet
*/
fun create(networkId: Network.ID, derivationPath: Network.DerivationPath, scanResponse: ScanResponse): Network? {
fun create(networkId: Network.ID, derivationPath: Network.DerivationPath, userWallet: UserWallet): Network? {
val blockchain = networkId.toBlockchain()
return create(
blockchain = blockchain,
derivationPath = derivationPath,
canHandleTokens = scanResponse.card.canHandleToken(
canHandleTokens = userWallet.canHandleToken(
blockchain = blockchain,
cardTypesResolver = scanResponse.cardTypesResolver,
excludedBlockchains = excludedBlockchains,
),
)

View file

@ -308,7 +308,7 @@ internal class DefaultCardCryptoCurrencyFactoryTest {
val multiWallet = model.multiWallet
// Act
val actual = factory.createDefaultCoinsForMultiCurrencyCard(scanResponse = multiWallet.scanResponse)
val actual = factory.createDefaultCoinsForMultiCurrencyWallet(multiWallet)
// Assert
val expected = model.expected
@ -355,7 +355,7 @@ internal class DefaultCardCryptoCurrencyFactoryTest {
// Act
val actual = runCatching {
factory.createPrimaryCurrencyForSingleCurrencyCard(scanResponse = singleWallet.scanResponse)
factory.createPrimaryCurrencyForSingleCurrencyCard(singleWallet)
}
// Assert
@ -405,7 +405,7 @@ internal class DefaultCardCryptoCurrencyFactoryTest {
// Act
val actual = runCatching {
factory.createCurrenciesForSingleCurrencyCardWithToken(scanResponse = userWallet.scanResponse)
factory.createCurrenciesForSingleCurrencyCardWithToken(userWallet)
}
// Assert
@ -554,7 +554,7 @@ internal class DefaultCardCryptoCurrencyFactoryTest {
sdkToken = userWallet.scanResponse.cardTypesResolver.getPrimaryToken()!!,
blockchain = blockchain,
extraDerivationPath = null,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)!!
}

View file

@ -5,6 +5,7 @@ import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
import com.tangem.common.test.domain.card.MockScanResponseFactory
import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory
import com.tangem.common.test.domain.wallet.MockUserWalletFactory
import com.tangem.common.test.utils.ProvideTestModels
import com.tangem.domain.common.DerivationStyleProvider
import com.tangem.domain.common.configs.GenericCardConfig
@ -12,6 +13,7 @@ import com.tangem.domain.common.configs.MultiWalletCardConfig
import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.models.UserWallet
import io.mockk.every
import io.mockk.mockk
import org.junit.jupiter.api.Nested
@ -43,7 +45,7 @@ class NetworkFactoryTest {
val actual = networkFactory.create(
blockchain = Blockchain.Ethereum,
extraDerivationPath = null,
scanResponse = createMultiWalletScanResponse(),
userWallet = createUserWallet(),
)
// Assert
@ -59,14 +61,14 @@ class NetworkFactoryTest {
networkFactory.create(
blockchain = model.blockchain,
extraDerivationPath = model.extraDerivationPath,
scanResponse = model.scanResponse,
userWallet = model.userWallet,
)
}
is CreateTestModel.Second -> {
networkFactory.create(
networkId = model.networkId,
derivationPath = model.derivationPath,
scanResponse = model.scanResponse,
userWallet = model.userWallet,
)
}
is CreateTestModel.Third -> {
@ -89,27 +91,27 @@ class NetworkFactoryTest {
CreateTestModel.First(
blockchain = Blockchain.Unknown,
extraDerivationPath = null, // never-mind
scanResponse = createMultiWalletScanResponse(), // never-mind
userWallet = createUserWallet(),
expected = null,
),
createFirst(
extraDerivationPath = null,
scanResponse = createGenericScanResponse(), // default derivation path is null
userWallet = createUserWallet(createGenericScanResponse()), // default derivation path is null
expectedDerivationPath = Network.DerivationPath.None,
),
createFirst(
extraDerivationPath = null,
scanResponse = createMultiWalletScanResponse(),
userWallet = createUserWallet(),
expectedDerivationPath = Network.DerivationPath.Card(value = "m/44'/60'/0'/0/0"), // use default
),
createFirst(
extraDerivationPath = "m/44'/60'/0'/0/0", // as default
scanResponse = createMultiWalletScanResponse(),
userWallet = createUserWallet(),
expectedDerivationPath = Network.DerivationPath.Card(value = "m/44'/60'/0'/0/0"),
),
createFirst(
extraDerivationPath = "m/84'/0'/0'/0/0",
scanResponse = createMultiWalletScanResponse(),
userWallet = createUserWallet(),
expectedDerivationPath = Network.DerivationPath.Custom(value = "m/84'/0'/0'/0/0"),
),
// endregion
@ -118,23 +120,23 @@ class NetworkFactoryTest {
CreateTestModel.Second(
networkId = Network.ID(value = "1", derivationPath = Network.DerivationPath.None),
derivationPath = Network.DerivationPath.None, // never-mind
scanResponse = createMultiWalletScanResponse(), // never-mind
userWallet = createUserWallet(), // never-mind
expected = null,
),
createSecond(
scanResponse = createGenericScanResponse(), // default derivation path is null
userWallet = createUserWallet(createGenericScanResponse()), // default derivation path is null
derivationPath = Network.DerivationPath.None,
),
createSecond(
scanResponse = createMultiWalletScanResponse(),
userWallet = createUserWallet(),
derivationPath = Network.DerivationPath.None,
),
createSecond(
scanResponse = createMultiWalletScanResponse(),
userWallet = createUserWallet(),
derivationPath = Network.DerivationPath.Card(value = "m/44'/60'/0'/0/0"),
),
createSecond(
scanResponse = createMultiWalletScanResponse(),
userWallet = createUserWallet(),
derivationPath = Network.DerivationPath.Custom(value = "m/84'/0'/0'/0/0"),
),
// endregion
@ -176,13 +178,13 @@ class NetworkFactoryTest {
private fun createFirst(
extraDerivationPath: String?,
scanResponse: ScanResponse,
userWallet: UserWallet,
expectedDerivationPath: Network.DerivationPath,
): CreateTestModel.First {
return CreateTestModel.First(
blockchain = Blockchain.Ethereum,
extraDerivationPath = extraDerivationPath,
scanResponse = scanResponse,
userWallet = userWallet,
expected = MockCryptoCurrencyFactory().ethereum.network.copy(
id = Network.ID(
value = Blockchain.Ethereum.id,
@ -195,13 +197,13 @@ class NetworkFactoryTest {
}
private fun createSecond(
scanResponse: ScanResponse,
userWallet: UserWallet,
derivationPath: Network.DerivationPath,
): CreateTestModel.Second {
return CreateTestModel.Second(
networkId = Network.ID(value = Blockchain.Ethereum.id, derivationPath = derivationPath),
derivationPath = derivationPath,
scanResponse = scanResponse,
userWallet = userWallet,
expected = MockCryptoCurrencyFactory().ethereum.network.copy(
id = Network.ID(
value = Blockchain.Ethereum.id,
@ -232,6 +234,10 @@ class NetworkFactoryTest {
)
}
private fun createUserWallet(scanResponse: ScanResponse = createMultiWalletScanResponse()): UserWallet.Cold {
return MockUserWalletFactory.create(scanResponse)
}
private fun createMultiWalletScanResponse(): ScanResponse {
return MockScanResponseFactory.create(
cardConfig = MultiWalletCardConfig,
@ -254,14 +260,14 @@ class NetworkFactoryTest {
data class First(
val blockchain: Blockchain,
val extraDerivationPath: String?,
val scanResponse: ScanResponse,
val userWallet: UserWallet,
override val expected: Network?,
) : CreateTestModel
data class Second(
val networkId: Network.ID,
val derivationPath: Network.DerivationPath,
val scanResponse: ScanResponse,
val userWallet: UserWallet,
override val expected: Network?,
) : CreateTestModel

View file

@ -95,7 +95,7 @@ internal class DefaultCustomTokensRepository(
networkFactory.create(
networkId = networkId,
derivationPath = derivationPath,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY]
userWallet = userWallet,
),
) {
"Network [$networkId] not found while finding token"
@ -106,8 +106,8 @@ internal class DefaultCustomTokensRepository(
symbol = null,
)
val supportedTokenNetworkIds = userWallet.scanResponse.card
.supportedBlockchains(userWallet.scanResponse.cardTypesResolver, excludedBlockchains)
val supportedTokenNetworkIds = userWallet
.supportedBlockchains(excludedBlockchains = excludedBlockchains)
.filter(Blockchain::canHandleTokens)
.map(Blockchain::toNetworkId)
@ -151,7 +151,7 @@ internal class DefaultCustomTokensRepository(
networkFactory.create(
networkId = networkId,
derivationPath = derivationPath,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY]
userWallet = userWallet,
),
) {
"Network [$networkId] not found while creating coin"
@ -188,7 +188,7 @@ internal class DefaultCustomTokensRepository(
networkFactory.create(
networkId = networkId,
derivationPath = derivationPath,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY]
userWallet = userWallet,
),
) {
"Network [$networkId] not found while creating custom token"
@ -261,7 +261,7 @@ internal class DefaultCustomTokensRepository(
networkFactory.create(
blockchain = blockchain,
extraDerivationPath = null,
scanResponse = scanResponse,
userWallet = userWallet,
)
} else {
null

View file

@ -31,7 +31,6 @@ import com.tangem.domain.managetokens.repository.ManageTokensRepository
import com.tangem.domain.models.network.Network
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.pagination.BatchFetchResult
import com.tangem.pagination.BatchListSource
import com.tangem.pagination.fetcher.LimitOffsetBatchFetcher
@ -142,13 +141,13 @@ internal class DefaultManageTokensRepository(
managedCryptoCurrencyFactory.createWithCustomTokens(
coinsResponse = updatedCoinsResponse,
tokensResponse = tokensResponse,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY]
userWallet = userWallet,
)
} else {
managedCryptoCurrencyFactory.create(
coinsResponse = updatedCoinsResponse,
tokensResponse = tokensResponse,
scanResponse = userWallet?.requireColdWallet()?.scanResponse, // TODO [REDACTED_TASK_KEY]
userWallet = userWallet,
)
}
@ -178,7 +177,7 @@ internal class DefaultManageTokensRepository(
testnetTokensConfig
},
tokensResponse = getSavedUserTokensResponseSync(userWallet.walletId),
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY]
userWallet = userWallet,
)
return BatchFetchResult.Success(
@ -190,8 +189,8 @@ internal class DefaultManageTokensRepository(
private fun createDefaultUserTokensResponse(userWallet: UserWallet) =
userTokensResponseFactory.createUserTokensResponse(
currencies = cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard(
userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY]
currencies = cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(
userWallet = userWallet,
),
isGroupedByNetwork = false,
isSortedByBalance = false,

View file

@ -15,13 +15,12 @@ import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
import com.tangem.datasource.local.config.testnet.models.TestnetTokensConfig
import com.tangem.domain.common.DerivationStyleProvider
import com.tangem.domain.common.extensions.canHandleToken
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency.SourceNetwork
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.models.UserWallet
import timber.log.Timber
internal class ManagedCryptoCurrencyFactory(
@ -32,20 +31,20 @@ internal class ManagedCryptoCurrencyFactory(
fun create(
coinsResponse: CoinsResponse,
tokensResponse: UserTokensResponse?,
scanResponse: ScanResponse?,
userWallet: UserWallet?,
): List<ManagedCryptoCurrency> {
return coinsResponse.coins.mapNotNull { coin ->
createToken(coin, tokensResponse, coinsResponse.imageHost, scanResponse)
createToken(coin, tokensResponse, coinsResponse.imageHost, userWallet)
}
}
fun createWithCustomTokens(
coinsResponse: CoinsResponse,
tokensResponse: UserTokensResponse,
scanResponse: ScanResponse,
userWallet: UserWallet,
): List<ManagedCryptoCurrency> {
val customTokens = createCustomTokens(tokensResponse, scanResponse)
val tokens = create(coinsResponse, tokensResponse, scanResponse)
val customTokens = createCustomTokens(tokensResponse, userWallet)
val tokens = create(coinsResponse, tokensResponse, userWallet)
return customTokens + tokens
}
@ -53,10 +52,10 @@ internal class ManagedCryptoCurrencyFactory(
fun createTestnetWithCustomTokens(
testnetTokensConfig: TestnetTokensConfig,
tokensResponse: UserTokensResponse?,
scanResponse: ScanResponse,
userWallet: UserWallet,
): List<ManagedCryptoCurrency> {
val customTokens = tokensResponse
?.let { createCustomTokens(it, scanResponse) }
?.let { createCustomTokens(it, userWallet) }
?: emptyList()
val testnetTokens = testnetTokensConfig.tokens.map { testnetToken ->
ManagedCryptoCurrency.Token(
@ -69,10 +68,10 @@ internal class ManagedCryptoCurrencyFactory(
networkId = network.id,
contractAddress = network.address,
decimals = network.decimalCount,
scanResponse = scanResponse,
userWallet = userWallet,
)
} ?: emptyList(),
addedIn = findAddedInNetworks(testnetToken.id, tokensResponse, scanResponse),
addedIn = findAddedInNetworks(testnetToken.id, tokensResponse, userWallet),
)
}
@ -81,28 +80,28 @@ internal class ManagedCryptoCurrencyFactory(
private fun createCustomTokens(
tokensResponse: UserTokensResponse,
scanResponse: ScanResponse,
userWallet: UserWallet,
): List<ManagedCryptoCurrency> = tokensResponse.tokens
.mapNotNull { token ->
maybeCreateCustomToken(token, scanResponse)
maybeCreateCustomToken(token, userWallet)
}
private fun maybeCreateCustomToken(
token: UserTokensResponse.Token,
scanResponse: ScanResponse,
userWallet: UserWallet,
): ManagedCryptoCurrency? {
val blockchain = Blockchain.fromNetworkId(token.networkId)
?.takeUnless { it in excludedBlockchains }
?: return null
if (!checkIsCustomToken(token, blockchain, scanResponse.derivationStyleProvider)) {
if (!checkIsCustomToken(token, blockchain, userWallet.derivationStyleProvider)) {
return null
}
val network = networkFactory.create(
blockchain = blockchain,
extraDerivationPath = token.derivationPath,
scanResponse = scanResponse,
userWallet = userWallet,
) ?: return null
val contractAddress = token.contractAddress
@ -135,7 +134,7 @@ internal class ManagedCryptoCurrencyFactory(
coinResponse: CoinsResponse.Coin,
tokensResponse: UserTokensResponse?,
imageHost: String?,
scanResponse: ScanResponse?,
userWallet: UserWallet?,
): ManagedCryptoCurrency? {
if (coinResponse.networks.isEmpty() || !coinResponse.active) return null
@ -146,7 +145,7 @@ internal class ManagedCryptoCurrencyFactory(
networkId = network.networkId,
contractAddress = network.contractAddress,
decimals = network.decimalCount?.toInt(),
scanResponse = scanResponse,
userWallet = userWallet,
)
}
.ifEmpty { return null }
@ -157,7 +156,7 @@ internal class ManagedCryptoCurrencyFactory(
symbol = coinResponse.symbol,
iconUrl = getIconUrl(coinResponse.id, imageHost),
availableNetworks = availableNetworks,
addedIn = findAddedInNetworks(coinResponse.id, tokensResponse, scanResponse),
addedIn = findAddedInNetworks(coinResponse.id, tokensResponse, userWallet),
)
}
@ -165,7 +164,7 @@ internal class ManagedCryptoCurrencyFactory(
networkId: String,
contractAddress: String?,
decimals: Int?,
scanResponse: ScanResponse?,
userWallet: UserWallet?,
extraDerivationPath: String? = null,
): SourceNetwork? {
val blockchain = Blockchain.fromNetworkId(networkId)
@ -175,10 +174,8 @@ internal class ManagedCryptoCurrencyFactory(
val network = networkFactory.create(
blockchain = blockchain,
extraDerivationPath = extraDerivationPath,
derivationStyleProvider = scanResponse?.derivationStyleProvider,
canHandleTokens = scanResponse?.let {
it.card.canHandleToken(blockchain, it.cardTypesResolver, excludedBlockchains)
} ?: false, // use card specific check if available
derivationStyleProvider = userWallet?.derivationStyleProvider,
canHandleTokens = userWallet?.canHandleToken(blockchain, excludedBlockchains) ?: false,
) ?: return null
return when {
@ -207,7 +204,7 @@ internal class ManagedCryptoCurrencyFactory(
private fun findAddedInNetworks(
currencyId: String,
tokensResponse: UserTokensResponse?,
scanResponse: ScanResponse?,
userWallet: UserWallet?,
): Set<Network> {
if (tokensResponse == null) return emptySet()
@ -220,10 +217,8 @@ internal class ManagedCryptoCurrencyFactory(
networkFactory.create(
blockchain = blockchain,
extraDerivationPath = token.derivationPath,
derivationStyleProvider = scanResponse?.derivationStyleProvider,
canHandleTokens = scanResponse?.let {
it.card.canHandleToken(blockchain, it.cardTypesResolver, excludedBlockchains)
} ?: true,
derivationStyleProvider = userWallet?.derivationStyleProvider,
canHandleTokens = userWallet?.canHandleToken(blockchain, excludedBlockchains) ?: true,
)
} else {
null

View file

@ -24,7 +24,6 @@ import com.tangem.domain.markets.*
import com.tangem.domain.markets.repositories.MarketsTokenRepository
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.pagination.*
import com.tangem.pagination.fetcher.LimitOffsetBatchFetcher
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
@ -259,13 +258,13 @@ internal class DefaultMarketsTokenRepository(
cryptoCurrencyFactory.createCoin(
blockchain = blockchain,
extraDerivationPath = null,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY]
userWallet = userWallet,
)
} else {
val currencyNetwork = networkFactory.create(
blockchain = blockchain,
extraDerivationPath = null,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY]
userWallet = userWallet,
) ?: return null
cryptoCurrencyFactory.createToken(

View file

@ -5,7 +5,6 @@ import com.tangem.data.networks.store.NetworksStatusesStore
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.models.network.NetworkStatus
import com.tangem.domain.networks.multi.MultiNetworkStatusProducer
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
@ -48,7 +47,7 @@ internal class DefaultMultiNetworkStatusProducer @AssistedInject constructor(
val network = networkFactory.create(
networkId = status.id,
derivationPath = status.id.derivationPath,
scanResponse = userWallet.requireColdWallet().scanResponse,
userWallet = userWallet,
) ?: return@mapNotNullTo null
NetworkStatus(network = network, value = status.value)

View file

@ -67,7 +67,7 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create(
networkId = simpleStatuses.first().id,
derivationPath = simpleStatuses.first().id.derivationPath,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
} returns statuses.first().network
@ -75,7 +75,7 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create(
networkId = simpleStatuses.last().id,
derivationPath = simpleStatuses.last().id.derivationPath,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
} returns statuses.last().network
@ -94,12 +94,12 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create(
networkId = simpleStatuses.first().id,
derivationPath = simpleStatuses.first().id.derivationPath,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
networkFactory.create(
networkId = simpleStatuses.last().id,
derivationPath = simpleStatuses.last().id.derivationPath,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
}
}
@ -130,7 +130,7 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create(
networkId = simpleStatuses.first().id,
derivationPath = simpleStatuses.first().id.derivationPath,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
} returns statuses.first().network
@ -138,7 +138,7 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create(
networkId = simpleStatuses.last().id,
derivationPath = simpleStatuses.last().id.derivationPath,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
} returns statuses.last().network
@ -146,7 +146,7 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create(
networkId = updatedSimpleStatuses.first().id,
derivationPath = updatedSimpleStatuses.first().id.derivationPath,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
} returns updatedStatuses.first().network
@ -154,7 +154,7 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create(
networkId = updatedSimpleStatuses.last().id,
derivationPath = updatedSimpleStatuses.last().id.derivationPath,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
} returns updatedStatuses.last().network
// endregion
@ -177,12 +177,12 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create(
networkId = simpleStatuses.first().id,
derivationPath = simpleStatuses.first().id.derivationPath,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
networkFactory.create(
networkId = simpleStatuses.last().id,
derivationPath = simpleStatuses.last().id.derivationPath,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
}
@ -202,12 +202,12 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create(
networkId = updatedSimpleStatuses.first().id,
derivationPath = updatedSimpleStatuses.first().id.derivationPath,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
networkFactory.create(
networkId = updatedSimpleStatuses.last().id,
derivationPath = updatedSimpleStatuses.last().id.derivationPath,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
}
}
@ -232,7 +232,7 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create(
networkId = simpleStatuses.first().id,
derivationPath = simpleStatuses.first().id.derivationPath,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
} returns statuses.first().network
@ -240,7 +240,7 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create(
networkId = simpleStatuses.last().id,
derivationPath = simpleStatuses.last().id.derivationPath,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
} returns statuses.last().network
// endregion
@ -263,12 +263,12 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create(
networkId = simpleStatuses.first().id,
derivationPath = simpleStatuses.first().id.derivationPath,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
networkFactory.create(
networkId = simpleStatuses.last().id,
derivationPath = simpleStatuses.last().id.derivationPath,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
}
@ -312,14 +312,14 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create(
networkId = simpleStatuses.first().id,
derivationPath = simpleStatuses.first().id.derivationPath,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
} returns statuses.first().network
every {
networkFactory.create(
networkId = simpleStatuses.last().id,
derivationPath = simpleStatuses.last().id.derivationPath,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
} returns statuses.last().network
// endregion
@ -336,7 +336,7 @@ internal class DefaultMultiNetworkStatusProducerTest {
verifyOrder(inverse = true) {
userWalletsStore.getSyncOrNull(any())
networkFactory.create(networkId = any(), derivationPath = any(), scanResponse = any())
networkFactory.create(networkId = any(), derivationPath = any(), userWallet = any())
}
// Act 2 (emit)
@ -353,12 +353,12 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create(
networkId = simpleStatuses.first().id,
derivationPath = simpleStatuses.first().id.derivationPath,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
networkFactory.create(
networkId = simpleStatuses.last().id,
derivationPath = simpleStatuses.last().id.derivationPath,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
}
}
@ -410,12 +410,12 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create(
networkId = simpleStatuses.first().id,
derivationPath = simpleStatuses.first().id.derivationPath,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
networkFactory.create(
networkId = simpleStatuses.last().id,
derivationPath = simpleStatuses.last().id.derivationPath,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
}
}
@ -429,10 +429,10 @@ internal class DefaultMultiNetworkStatusProducerTest {
val userWallet = MockUserWalletFactory.create(scanResponse = scanResponse)
val ethNetwork = MockCryptoCurrencyFactory(scanResponse = scanResponse).ethereum.network.copy(
val ethNetwork = MockCryptoCurrencyFactory(userWallet = userWallet).ethereum.network.copy(
canHandleTokens = true,
)
val cardanoNetwork = MockCryptoCurrencyFactory(scanResponse = scanResponse).cardano.network
val cardanoNetwork = MockCryptoCurrencyFactory(userWallet = userWallet).cardano.network
}
}

View file

@ -208,7 +208,7 @@ internal class DefaultNFTRepository @Inject constructor(
networkFactory.create(
blockchain = it,
extraDerivationPath = null,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY]
userWallet = userWallet,
)
}
.filter { it.canHandleNFTs(userWalletId) }

View file

@ -27,7 +27,6 @@ import com.tangem.domain.onramp.model.HotCryptoCurrency
import com.tangem.domain.onramp.repositories.HotCryptoRepository
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.JobHolder
import com.tangem.utils.coroutines.runCatching
@ -93,7 +92,7 @@ internal class DefaultHotCryptoRepository(
?: error("UserWalletId [$userWalletId] not found")
HotCryptoCurrencyConverter(
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY]
userWallet = userWallet,
imageHost = it.imageHost,
excludedBlockchains = excludedBlockchains,
)

View file

@ -10,22 +10,22 @@ import com.tangem.domain.models.StatusSource
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.quote.QuoteStatus
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.onramp.model.HotCryptoCurrency
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.utils.converter.Converter
import java.math.BigDecimal
/**
* Converter from [HotCryptoResponse.Token] to [HotCryptoCurrency]
*
* @property scanResponse scan response
* @property userWallet scan response
* @property imageHost image host
* @param excludedBlockchains excluded blockchains
*
[REDACTED_AUTHOR]
*/
internal class HotCryptoCurrencyConverter(
private val scanResponse: ScanResponse,
private val userWallet: UserWallet,
private val imageHost: String?,
excludedBlockchains: ExcludedBlockchains,
) : Converter<HotCryptoResponse.Token, HotCryptoCurrency?> {
@ -81,7 +81,7 @@ internal class HotCryptoCurrencyConverter(
return networkFactory.create(
blockchain = blockchain,
extraDerivationPath = null,
scanResponse = scanResponse,
userWallet = userWallet,
)
}

View file

@ -21,7 +21,6 @@ import com.tangem.domain.swap.models.SwapTransactionListModel
import com.tangem.domain.swap.models.SwapTransactionModel
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.extensions.addOrReplace
import kotlinx.coroutines.flow.Flow
@ -119,7 +118,7 @@ internal class DefaultSwapTransactionRepository(
currencyTxs?.mapNotNull {
listConverter.convertBack(
value = it,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY]
userWallet = userWallet,
txStatuses = txStatuses,
)
}

View file

@ -3,8 +3,8 @@ package com.tangem.data.swap.converter.transaction
import com.tangem.data.common.currency.ResponseCryptoCurrenciesFactory
import com.tangem.data.swap.models.SwapStatusDTO
import com.tangem.data.swap.models.SwapTransactionDTO
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.swap.models.SwapTransactionModel
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.utils.converter.TwoWayConverter
internal class SavedSwapTransactionConverter(
@ -35,14 +35,14 @@ internal class SavedSwapTransactionConverter(
fun convertBack(
value: SwapTransactionDTO,
scanResponse: ScanResponse,
userWallet: UserWallet,
txStatuses: Map<String, SwapStatusDTO>,
): SwapTransactionModel {
val status = txStatuses[value.txId]
val refundCurrency = status?.refundTokensResponse?.let { id ->
responseCryptoCurrenciesFactory.createCurrency(
responseToken = id,
scanResponse = scanResponse,
userWallet = userWallet,
)
}
val statusWithRefundCurrency = status?.copy(refundCurrency = refundCurrency)

View file

@ -6,8 +6,8 @@ import com.tangem.data.swap.models.SwapStatusDTO
import com.tangem.data.swap.models.SwapTransactionDTO
import com.tangem.data.swap.models.SwapTransactionListDTO
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.swap.models.SwapTransactionListModel
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.utils.converter.Converter
@ -35,7 +35,7 @@ internal class SavedSwapTransactionListConverter(
fun convertBack(
value: SwapTransactionListDTO,
scanResponse: ScanResponse,
userWallet: UserWallet,
txStatuses: Map<String, SwapStatusDTO>,
): SwapTransactionListModel? {
val fromToken = value.fromTokensResponse
@ -45,16 +45,16 @@ internal class SavedSwapTransactionListConverter(
} else {
val fromCryptoCurrency = responseCryptoCurrenciesFactory.createCurrency(
responseToken = fromToken,
scanResponse = scanResponse,
userWallet = userWallet,
) ?: return null
val toCryptoCurrency = responseCryptoCurrenciesFactory.createCurrency(
responseToken = toToken,
scanResponse = scanResponse,
userWallet = userWallet,
) ?: return null
return SwapTransactionListModel(
transactions = value.transactions.map { tx ->
savedSwapTransactionConverter.convertBack(tx, scanResponse, txStatuses)
savedSwapTransactionConverter.convertBack(tx, userWallet, txStatuses)
},
userWalletId = value.userWalletId,
fromCryptoCurrencyId = value.fromCryptoCurrencyId,

View file

@ -16,7 +16,6 @@ import com.tangem.datasource.local.token.UserTokensResponseStore
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.core.utils.catchOn
import com.tangem.domain.demo.DemoConfig
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesFetcher
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesFetcher.Params
import com.tangem.domain.wallets.models.UserWallet
@ -60,7 +59,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcher(
if (!userWallet.isMultiCurrency) error("${this::class.simpleName} supports only multi-currency wallet")
val response = if (userWallet is UserWallet.Cold && userWallet.isDemoWalletWithoutSavedTokens()) {
createDefaultUserTokensResponse(scanResponse = userWallet.scanResponse)
createDefaultUserTokensResponse(userWallet = userWallet)
} else {
safeApiCall(
call = {
@ -99,7 +98,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcher(
val userWalletId = userWallet.walletId
val response = userTokensResponseStore.getSyncOrNull(userWalletId = userWalletId)
?: createDefaultUserTokensResponse(scanResponse = userWallet.requireColdWallet().scanResponse)
?: createDefaultUserTokensResponse(userWallet = userWallet)
if (error is ApiResponseError.HttpException && error.code == ApiResponseError.HttpException.Code.NOT_FOUND) {
Timber.w(error, "Requested currencies could not be found in the remote store for: $userWalletId")
@ -121,9 +120,9 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcher(
expressServiceLoader.update(userWallet = userWallet, userTokens = tokens)
}
private fun createDefaultUserTokensResponse(scanResponse: ScanResponse): UserTokensResponse {
private fun createDefaultUserTokensResponse(userWallet: UserWallet): UserTokensResponse {
return userTokensResponseFactory.createUserTokensResponse(
currencies = cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard(scanResponse),
currencies = cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(userWallet),
isGroupedByNetwork = false,
isSortedByBalance = false,
)

View file

@ -48,7 +48,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducer @AssistedInject constr
responseCryptoCurrenciesFactory.createCurrencies(
response = response,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
).toSet()
}
.onEmpty { emit(fallback) }

View file

@ -184,7 +184,8 @@ internal class DefaultCurrenciesRepository(
)
val token = userTokensResponseFactory.createResponseToken(currency)
val updatedResponse = savedCurrencies.copy(tokens = savedCurrencies.tokens.filterNot { it == token })
val updatedResponse =
savedCurrencies.copy(tokens = savedCurrencies.tokens.filterNot { it == token })
userTokensSaver.storeAndPush(
userWalletId = userWalletId,
response = updatedResponse,
@ -229,10 +230,11 @@ internal class DefaultCurrenciesRepository(
): CryptoCurrency {
return withContext(dispatchers.io) {
val userWallet = userWalletsStore.getSyncStrict(userWalletId)
userWallet.requireColdWallet()
ensureIsCorrectUserWallet(userWallet, isMultiCurrencyWalletExpected = false)
val currency = cardCryptoCurrencyFactory.createPrimaryCurrencyForSingleCurrencyCard(
userWallet.requireColdWallet().scanResponse,
userWallet = userWallet,
)
fetchExpressAssetsByNetworkIds(
@ -254,11 +256,12 @@ internal class DefaultCurrenciesRepository(
val scanResponse = userWallet.requireColdWallet().scanResponse
val currencies = if (scanResponse.cardTypesResolver.isSingleWalletWithToken()) {
cardCryptoCurrencyFactory.createCurrenciesForSingleCurrencyCardWithToken(scanResponse = scanResponse)
cardCryptoCurrencyFactory.createCurrenciesForSingleCurrencyCardWithToken(userWallet = userWallet)
} else {
cardCryptoCurrencyFactory.createPrimaryCurrencyForSingleCurrencyCard(scanResponse = scanResponse).run {
listOf(this)
}
cardCryptoCurrencyFactory.createPrimaryCurrencyForSingleCurrencyCard(userWallet = userWallet)
.run {
listOf(this)
}
}
fetchExpressAssetsByNetworkIds(
@ -277,10 +280,11 @@ internal class DefaultCurrenciesRepository(
): CryptoCurrency {
return withContext(dispatchers.io) {
val userWallet = userWalletsStore.getSyncStrict(userWalletId)
userWallet.requireColdWallet()
ensureIsCorrectUserWallet(userWallet, isMultiCurrencyWalletExpected = false)
val currency = cardCryptoCurrencyFactory.createCurrenciesForSingleCurrencyCardWithToken(
scanResponse = userWallet.requireColdWallet().scanResponse,
userWallet = userWallet,
)
.find { it.id == id }
requireNotNull(currency) { "Unable to find currency with provided ID: $id" }
@ -320,7 +324,10 @@ internal class DefaultCurrenciesRepository(
},
)
responseCryptoCurrenciesFactory.createCurrencies(storedTokens, userWallet.requireColdWallet().scanResponse)
responseCryptoCurrenciesFactory.createCurrencies(
storedTokens,
userWallet = userWallet,
)
}
override suspend fun getMultiCurrencyWalletCachedCurrenciesSync(userWalletId: UserWalletId) =
@ -335,7 +342,10 @@ internal class DefaultCurrenciesRepository(
},
)
responseCryptoCurrenciesFactory.createCurrencies(storedTokens, userWallet.requireColdWallet().scanResponse)
responseCryptoCurrenciesFactory.createCurrencies(
storedTokens,
userWallet = userWallet,
)
}
override suspend fun getMultiCurrencyWalletCurrency(
@ -360,7 +370,7 @@ internal class DefaultCurrenciesRepository(
responseCryptoCurrenciesFactory.createCurrency(
currencyId = id,
response = response,
scanResponse = userWallet.requireColdWallet().scanResponse,
userWallet = userWallet,
)
}
@ -394,7 +404,7 @@ internal class DefaultCurrenciesRepository(
val coin = responseCryptoCurrenciesFactory.createCurrency(
responseToken = storedCoin,
scanResponse = userWallet.requireColdWallet().scanResponse,
userWallet = userWallet,
)
coin as? CryptoCurrency.Coin ?: error("Unable to create currency")
@ -438,12 +448,15 @@ internal class DefaultCurrenciesRepository(
cryptoCurrencyStatus: CryptoCurrencyStatus,
): Boolean {
val blockchain = cryptoCurrencyStatus.currency.network.toBlockchain()
val isBitcoinBlockchain = blockchain == Blockchain.Bitcoin || blockchain == Blockchain.BitcoinTestnet
val isBitcoinBlockchain =
blockchain == Blockchain.Bitcoin || blockchain == Blockchain.BitcoinTestnet
return when {
cryptoCurrencyStatus.currency is CryptoCurrency.Coin && isBitcoinBlockchain -> {
val outgoingTransactions = cryptoCurrencyStatus.value.pendingTransactions.filter { it.isOutgoing }
val outgoingTransactions =
cryptoCurrencyStatus.value.pendingTransactions.filter { it.isOutgoing }
outgoingTransactions.isNotEmpty()
}
blockchain.isEvm() -> false
blockchain == Blockchain.Tron || blockchain == Blockchain.TronTestnet -> false
else -> {
@ -481,6 +494,7 @@ internal class DefaultCurrenciesRepository(
balance = balance,
)
}
is FeePaidSdkCurrency.FeeResource -> FeePaidCurrency.FeeResource(currency = feePaidCurrency.currency)
}
}
@ -508,7 +522,8 @@ internal class DefaultCurrenciesRepository(
.coins
.firstOrNull()
?: error("Token not found")
val network = foundToken.networks.firstOrNull { it.networkId == networkId } ?: error("Network not found")
val network = foundToken.networks.firstOrNull { it.networkId == networkId }
?: error("Network not found")
CryptoCurrencyFactory.Token(
symbol = foundToken.symbol,
name = foundToken.name,
@ -521,7 +536,7 @@ internal class DefaultCurrenciesRepository(
token = token,
networkId = networkId,
extraDerivationPath = null,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY]
userWallet = userWallet,
) ?: error("Unable to create token")
}
@ -559,23 +574,25 @@ internal class DefaultCurrenciesRepository(
responseCryptoCurrenciesFactory.createCurrencies(
response = storedTokens.copy(tokens = filterResponse),
scanResponse = userWallet.requireColdWallet().scanResponse,
userWallet = userWallet,
)
}
}
else -> {
val currencies = if (userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()) {
getSingleCurrencyWalletWithCardCurrencies(userWallet.walletId)
} else {
val currency =
getSingleCurrencyWalletPrimaryCurrency(userWalletId = userWallet.walletId)
if (currency.id.rawCurrencyId == currencyRawId) {
listOf(currency)
else -> {
val currencies =
if (userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()) {
getSingleCurrencyWalletWithCardCurrencies(userWallet.walletId)
} else {
emptyList()
val currency =
getSingleCurrencyWalletPrimaryCurrency(userWalletId = userWallet.walletId)
if (currency.id.rawCurrencyId == currencyRawId) {
listOf(currency)
} else {
emptyList()
}
}
}
flow {
emit(currencies)
}
@ -603,14 +620,15 @@ internal class DefaultCurrenciesRepository(
}
override fun getCardTypesResolver(userWalletId: UserWalletId): CardTypesResolver {
return userWalletsStore.getSyncStrict(userWalletId).requireColdWallet().cardTypesResolver // TODO [REDACTED_TASK_KEY]
return userWalletsStore.getSyncStrict(userWalletId)
.requireColdWallet().cardTypesResolver // TODO [REDACTED_TASK_KEY]
}
private fun getMultiCurrencyWalletCurrencies(userWallet: UserWallet): Flow<List<CryptoCurrency>> {
return getSavedUserTokensResponse(userWallet.walletId).map { storedTokens ->
responseCryptoCurrenciesFactory.createCurrencies(
response = storedTokens,
scanResponse = userWallet.requireColdWallet().scanResponse,
userWallet = userWallet,
)
}
}
@ -700,7 +718,10 @@ internal class DefaultCurrenciesRepository(
?: createDefaultUserTokensResponse(userWallet = userWallet)
if (e is ApiResponseError.HttpException && e.code == ApiResponseError.HttpException.Code.NOT_FOUND) {
Timber.w(e, "Requested currencies could not be found in the remote store for: $userWalletId")
Timber.w(
e,
"Requested currencies could not be found in the remote store for: $userWalletId",
)
userTokensSaver.push(userWalletId, response)
} else {
@ -712,8 +733,8 @@ internal class DefaultCurrenciesRepository(
private fun createDefaultUserTokensResponse(userWallet: UserWallet) =
userTokensResponseFactory.createUserTokensResponse(
currencies = cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard(
userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY]
currencies = cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(
userWallet = userWallet,
),
isGroupedByNetwork = false,
isSortedByBalance = false,
@ -732,9 +753,11 @@ internal class DefaultCurrenciesRepository(
!userWallet.isMultiCurrency && isMultiCurrencyWalletExpected -> {
"Multi currency wallet expected, but single currency wallet was found: $userWalletId"
}
userWallet.isMultiCurrency && !isMultiCurrencyWalletExpected -> {
"Single currency wallet expected, but multi currency wallet was found: $userWalletId"
}
else -> null
}

View file

@ -125,7 +125,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
every { userWalletsStore.getSyncStrict(params.userWalletId) } returns mockUserWallet
coEvery { userTokensResponseStore.getSyncOrNull(userWalletId = params.userWalletId) } returns null
every {
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard(mockUserWallet.scanResponse)
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(mockUserWallet)
} returns defaultCoins
coEvery {
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = userTokensResponse)
@ -141,7 +141,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
coVerifyOrder {
userWalletsStore.getSyncStrict(key = params.userWalletId)
userTokensResponseStore.getSyncOrNull(userWalletId = params.userWalletId)
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard(scanResponse = mockUserWallet.scanResponse)
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(mockUserWallet)
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = userTokensResponse)
userTokensSaver.store(userWalletId = params.userWalletId, response = userTokensResponse)
expressServiceLoader.update(userWallet = mockUserWallet, userTokens = userTokensResponse.toLeastTokens())
@ -187,7 +187,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
}
coVerify(inverse = true) {
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard(scanResponse = any())
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(any())
}
}
@ -229,7 +229,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
coVerify(inverse = true) {
userTokensResponseStore.getSyncOrNull(userWalletId = any())
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard(scanResponse = any())
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(any())
}
}
@ -267,7 +267,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
coEvery { tangemTechApi.getUserTokens(userId = params.userWalletId.stringValue) } returns apiResponse
coEvery { userTokensResponseStore.getSyncOrNull(userWalletId = userWalletId) } returns null
coEvery {
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard(mockUserWallet.scanResponse)
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(mockUserWallet)
} returns defaultCoins
coEvery {
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = userTokensResponse)
@ -335,7 +335,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
coVerify(inverse = true) {
userTokensSaver.push(userWalletId = any(), response = any())
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard(scanResponse = any())
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(any())
}
}
@ -377,7 +377,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
coEvery { tangemTechApi.getUserTokens(userId = params.userWalletId.stringValue) } returns apiResponse
coEvery { userTokensResponseStore.getSyncOrNull(userWalletId = userWalletId) } returns null
coEvery {
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard(mockUserWallet.scanResponse)
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(mockUserWallet)
} returns defaultCoins
coEvery {
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = userTokensResponse)
@ -394,7 +394,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
userWalletsStore.getSyncStrict(key = params.userWalletId)
tangemTechApi.getUserTokens(userId = params.userWalletId.stringValue)
userTokensResponseStore.getSyncOrNull(userWalletId = userWalletId)
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard(mockUserWallet.scanResponse)
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(mockUserWallet)
userTokensSaver.push(userWalletId = params.userWalletId, response = userTokensResponse)
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = userTokensResponse)
userTokensSaver.store(userWalletId = params.userWalletId, response = userTokensResponse)
@ -447,7 +447,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
}
coVerify(inverse = true) {
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard(scanResponse = any())
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(any())
}
}

View file

@ -72,7 +72,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
}
verify(inverse = true) {
responseCryptoCurrenciesFactory.createCurrencies(response = any(), scanResponse = any())
responseCryptoCurrenciesFactory.createCurrencies(response = any(), userWallet = any())
}
}
@ -114,14 +114,14 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
every {
responseCryptoCurrenciesFactory.createCurrencies(
response = userTokensResponse,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
} returns cryptoCurrencies.toList()
every {
responseCryptoCurrenciesFactory.createCurrencies(
response = updatedUserTokensResponse,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
} returns updatedCryptoCurrencies.toList()
@ -143,7 +143,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
userTokensResponseStore.get(params.userWalletId)
responseCryptoCurrenciesFactory.createCurrencies(
response = userTokensResponse,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
}
@ -161,7 +161,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
verifyOrder {
responseCryptoCurrenciesFactory.createCurrencies(
response = updatedUserTokensResponse,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
}
}
@ -185,7 +185,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
every {
responseCryptoCurrenciesFactory.createCurrencies(
response = userTokensResponse,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
} returns cryptoCurrencies.toList()
@ -207,7 +207,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
userTokensResponseStore.get(params.userWalletId)
responseCryptoCurrenciesFactory.createCurrencies(
response = userTokensResponse,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
}
@ -251,7 +251,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
every {
responseCryptoCurrenciesFactory.createCurrencies(
response = userTokensResponse,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
} returns cryptoCurrencies.toList()
@ -282,7 +282,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
verifyOrder {
responseCryptoCurrenciesFactory.createCurrencies(
response = userTokensResponse,
scanResponse = userWallet.scanResponse,
userWallet = userWallet,
)
}
}
@ -307,7 +307,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
}
verify(inverse = true) {
responseCryptoCurrenciesFactory.createCurrencies(response = any(), scanResponse = any())
responseCryptoCurrenciesFactory.createCurrencies(response = any(), userWallet = any())
}
}
@ -335,7 +335,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
verify(inverse = true) {
userTokensResponseStore.get(any())
responseCryptoCurrenciesFactory.createCurrencies(response = any(), scanResponse = any())
responseCryptoCurrenciesFactory.createCurrencies(response = any(), userWallet = any())
}
}

View file

@ -7,7 +7,6 @@ import com.tangem.data.walletconnect.model.CAIP2
import com.tangem.data.walletconnect.model.NamespaceKey
import com.tangem.domain.models.network.Network
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.requireColdWallet
internal interface WcNamespaceConverter {
@ -27,7 +26,7 @@ internal interface WcNamespaceConverter {
return NetworkFactory(excludedBlockchains).create(
blockchain = blockchain,
extraDerivationPath = null,
scanResponse = wallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY]
userWallet = wallet,
)
}
}