diff --git a/core/utils/src/main/java/com/tangem/utils/coroutines/JobHolder.kt b/core/utils/src/main/java/com/tangem/utils/coroutines/JobHolder.kt index fa2f9a10b6..d6ac93583e 100644 --- a/core/utils/src/main/java/com/tangem/utils/coroutines/JobHolder.kt +++ b/core/utils/src/main/java/com/tangem/utils/coroutines/JobHolder.kt @@ -30,6 +30,10 @@ class JobHolder { job = null } + suspend fun join() { + job?.join() + } + fun isEmpty() = job == null } diff --git a/features/onramp/impl/build.gradle.kts b/features/onramp/impl/build.gradle.kts index 290dd27ce5..1e3239f200 100644 --- a/features/onramp/impl/build.gradle.kts +++ b/features/onramp/impl/build.gradle.kts @@ -50,6 +50,7 @@ dependencies { implementation(projects.domain.account.status) implementation(projects.domain.appTheme) implementation(projects.domain.appTheme.models) + implementation(projects.data.common) /** DI */ implementation(deps.hilt.android) @@ -68,6 +69,10 @@ dependencies { implementation(deps.compose.shimmer) implementation(deps.compose.coil) + /** Tangem libraries */ + implementation(tangemDeps.blockchain) + implementation(projects.libs.blockchainSdk) + /** Other */ implementation(deps.decompose.ext.compose) implementation(deps.kotlin.immutable.collections) diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/model/HotCryptoModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/model/HotCryptoModel.kt index 75812c5cef..40ac56570b 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/model/HotCryptoModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/model/HotCryptoModel.kt @@ -8,18 +8,28 @@ import com.arkivanov.decompose.router.stack.StackNavigation import com.arkivanov.decompose.router.stack.popToFirst import com.arkivanov.decompose.router.stack.pushNew import com.arkivanov.decompose.router.stack.replaceAll +import com.tangem.blockchainsdk.utils.toBlockchain +import com.tangem.blockchainsdk.utils.toCoinId import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.ui.components.token.state.TokenItemState import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM import com.tangem.core.ui.extensions.resourceReference +import com.tangem.data.common.currency.getCoinId +import com.tangem.data.common.currency.getTokenId +import com.tangem.data.common.currency.isCustomCoin +import com.tangem.data.common.currency.isCustomToken +import com.tangem.data.common.network.NetworkFactory import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency +import com.tangem.domain.models.account.AccountStatus +import com.tangem.domain.models.account.derivationIndex import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus +import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.onramp.GetHotCryptoUseCase import com.tangem.domain.onramp.model.HotCryptoCurrency import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase @@ -70,6 +80,7 @@ internal class HotCryptoModel @Inject constructor( private val accountsFeatureToggles: AccountsFeatureToggles, private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase, val portfolioSelectorController: PortfolioSelectorController, + private val networkFactory: NetworkFactory, private val portfolioFetcherFactory: PortfolioFetcher.Factory, ) : Model(), OnrampAddTokenComponent.Callbacks by callbackDelegate { @@ -172,10 +183,15 @@ internal class HotCryptoModel @Inject constructor( if (isSingleAccount) { val account = hotCryptoPortfolioData.wallet.accounts.first().account - val tokenToAdd = AddHotCryptoData( + val cryptoCurrency = updateCryptoCurrency( cryptoCurrency = currency.cryptoCurrency, userWallet = userWallet, account = account, + ) + val tokenToAdd = AddHotCryptoData( + cryptoCurrency = requireNotNull(cryptoCurrency), + userWallet = userWallet, + account = account, isMorePortfolioAvailable = false, ) hotCryptoToAddDataFlow.emit(tokenToAdd) @@ -188,10 +204,15 @@ internal class HotCryptoModel @Inject constructor( .selectedAccountWithData(requireNotNull(portfolioFetcher)) .filterNotNull() .map { (_, selectedAccount) -> - AddHotCryptoData( + val cryptoCurrency = updateCryptoCurrency( cryptoCurrency = currency.cryptoCurrency, userWallet = userWallet, account = selectedAccount, + ) + AddHotCryptoData( + cryptoCurrency = requireNotNull(cryptoCurrency), + userWallet = userWallet, + account = selectedAccount, isMorePortfolioAvailable = true, ) } @@ -251,6 +272,47 @@ internal class HotCryptoModel @Inject constructor( return@isEnabled isNotAddedHotCrypto } } + + // todo account move to common module + private fun updateCryptoCurrency( + cryptoCurrency: CryptoCurrency, + userWallet: UserWallet, + account: AccountStatus, + ): CryptoCurrency? { + val derivationIndex = account.account.derivationIndex ?: return null + val blockchain = cryptoCurrency.network.toBlockchain() + + val network = networkFactory.create( + blockchain = blockchain, + extraDerivationPath = null, + accountIndex = derivationIndex, + userWallet = userWallet, + ) ?: return null + + return when (cryptoCurrency) { + is CryptoCurrency.Coin -> { + val id = getCoinId(network, network.toBlockchain().toCoinId()) + cryptoCurrency.copy( + id = id, + network = network, + isCustom = isCustomCoin(network), + ) + } + + is CryptoCurrency.Token -> { + val id = getTokenId( + network = network, + rawTokenId = cryptoCurrency.id.rawCurrencyId, + contractAddress = cryptoCurrency.contractAddress, + ) + cryptoCurrency.copy( + id = id, + network = network, + isCustom = isCustomToken(id, network), + ) + } + } + } } @ModelScoped diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/portfolio/model/OnrampAddTokenModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/portfolio/model/OnrampAddTokenModel.kt index d786999cad..0432278b80 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/portfolio/model/OnrampAddTokenModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/hottokens/portfolio/model/OnrampAddTokenModel.kt @@ -10,6 +10,8 @@ import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.message.ToastMessage import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase import com.tangem.domain.account.status.usecase.ManageCryptoCurrenciesUseCase +import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.wallets.usecase.BackendId import com.tangem.domain.wallets.usecase.ColdWalletAndHasMissedDerivationsUseCase @@ -47,10 +49,14 @@ internal class OnrampAddTokenModel @Inject constructor( params.tokenToAdd .distinctUntilChanged() .mapLatest { tokenToAdd: AddHotCryptoData -> - addTokenJob.cancel() + addTokenJob.join() val backendId = tokenToAdd.cryptoCurrency.network.backendId val userWalletId = tokenToAdd.account.accountId.userWalletId - val isTangemIconVisible = needColdWalletInteraction(userWalletId, backendId) + val isTangemIconVisible = needColdWalletInteraction( + walletId = userWalletId, + backendId = backendId, + cryptoCurrency = tokenToAdd.cryptoCurrency, + ) uiBuilder.updateContent( tokenToAdd = tokenToAdd, isTangemIconVisible = isTangemIconVisible, @@ -79,7 +85,9 @@ internal class OnrampAddTokenModel @Inject constructor( userWalletId = accountId.userWalletId, currencyId = cryptoCurrency.id, network = cryptoCurrency.network, - ).firstOrNull() + ) + .filter { (_, status) -> status.value !is CryptoCurrencyStatus.Loading } + .firstOrNull() if (status == null) { processError(error = null) } else { @@ -88,11 +96,14 @@ internal class OnrampAddTokenModel @Inject constructor( uiState.value = um.toggleProgress(false) } - private suspend fun needColdWalletInteraction(walletId: UserWalletId, backendId: BackendId): Boolean = - coldWalletAndHasMissedDerivationsUseCase.invoke( - userWalletId = walletId, - networksWithDerivationPath = mapOf(backendId to null), - ) + private suspend fun needColdWalletInteraction( + walletId: UserWalletId, + backendId: BackendId, + cryptoCurrency: CryptoCurrency, + ): Boolean = coldWalletAndHasMissedDerivationsUseCase.invoke( + userWalletId = walletId, + networksWithDerivationPath = mapOf(backendId to cryptoCurrency.network.derivationPath.value), + ) private fun processError(error: Throwable?) { val message = error?.message?.let { stringReference(it) }