Updated on 2026-08-14

This commit is contained in:
Tangem 2025-10-14 21:28:31 +04:00
parent 8e433e111e
commit 17c591db4e
19 changed files with 180 additions and 81 deletions

View file

@ -2,6 +2,8 @@ package com.tangem.features.managetokens.utils.list
import arrow.core.Either
import arrow.core.NonEmptyList
import arrow.core.right
import com.tangem.domain.account.status.usecase.SaveCryptoCurrenciesUseCase
import com.tangem.domain.managetokens.CheckIsCurrencyNotAddedUseCase
import com.tangem.domain.managetokens.CreateCryptoCurrencyUseCase
import com.tangem.domain.managetokens.FindTokenUseCase
@ -28,6 +30,7 @@ internal class CustomTokenFormUseCasesFacade @AssistedInject constructor(
private val findTokenUseCase: FindTokenUseCase,
private val checkIsCurrencyNotAddedUseCase: CheckIsCurrencyNotAddedUseCase,
private val coldWalletAndHasMissedDerivationsUseCase: ColdWalletAndHasMissedDerivationsUseCase,
private val saveCryptoCurrenciesUseCase: SaveCryptoCurrenciesUseCase,
@Assisted private val mode: AddCustomTokenMode,
) {
@ -40,15 +43,19 @@ internal class CustomTokenFormUseCasesFacade @AssistedInject constructor(
}
suspend fun addCryptoCurrenciesUseCase(currency: CryptoCurrency): Either<Throwable, Unit> = when (mode) {
is AddCustomTokenMode.Account -> TODO("Account")
is AddCustomTokenMode.Wallet -> addCryptoCurrenciesUseCase.invoke(
userWalletId = mode.userWalletId,
currency = currency,
)
is AddCustomTokenMode.Account -> {
saveCryptoCurrenciesUseCase(accountId = mode.accountId, add = currency)
}
is AddCustomTokenMode.Wallet -> {
addCryptoCurrenciesUseCase.invoke(
userWalletId = mode.userWalletId,
currency = currency,
)
}
}
suspend fun derivePublicKeysUseCase(currencies: List<CryptoCurrency>): Either<Throwable, Unit> = when (mode) {
is AddCustomTokenMode.Account -> TODO("Account")
is AddCustomTokenMode.Account -> Unit.right()
is AddCustomTokenMode.Wallet -> derivePublicKeysUseCase.invoke(
userWalletId = mode.userWalletId,
currencies = currencies,

View file

@ -2,10 +2,13 @@ package com.tangem.features.managetokens.utils.list
import arrow.core.Either
import arrow.core.left
import com.tangem.domain.account.status.usecase.SaveCryptoCurrenciesUseCase
import com.tangem.domain.managetokens.*
import com.tangem.domain.managetokens.model.CurrencyUnsupportedState
import com.tangem.domain.managetokens.model.ManageTokensListConfig
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
import com.tangem.domain.managetokens.repository.CustomTokensRepository
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.wallets.usecase.ColdWalletAndHasMissedDerivationsUseCase
@ -23,6 +26,8 @@ internal class ManageTokensUseCasesFacade @AssistedInject constructor(
private val checkCurrencyUnsupportedUseCase: CheckCurrencyUnsupportedUseCase,
private val coldWalletAndHasMissedDerivationsUseCase: ColdWalletAndHasMissedDerivationsUseCase,
private val saveManagedTokensUseCase: SaveManagedTokensUseCase,
private val saveCryptoCurrenciesUseCase: SaveCryptoCurrenciesUseCase,
private val customTokensRepository: CustomTokensRepository,
@Assisted private val mode: ManageTokensMode,
) {
@ -40,7 +45,14 @@ internal class ManageTokensUseCasesFacade @AssistedInject constructor(
suspend fun removeCustomCurrencyUseCase(customCurrency: ManagedCryptoCurrency.Custom): Either<Throwable, Unit> {
return when (mode) {
is ManageTokensMode.Account -> TODO("Account")
is ManageTokensMode.Account -> {
val currency = customTokensRepository.convertToCryptoCurrency(
userWalletId = mode.accountId.userWalletId,
currency = customCurrency,
)
saveCryptoCurrenciesUseCase(accountId = mode.accountId, remove = currency)
}
is ManageTokensMode.Wallet -> removeCustomCurrencyUseCase.invoke(
userWalletId = mode.userWalletId,
customCurrency = customCurrency,
@ -92,15 +104,46 @@ internal class ManageTokensUseCasesFacade @AssistedInject constructor(
currenciesToAdd: Map<ManagedCryptoCurrency.Token, Set<Network>>,
currenciesToRemove: Map<ManagedCryptoCurrency.Token, Set<Network>>,
): Either<Throwable, Unit> = when (mode) {
is ManageTokensMode.Account -> TODO("Account")
is ManageTokensMode.Wallet -> saveManagedTokensUseCase.invoke(
userWalletId = mode.userWalletId,
currenciesToAdd = currenciesToAdd,
currenciesToRemove = currenciesToRemove,
)
is ManageTokensMode.Account -> {
saveCryptoCurrenciesUseCase(
accountId = mode.accountId,
add = currenciesToAdd.mapToCryptoCurrencies(userWalletId = mode.accountId.userWalletId),
remove = currenciesToRemove.mapToCryptoCurrencies(userWalletId = mode.accountId.userWalletId),
)
}
is ManageTokensMode.Wallet -> {
saveManagedTokensUseCase.invoke(
userWalletId = mode.userWalletId,
currenciesToAdd = currenciesToAdd,
currenciesToRemove = currenciesToRemove,
)
}
ManageTokensMode.None -> nonePortfolioError.left()
}
private suspend fun Map<ManagedCryptoCurrency.Token, Set<Network>>.mapToCryptoCurrencies(
userWalletId: UserWalletId,
): List<CryptoCurrency> {
return flatMap { (token, networks) ->
token.availableNetworks
.filter { sourceNetwork -> networks.contains(sourceNetwork.network) }
.map { sourceNetwork ->
when (sourceNetwork) {
is ManagedCryptoCurrency.SourceNetwork.Default -> customTokensRepository.createToken(
managedCryptoCurrency = token,
sourceNetwork = sourceNetwork,
rawId = CryptoCurrency.RawID(token.id.value),
)
is ManagedCryptoCurrency.SourceNetwork.Main -> customTokensRepository.createCoin(
userWalletId = userWalletId,
networkId = sourceNetwork.id,
derivationPath = sourceNetwork.network.derivationPath,
)
}
}
}
}
@AssistedFactory
interface Factory {
fun create(mode: ManageTokensMode): ManageTokensUseCasesFacade

View file

@ -1,12 +1,14 @@
package com.tangem.features.onramp.hottokens.portfolio.model
import arrow.core.getOrElse
import arrow.core.left
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.domain.wallets.usecase.DerivePublicKeysUseCase
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
import com.tangem.domain.wallets.usecase.DerivePublicKeysUseCase
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.features.onramp.hottokens.portfolio.OnrampAddToPortfolioComponent
import com.tangem.features.onramp.hottokens.portfolio.entity.OnrampAddToPortfolioUM
@ -35,6 +37,7 @@ internal class OnrampAddToPortfolioModel @Inject constructor(
override val dispatchers: CoroutineDispatcherProvider,
private val derivePublicKeysUseCase: DerivePublicKeysUseCase,
private val addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase,
private val accountsFeatureToggles: AccountsFeatureToggles,
private val getUserWalletUseCase: GetUserWalletUseCase,
) : Model() {
@ -73,16 +76,25 @@ internal class OnrampAddToPortfolioModel @Inject constructor(
modelScope.launch {
changeAddButtonProgressStatus(isProgress = true)
derivePublicKeysUseCase(params.userWalletId, listOfNotNull(params.cryptoCurrency)).getOrElse {
Timber.e("Failed to derive public keys: $it")
if (accountsFeatureToggles.isFeatureEnabled) {
// saveCryptoCurrenciesUseCase(
// accountId = params.accountId,
// add = params.cryptoCurrency,
// )
// TODO account
IllegalStateException("Not implemented yet").left()
} else {
derivePublicKeysUseCase(params.userWalletId, listOfNotNull(params.cryptoCurrency)).getOrElse {
Timber.e("Failed to derive public keys: $it")
changeAddButtonProgressStatus(isProgress = false)
changeAddButtonProgressStatus(isProgress = false)
}
addCryptoCurrenciesUseCase(
userWalletId = params.userWalletId,
currency = params.cryptoCurrency,
)
}
addCryptoCurrenciesUseCase(
userWalletId = params.userWalletId,
currency = params.cryptoCurrency,
)
.onRight { params.onSuccessAdding(params.cryptoCurrency.id) }
.onLeft { changeAddButtonProgressStatus(isProgress = false) }
}

View file

@ -19,6 +19,7 @@ dependencies {
implementation(projects.libs.crypto)
/** Domain modules */
implementation(projects.domain.account.status)
implementation(projects.domain.card)
implementation(projects.domain.models)
implementation(projects.domain.tokens)

View file

@ -2,6 +2,7 @@ package com.tangem.feature.referral.domain
import arrow.core.getOrElse
import com.tangem.common.core.TangemSdkError
import com.tangem.domain.account.status.usecase.SaveCryptoCurrenciesUseCase
import com.tangem.domain.models.PortfolioId
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.wallet.UserWalletId
@ -21,6 +22,7 @@ internal class ReferralInteractorImpl(
private val derivePublicKeysUseCase: DerivePublicKeysUseCase,
private val getUserWalletUseCase: GetUserWalletUseCase,
private val addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase,
private val saveCryptoCurrenciesUseCase: SaveCryptoCurrenciesUseCase,
) : ReferralInteractor {
private val tokensForReferral = mutableListOf<TokenData>()
@ -45,19 +47,23 @@ internal class ReferralInteractorImpl(
val cryptoCurrency = repository.getCryptoCurrency(userWalletId = userWallet.walletId, tokenData = tokenData)
?: error("Failed to create crypto currency")
// todo account different for account?
derivePublicKeysUseCase(userWallet.walletId, listOfNotNull(cryptoCurrency)).getOrElse {
Timber.e("Failed to derive public keys: $it")
throw it.mapToDomainError()
}
when (portfolioId) {
is PortfolioId.Account -> TODO("account")
is PortfolioId.Wallet -> addCryptoCurrenciesUseCase(
userWalletId = userWallet.walletId,
currency = cryptoCurrency,
)
is PortfolioId.Account -> {
saveCryptoCurrenciesUseCase(accountId = portfolioId.accountId, add = cryptoCurrency)
}
is PortfolioId.Wallet -> {
derivePublicKeysUseCase(userWallet.walletId, listOfNotNull(cryptoCurrency)).getOrElse {
Timber.e("Failed to derive public keys: $it")
throw it.mapToDomainError()
}
addCryptoCurrenciesUseCase(
userWalletId = userWallet.walletId,
currency = cryptoCurrency,
)
}
}
.onLeft(Timber::e)
val publicAddress = when (portfolioId) {
is PortfolioId.Account -> TODO("account")

View file

@ -1,9 +1,10 @@
package com.tangem.feature.referral.domain.di
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.di.ModelComponent
import com.tangem.domain.wallets.usecase.DerivePublicKeysUseCase
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.domain.account.status.usecase.SaveCryptoCurrenciesUseCase
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
import com.tangem.domain.wallets.usecase.DerivePublicKeysUseCase
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.feature.referral.domain.ReferralInteractor
import com.tangem.feature.referral.domain.ReferralInteractorImpl
@ -25,6 +26,7 @@ class ReferralDomainModule {
derivePublicKeysUseCase: DerivePublicKeysUseCase,
getUserWalletUseCase: GetUserWalletUseCase,
addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase,
saveCryptoCurrenciesUseCase: SaveCryptoCurrenciesUseCase,
): ReferralInteractor {
return ReferralInteractorImpl(
repository = referralRepository,
@ -32,6 +34,7 @@ class ReferralDomainModule {
derivePublicKeysUseCase = derivePublicKeysUseCase,
getUserWalletUseCase = getUserWalletUseCase,
addCryptoCurrenciesUseCase = addCryptoCurrenciesUseCase,
saveCryptoCurrenciesUseCase = saveCryptoCurrenciesUseCase,
)
}
}

View file

@ -3,6 +3,7 @@ package com.tangem.features.send.v2.send.confirm.model
import android.os.SystemClock
import androidx.compose.runtime.Stable
import arrow.core.getOrElse
import arrow.core.left
import com.tangem.blockchain.common.AmountType
import com.tangem.blockchain.common.TransactionData
import com.tangem.common.routing.AppRouter
@ -20,6 +21,7 @@ import com.tangem.core.navigation.share.ShareManager
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
import com.tangem.domain.feedback.GetWalletMetaInfoUseCase
import com.tangem.domain.feedback.SaveBlockchainErrorUseCase
@ -105,6 +107,7 @@ internal class SendConfirmModel @Inject constructor(
private val feeSelectorReloadTrigger: FeeSelectorReloadTrigger,
private val sendAmountReduceTrigger: SendAmountReduceTrigger,
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
private val accountsFeatureToggles: AccountsFeatureToggles,
sendBalanceUpdaterFactory: SendBalanceUpdater.Factory,
) : Model(), SendConfirmClickIntents, FeeSelectorModelCallback, SendNotificationsComponent.ModelCallback {
@ -429,13 +432,21 @@ internal class SendConfirmModel @Inject constructor(
val network = receivingUserWallet.network ?: return
modelScope.launch(dispatchers.default) {
withContext(NonCancellable) {
addCryptoCurrenciesUseCase(
userWalletId = userWalletId,
cryptoCurrency = cryptoCurrency,
network = network,
)
if (accountsFeatureToggles.isFeatureEnabled) {
// val tokenToAdd = currenciesRepository.createTokenCurrency(cryptoCurrency, network)
// saveCryptoCurrenciesUseCase(accountId = accountId, add = tokenToAdd)
// TODO account
IllegalStateException("Not implemented yet").left()
} else {
withContext(NonCancellable) {
addCryptoCurrenciesUseCase(
userWalletId = userWalletId,
cryptoCurrency = cryptoCurrency,
network = network,
)
}
}
.onLeft(Timber::e)
}
}