Updated on 2026-08-14

This commit is contained in:
Tangem 2026-03-23 19:34:05 +05:00
parent e10334a935
commit a811501f80
5 changed files with 83 additions and 31 deletions

View file

@ -78,12 +78,14 @@ internal object TransactionDomainModule {
walletManagersFacade: WalletManagersFacade,
singleNetworkStatusSupplier: SingleNetworkStatusSupplier,
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
tangemHotWalletSignerFactory: TangemHotWalletSigner.Factory,
): AssociateAssetUseCase {
return AssociateAssetUseCase(
cardSdkConfigRepository = cardSdkConfigRepository,
walletManagersFacade = walletManagersFacade,
singleNetworkStatusSupplier = singleNetworkStatusSupplier,
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
getHotTransactionSigner = tangemHotWalletSignerFactory::create,
)
}
@ -92,10 +94,12 @@ internal object TransactionDomainModule {
fun provideRetryTransactionUseCase(
cardSdkConfigRepository: CardSdkConfigRepository,
walletManagersFacade: WalletManagersFacade,
tangemHotWalletSignerFactory: TangemHotWalletSigner.Factory,
): RetryIncompleteTransactionUseCase {
return RetryIncompleteTransactionUseCase(
cardSdkConfigRepository = cardSdkConfigRepository,
walletManagersFacade = walletManagersFacade,
getHotTransactionSigner = tangemHotWalletSignerFactory::create,
)
}
@ -104,10 +108,12 @@ internal object TransactionDomainModule {
fun provideOpenTrustlineUseCase(
cardSdkConfigRepository: CardSdkConfigRepository,
walletManagersFacade: WalletManagersFacade,
tangemHotWalletSignerFactory: TangemHotWalletSigner.Factory,
): OpenTrustlineUseCase {
return OpenTrustlineUseCase(
cardSdkConfigRepository = cardSdkConfigRepository,
walletManagersFacade = walletManagersFacade,
getHotTransactionSigner = tangemHotWalletSignerFactory::create,
)
}

View file

@ -3,10 +3,12 @@ package com.tangem.domain.transaction.usecase
import arrow.core.Either
import arrow.core.raise.catch
import arrow.core.raise.either
import com.tangem.blockchain.common.TransactionSigner
import com.tangem.blockchain.extensions.SimpleResult
import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.NetworkStatus
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.networks.single.SingleNetworkStatusProducer
import com.tangem.domain.networks.single.SingleNetworkStatusSupplier
@ -22,15 +24,13 @@ class AssociateAssetUseCase(
private val walletManagersFacade: WalletManagersFacade,
private val singleNetworkStatusSupplier: SingleNetworkStatusSupplier,
private val multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
private val getHotTransactionSigner: (UserWallet.Hot) -> TransactionSigner,
) {
suspend operator fun invoke(
userWalletId: UserWalletId,
currency: CryptoCurrency,
): Either<AssociateAssetError, Unit> {
suspend operator fun invoke(userWallet: UserWallet, currency: CryptoCurrency): Either<AssociateAssetError, Unit> {
return either {
val networkCoin = multiWalletCryptoCurrenciesSupplier.getSyncOrNull(
params = MultiWalletCryptoCurrenciesProducer.Params(userWalletId),
params = MultiWalletCryptoCurrenciesProducer.Params(userWallet.walletId),
)
?.firstOrNull {
val network = currency.network
@ -38,18 +38,19 @@ class AssociateAssetUseCase(
}
?: error("Unable to create network coin for currencyID: ${currency.id}")
if (isBalanceZero(userWalletId, networkCoin)) {
if (isBalanceZero(userWallet.walletId, networkCoin)) {
raise(AssociateAssetError.NotEnoughBalance(networkCoin))
}
val signer = cardSdkConfigRepository.getCommonSigner(
cardId = null,
twinKey = null, // use null here because no assets support for Twin cards
)
val signer = createSigner(userWallet)
catch(
block = {
when (val result = walletManagersFacade.fulfillRequirements(userWalletId, currency, signer)) {
when (val result = walletManagersFacade.fulfillRequirements(
userWallet.walletId,
currency,
signer,
)) {
is SimpleResult.Failure -> raise(AssociateAssetError.DataError(result.error.customMessage))
SimpleResult.Success -> Unit
}
@ -59,6 +60,20 @@ class AssociateAssetUseCase(
}
}
private fun createSigner(userWallet: UserWallet): TransactionSigner {
return when (userWallet) {
is UserWallet.Hot -> getHotTransactionSigner(userWallet)
is UserWallet.Cold -> getColdSigner()
}
}
private fun getColdSigner(): TransactionSigner {
return cardSdkConfigRepository.getCommonSigner(
cardId = null,
twinKey = null, // use null here because no assets support for Twin cards
)
}
private suspend fun isBalanceZero(userWalletId: UserWalletId, currency: CryptoCurrency): Boolean {
val networkStatus = singleNetworkStatusSupplier(
params = SingleNetworkStatusProducer.Params(

View file

@ -4,32 +4,32 @@ import arrow.core.Either
import arrow.core.raise.catch
import arrow.core.raise.either
import com.tangem.blockchain.common.BlockchainSdkError
import com.tangem.blockchain.common.TransactionSigner
import com.tangem.blockchain.extensions.SimpleResult
import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.transaction.error.OpenTrustlineError
import com.tangem.domain.transaction.error.parseWrappedError
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.models.wallet.UserWalletId
class OpenTrustlineUseCase(
private val cardSdkConfigRepository: CardSdkConfigRepository,
private val walletManagersFacade: WalletManagersFacade,
private val getHotTransactionSigner: (UserWallet.Hot) -> TransactionSigner,
) {
suspend operator fun invoke(
userWalletId: UserWalletId,
currency: CryptoCurrency,
): Either<OpenTrustlineError, Unit> {
suspend operator fun invoke(userWallet: UserWallet, currency: CryptoCurrency): Either<OpenTrustlineError, Unit> {
return either {
val signer = cardSdkConfigRepository.getCommonSigner(
cardId = null,
twinKey = null, // use null here because no assets support for Twin cards
)
val signer = createSigner(userWallet)
catch(
block = {
when (val result = walletManagersFacade.fulfillRequirements(userWalletId, currency, signer)) {
when (val result = walletManagersFacade.fulfillRequirements(
userWallet.walletId,
currency,
signer,
)) {
is SimpleResult.Failure -> when (val error = result.error) {
is BlockchainSdkError.Stellar.MinReserveRequired ->
raise(
@ -58,4 +58,18 @@ class OpenTrustlineUseCase(
)
}
}
private fun createSigner(userWallet: UserWallet): TransactionSigner {
return when (userWallet) {
is UserWallet.Hot -> getHotTransactionSigner(userWallet)
is UserWallet.Cold -> getColdSigner()
}
}
private fun getColdSigner(): TransactionSigner {
return cardSdkConfigRepository.getCommonSigner(
cardId = null,
twinKey = null, // use null here because no assets support for Twin cards
)
}
}

View file

@ -4,33 +4,36 @@ import arrow.core.Either
import arrow.core.raise.catch
import arrow.core.raise.either
import com.tangem.blockchain.common.BlockchainSdkError
import com.tangem.blockchain.common.TransactionSigner
import com.tangem.blockchain.extensions.SimpleResult
import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.transaction.error.IncompleteTransactionError
import com.tangem.domain.transaction.error.SendTransactionError
import com.tangem.domain.transaction.error.parseWrappedError
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.models.wallet.UserWalletId
class RetryIncompleteTransactionUseCase(
private val cardSdkConfigRepository: CardSdkConfigRepository,
private val walletManagersFacade: WalletManagersFacade,
private val getHotTransactionSigner: (UserWallet.Hot) -> TransactionSigner,
) {
suspend operator fun invoke(
userWalletId: UserWalletId,
userWallet: UserWallet,
currency: CryptoCurrency,
): Either<IncompleteTransactionError, Unit> {
return either {
val signer = cardSdkConfigRepository.getCommonSigner(
cardId = null,
twinKey = null, // use null here because no assets support for Twin cards
)
val signer = createSigner(userWallet)
catch(
block = {
when (val result = walletManagersFacade.fulfillRequirements(userWalletId, currency, signer)) {
when (val result = walletManagersFacade.fulfillRequirements(
userWallet.walletId,
currency,
signer,
)) {
is SimpleResult.Failure -> {
val error = result.error as? BlockchainSdkError
when (error) {
@ -51,4 +54,18 @@ class RetryIncompleteTransactionUseCase(
)
}
}
private fun createSigner(userWallet: UserWallet): TransactionSigner {
return when (userWallet) {
is UserWallet.Hot -> getHotTransactionSigner(userWallet)
is UserWallet.Cold -> getColdSigner()
}
}
private fun getColdSigner(): TransactionSigner {
return cardSdkConfigRepository.getCommonSigner(
cardId = null,
twinKey = null, // use null here because no assets support for Twin cards
)
}
}

View file

@ -941,7 +941,7 @@ internal class TokenDetailsModel @Inject constructor(
)
modelScope.launch {
retryIncompleteTransactionUseCase(
userWalletId = userWalletId,
userWallet = userWallet,
currency = cryptoCurrency,
).fold(
ifLeft = { e ->
@ -982,7 +982,7 @@ internal class TokenDetailsModel @Inject constructor(
)
modelScope.launch(dispatchers.mainImmediate) {
openTrustlineUseCase(
userWalletId = userWalletId,
userWallet = userWallet,
currency = cryptoCurrency,
).fold(
ifLeft = { e ->
@ -1054,7 +1054,7 @@ internal class TokenDetailsModel @Inject constructor(
)
modelScope.launch(dispatchers.io) {
associateAssetUseCase(
userWalletId = userWalletId,
userWallet = userWallet,
currency = cryptoCurrency,
).fold(
ifLeft = { e ->