Updated on 2026-08-14

This commit is contained in:
Tangem 2025-10-21 11:27:27 +04:00
parent e07246d25d
commit 9491a9cae6
12 changed files with 82 additions and 50 deletions

View file

@ -1,23 +0,0 @@
package com.tangem.tap.common.extensions
import java.math.BigDecimal
import java.math.RoundingMode
import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
import java.util.Locale
// TODO: move extensions to utils
fun BigDecimal.toFormattedString(
decimals: Int,
roundingMode: RoundingMode = RoundingMode.DOWN,
locale: Locale = Locale.US,
): String {
val symbols = DecimalFormatSymbols(locale)
val df = DecimalFormat()
df.decimalFormatSymbols = symbols
df.maximumFractionDigits = decimals
df.minimumFractionDigits = 0
df.isGroupingUsed = true
df.roundingMode = roundingMode
return df.format(this)
}

View file

@ -17,7 +17,6 @@ import com.tangem.tap.domain.tasks.UserWalletIdPreflightReadFilter
*
[REDACTED_AUTHOR]
*/
// TODO remove it after test after resolve [REDACTED_JIRA]
internal class ResetBackupCardTask(
private val userWalletId: UserWalletId,
) : CardSessionRunnable<Boolean> {

View file

@ -28,5 +28,4 @@ class TestingCoroutineDispatcherProvider(
override val io: CoroutineDispatcher = Dispatchers.Unconfined,
override val default: CoroutineDispatcher = Dispatchers.Unconfined,
override val single: CoroutineDispatcher = Executors.newFixedThreadPool(1).asCoroutineDispatcher(),
) : CoroutineDispatcherProvider
) : CoroutineDispatcherProvider

View file

@ -49,6 +49,7 @@ class CryptoCurrencyFactory(
blockchain: Blockchain,
extraDerivationPath: String?,
userWallet: UserWallet,
accountIndex: DerivationIndex? = null,
): CryptoCurrency.Token? {
if (blockchain == Blockchain.Unknown) {
Timber.e("Unable to map the SDK token to the domain token with Unknown blockchain")
@ -59,6 +60,7 @@ class CryptoCurrencyFactory(
blockchain = blockchain,
extraDerivationPath = extraDerivationPath,
userWallet = userWallet,
accountIndex = accountIndex,
) ?: return null
val id = getTokenId(network, sdkToken)
@ -75,11 +77,16 @@ class CryptoCurrencyFactory(
)
}
fun createCoin(chainId: Int, extraDerivationPath: String?, userWallet: UserWallet): CryptoCurrency.Coin? {
fun createCoin(
chainId: Int,
extraDerivationPath: String?,
userWallet: UserWallet,
accountIndex: DerivationIndex? = null,
): CryptoCurrency.Coin? {
val blockchain: Blockchain? = Chain.entries.find { it.id == chainId }?.blockchain
return if (blockchain != null) {
createCoin(blockchain, extraDerivationPath, userWallet)
createCoin(blockchain, extraDerivationPath, userWallet, accountIndex)
} else {
Timber.e("Unable to get blockchain from chainId == $chainId")
null

View file

@ -53,7 +53,7 @@ class UserTokensResponseFactory @Inject constructor() {
fun createDefaultResponse(
userWallet: UserWallet?,
networkFactory: NetworkFactory,
accountId: AccountId? = null,
accountId: AccountId?,
): UserTokensResponse {
val tokens = userWallet?.let {
getDefaultWalletBlockchains(userWallet = it, demoConfig = DemoConfig())

View file

@ -9,6 +9,7 @@ import com.tangem.datasource.api.common.response.getOrThrow
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.api.tangemTech.models.StartReferralBody
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.models.account.DerivationIndex
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.feature.referral.converters.ReferralConverter
@ -20,7 +21,6 @@ import kotlinx.coroutines.withContext
import java.util.concurrent.ConcurrentHashMap
import javax.inject.Inject
@Suppress("LongParameterList")
internal class ReferralRepositoryImpl @Inject constructor(
private val referralApi: TangemTechApi,
private val referralConverter: ReferralConverter,
@ -74,7 +74,11 @@ internal class ReferralRepositoryImpl @Inject constructor(
}
}
override suspend fun getCryptoCurrency(userWalletId: UserWalletId, tokenData: TokenData): CryptoCurrency? {
override suspend fun getCryptoCurrency(
userWalletId: UserWalletId,
tokenData: TokenData,
accountIndex: DerivationIndex?,
): CryptoCurrency? {
val userWallet = withContext(coroutineDispatcher.io) {
userWalletsStore.getSyncOrNull(userWalletId) ?: error("Wallet $userWalletId not found")
}
@ -97,12 +101,14 @@ internal class ReferralRepositoryImpl @Inject constructor(
blockchain = blockchain,
extraDerivationPath = null,
userWallet = userWallet,
accountIndex = accountIndex,
)
} else {
cryptoCurrencyFactory.createCoin(
blockchain = blockchain,
extraDerivationPath = null,
userWallet = userWallet,
accountIndex = accountIndex,
)
}
}

View file

@ -1,6 +1,7 @@
package com.tangem.feature.referral.domain
import com.tangem.domain.models.PortfolioId
import com.tangem.domain.models.account.DerivationIndex
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.feature.referral.domain.models.ReferralData
@ -12,5 +13,9 @@ interface ReferralInteractor {
suspend fun startReferral(portfolioId: PortfolioId): ReferralData
suspend fun getCryptoCurrency(userWalletId: UserWalletId, tokenData: TokenData): CryptoCurrency?
suspend fun getCryptoCurrency(
userWalletId: UserWalletId,
tokenData: TokenData,
accountIndex: DerivationIndex?,
): CryptoCurrency?
}

View file

@ -2,8 +2,11 @@ package com.tangem.feature.referral.domain
import arrow.core.getOrElse
import com.tangem.common.core.TangemSdkError
import com.tangem.domain.account.producer.SingleAccountProducer
import com.tangem.domain.account.status.usecase.ManageCryptoCurrenciesUseCase
import com.tangem.domain.account.supplier.SingleAccountSupplier
import com.tangem.domain.models.PortfolioId
import com.tangem.domain.models.account.DerivationIndex
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
@ -23,6 +26,7 @@ internal class ReferralInteractorImpl(
private val getUserWalletUseCase: GetUserWalletUseCase,
private val addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase,
private val manageCryptoCurrenciesUseCase: ManageCryptoCurrenciesUseCase,
private val singleAccountSupplier: SingleAccountSupplier,
) : ReferralInteractor {
private val tokensForReferral = mutableListOf<TokenData>()
@ -44,7 +48,23 @@ internal class ReferralInteractorImpl(
error("Failed to get user wallet $userWalletId: $it")
}
val cryptoCurrency = repository.getCryptoCurrency(userWalletId = userWallet.walletId, tokenData = tokenData)
val accountIndex = when (portfolioId) {
is PortfolioId.Account -> {
val account = singleAccountSupplier.getSyncOrNull(
params = SingleAccountProducer.Params(accountId = portfolioId.accountId),
)
?: error("Account not found: ${portfolioId.accountId}")
account.derivationIndex
}
is PortfolioId.Wallet -> null
}
val cryptoCurrency = getCryptoCurrency(
userWalletId = portfolioId.userWalletId,
tokenData = tokenData,
accountIndex = accountIndex,
)
?: error("Failed to create crypto currency")
when (portfolioId) {
@ -65,13 +85,10 @@ internal class ReferralInteractorImpl(
}
.onLeft(Timber::e)
val publicAddress = when (portfolioId) {
is PortfolioId.Account -> TODO("account")
is PortfolioId.Wallet -> userWalletManager.getWalletAddress(
networkId = tokenData.networkId,
derivationPath = cryptoCurrency.network.derivationPath.value,
)
}
val publicAddress = userWalletManager.getWalletAddress(
networkId = tokenData.networkId,
derivationPath = cryptoCurrency.network.derivationPath.value,
)
return repository.startReferral(
walletId = userWalletManager.getWalletId(),
@ -81,8 +98,17 @@ internal class ReferralInteractorImpl(
)
}
override suspend fun getCryptoCurrency(userWalletId: UserWalletId, tokenData: TokenData): CryptoCurrency? =
repository.getCryptoCurrency(userWalletId = userWalletId, tokenData = tokenData)
override suspend fun getCryptoCurrency(
userWalletId: UserWalletId,
tokenData: TokenData,
accountIndex: DerivationIndex?,
): CryptoCurrency? {
return repository.getCryptoCurrency(
userWalletId = userWalletId,
tokenData = tokenData,
accountIndex = accountIndex,
)
}
private fun saveReferralTokens(tokens: List<TokenData>) {
tokensForReferral.clear()

View file

@ -1,5 +1,6 @@
package com.tangem.feature.referral.domain
import com.tangem.domain.models.account.DerivationIndex
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.feature.referral.domain.models.ReferralData
@ -16,5 +17,10 @@ interface ReferralRepository {
/** Starts user referral program */
suspend fun startReferral(walletId: String, networkId: String, tokenId: String, address: String): ReferralData
suspend fun getCryptoCurrency(userWalletId: UserWalletId, tokenData: TokenData): CryptoCurrency?
/** Returns [CryptoCurrency] by [tokenData] for specific [userWalletId] and optional [accountIndex] */
suspend fun getCryptoCurrency(
userWalletId: UserWalletId,
tokenData: TokenData,
accountIndex: DerivationIndex?,
): CryptoCurrency?
}

View file

@ -3,6 +3,7 @@ package com.tangem.feature.referral.domain.di
import com.tangem.core.decompose.di.ModelComponent
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.domain.account.status.usecase.ManageCryptoCurrenciesUseCase
import com.tangem.domain.account.supplier.SingleAccountSupplier
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
import com.tangem.domain.wallets.usecase.DerivePublicKeysUseCase
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
@ -27,6 +28,7 @@ class ReferralDomainModule {
getUserWalletUseCase: GetUserWalletUseCase,
addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase,
manageCryptoCurrenciesUseCase: ManageCryptoCurrenciesUseCase,
singleAccountSupplier: SingleAccountSupplier,
): ReferralInteractor {
return ReferralInteractorImpl(
repository = referralRepository,
@ -35,6 +37,7 @@ class ReferralDomainModule {
getUserWalletUseCase = getUserWalletUseCase,
addCryptoCurrenciesUseCase = addCryptoCurrenciesUseCase,
manageCryptoCurrenciesUseCase = manageCryptoCurrenciesUseCase,
singleAccountSupplier = singleAccountSupplier,
)
}
}

View file

@ -121,15 +121,20 @@ internal class ReferralModel @Inject constructor(
flow4 = portfolioFetcher.data,
) { pair, isBalanceHidden, appCurrency, portfolios ->
val selectedAccount = pair?.second ?: return@combine null
val awardCryptoCurrency = referralInteractor.getCryptoCurrency(
userWalletId = params.userWalletId,
tokenData = referralData.getToken(),
) ?: return@combine null
val cryptoPortfolio = when (selectedAccount) {
is AccountStatus.CryptoPortfolio -> selectedAccount
}
val awardCryptoCurrency = referralInteractor.getCryptoCurrency(
userWalletId = params.userWalletId,
tokenData = referralData.getToken(),
accountIndex = cryptoPortfolio.account.derivationIndex,
) ?: return@combine null
val accountAwardToken = cryptoPortfolio.tokenList.flattenCurrencies()
.find { it.currency.id == awardCryptoCurrency.id }
return@combine AccountAwardConverter(
isBalanceHidden = isBalanceHidden,
awardCryptoCurrency = awardCryptoCurrency,
@ -142,12 +147,12 @@ internal class ReferralModel @Inject constructor(
}
private fun createInitiallyUiState() = ReferralStateHolder(
headerState = ReferralStateHolder.HeaderState(
headerState = HeaderState(
onBackClicked = appRouter::pop,
),
referralInfoState = ReferralInfoState.Loading,
errorSnackbar = null,
analytics = ReferralStateHolder.Analytics(
analytics = Analytics(
onAgreementClicked = ::onAgreementClicked,
onCopyClicked = ::onCopyClicked,
onShareClicked = ::onShareClicked,

View file

@ -1,5 +1,4 @@
# docs https://docs.gradle.org/current/userguide/platforms.html
# TODO: update versions refs https://tangem.atlassian.net/browse/AND-3195
[versions]
# region Classpath