Updated on 2026-08-14
This commit is contained in:
parent
0598dd8e16
commit
bbf13f1ae8
32 changed files with 53 additions and 142 deletions
|
|
@ -45,15 +45,6 @@ interface TangemTechApi {
|
||||||
@GET("v1/geo")
|
@GET("v1/geo")
|
||||||
suspend fun getUserCountryCode(): GeoResponse
|
suspend fun getUserCountryCode(): GeoResponse
|
||||||
|
|
||||||
@GET("v1/user-tokens/{user-id}")
|
|
||||||
suspend fun getUserTokens(@Path(value = "user-id") userId: String): ApiResponse<UserTokensResponse>
|
|
||||||
|
|
||||||
@PUT("v1/user-tokens/{user-id}")
|
|
||||||
suspend fun saveUserTokens(
|
|
||||||
@Path(value = "user-id") userId: String,
|
|
||||||
@Body userTokens: UserTokensResponse,
|
|
||||||
): ApiResponse<Unit>
|
|
||||||
|
|
||||||
@PUT("/v1/wallets/{walletId}/tokens")
|
@PUT("/v1/wallets/{walletId}/tokens")
|
||||||
suspend fun saveTokens(
|
suspend fun saveTokens(
|
||||||
@Path(value = "walletId") userId: String,
|
@Path(value = "walletId") userId: String,
|
||||||
|
|
@ -138,14 +129,8 @@ interface TangemTechApi {
|
||||||
@PATCH("v1/user-wallets/wallets/{wallet_id}")
|
@PATCH("v1/user-wallets/wallets/{wallet_id}")
|
||||||
suspend fun updateWallet(@Path("wallet_id") walletId: String, @Body body: WalletBody): ApiResponse<Unit>
|
suspend fun updateWallet(@Path("wallet_id") walletId: String, @Body body: WalletBody): ApiResponse<Unit>
|
||||||
|
|
||||||
@POST("v1/user-wallets/wallets/create-and-connect-by-appuid/{application_id}")
|
|
||||||
suspend fun associateApplicationIdWithWallets(
|
|
||||||
@Path("application_id") applicationId: String,
|
|
||||||
@Body body: List<WalletIdBody>,
|
|
||||||
): ApiResponse<Unit>
|
|
||||||
|
|
||||||
@PUT("/v1/user-wallets/applications/{application_id}/wallets")
|
@PUT("/v1/user-wallets/applications/{application_id}/wallets")
|
||||||
suspend fun associateApplicationIdWithWalletsV2(
|
suspend fun associateApplicationIdWithWallets(
|
||||||
@Path("application_id") applicationId: String,
|
@Path("application_id") applicationId: String,
|
||||||
@Body body: AssociateApplicationIdWithWalletsBody,
|
@Body body: AssociateApplicationIdWithWalletsBody,
|
||||||
): ApiResponse<Unit>
|
): ApiResponse<Unit>
|
||||||
|
|
|
||||||
|
|
@ -11,23 +11,6 @@ import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||||
*/
|
*/
|
||||||
class UserTokensBackwardCompatibility {
|
class UserTokensBackwardCompatibility {
|
||||||
|
|
||||||
fun applyCompatibilityAndGetUpdated(userTokensResponse: UserTokensResponse): UserTokensResponse {
|
|
||||||
return userTokensResponse.copy(
|
|
||||||
tokens = userTokensResponse.tokens.map { token ->
|
|
||||||
val oldSavedId = NETWORKS_TO_OLD_SAVED_IDS[token.networkId]
|
|
||||||
if (oldSavedId != null && token.id == oldSavedId) {
|
|
||||||
Blockchain.fromNetworkId(token.networkId)?.let { blockchain ->
|
|
||||||
token.copy(
|
|
||||||
id = blockchain.toCoinId(),
|
|
||||||
)
|
|
||||||
} ?: token
|
|
||||||
} else {
|
|
||||||
token
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun applyCompatibilityAndGetUpdated(tokens: List<UserTokensResponse.Token>): List<UserTokensResponse.Token> {
|
fun applyCompatibilityAndGetUpdated(tokens: List<UserTokensResponse.Token>): List<UserTokensResponse.Token> {
|
||||||
return tokens.map { token ->
|
return tokens.map { token ->
|
||||||
val oldSavedId = NETWORKS_TO_OLD_SAVED_IDS[token.networkId]
|
val oldSavedId = NETWORKS_TO_OLD_SAVED_IDS[token.networkId]
|
||||||
|
|
|
||||||
|
|
@ -362,7 +362,7 @@ internal class DefaultWalletsRepository(
|
||||||
override suspend fun associateWallets(applicationId: String, wallets: List<UserWallet>) =
|
override suspend fun associateWallets(applicationId: String, wallets: List<UserWallet>) =
|
||||||
withContext(dispatchers.io) {
|
withContext(dispatchers.io) {
|
||||||
val associateApplicationIdWithWallets: suspend () -> ApiResponse<Unit> = {
|
val associateApplicationIdWithWallets: suspend () -> ApiResponse<Unit> = {
|
||||||
tangemTechApi.associateApplicationIdWithWalletsV2(
|
tangemTechApi.associateApplicationIdWithWallets(
|
||||||
applicationId = applicationId,
|
applicationId = applicationId,
|
||||||
body = AssociateApplicationIdWithWalletsBody(
|
body = AssociateApplicationIdWithWalletsBody(
|
||||||
walletIds = wallets.map { it.walletId.stringValue }.distinct(),
|
walletIds = wallets.map { it.walletId.stringValue }.distinct(),
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ class DefaultWalletsRepositoryTest {
|
||||||
inner class AssociateWallets {
|
inner class AssociateWallets {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `should convert and send to API V2`() = runTest {
|
fun `should convert and send to associateApplicationIdWithWallets`() = runTest {
|
||||||
// Arrange
|
// Arrange
|
||||||
val applicationId = "test_app_id"
|
val applicationId = "test_app_id"
|
||||||
val wallet1Id = "1234567890abcdef"
|
val wallet1Id = "1234567890abcdef"
|
||||||
|
|
@ -202,7 +202,7 @@ class DefaultWalletsRepositoryTest {
|
||||||
)
|
)
|
||||||
|
|
||||||
coEvery {
|
coEvery {
|
||||||
tangemTechApi.associateApplicationIdWithWalletsV2(eq(applicationId), any())
|
tangemTechApi.associateApplicationIdWithWallets(eq(applicationId), any())
|
||||||
} returns ApiResponse.Success(Unit)
|
} returns ApiResponse.Success(Unit)
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -210,7 +210,7 @@ class DefaultWalletsRepositoryTest {
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
coVerify(exactly = 1) {
|
coVerify(exactly = 1) {
|
||||||
tangemTechApi.associateApplicationIdWithWalletsV2(
|
tangemTechApi.associateApplicationIdWithWallets(
|
||||||
applicationId = eq(applicationId),
|
applicationId = eq(applicationId),
|
||||||
body = match { body ->
|
body = match { body ->
|
||||||
body.walletIds.size == 2 &&
|
body.walletIds.size == 2 &&
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,11 @@ package com.tangem.domain.account.status.di
|
||||||
import com.tangem.domain.account.repository.AccountsCRUDRepository
|
import com.tangem.domain.account.repository.AccountsCRUDRepository
|
||||||
import com.tangem.domain.account.status.supplier.MultiAccountStatusListSupplier
|
import com.tangem.domain.account.status.supplier.MultiAccountStatusListSupplier
|
||||||
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
|
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
|
||||||
import com.tangem.domain.account.status.usecase.GetFeePaidCryptoCurrencyStatusSyncUseCase
|
|
||||||
import com.tangem.domain.account.status.usecase.*
|
import com.tangem.domain.account.status.usecase.*
|
||||||
import com.tangem.domain.account.status.utils.CryptoCurrencyBalanceFetcher
|
import com.tangem.domain.account.status.utils.CryptoCurrencyBalanceFetcher
|
||||||
import com.tangem.domain.account.status.utils.CryptoCurrencyMetadataCleaner
|
import com.tangem.domain.account.status.utils.CryptoCurrencyMetadataCleaner
|
||||||
import com.tangem.domain.account.supplier.SingleAccountListSupplier
|
import com.tangem.domain.account.supplier.SingleAccountListSupplier
|
||||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||||
import com.tangem.utils.coroutines.AppCoroutineScope
|
|
||||||
import com.tangem.domain.express.ExpressServiceFetcher
|
import com.tangem.domain.express.ExpressServiceFetcher
|
||||||
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
||||||
import com.tangem.domain.networks.multi.MultiNetworkStatusSupplier
|
import com.tangem.domain.networks.multi.MultiNetworkStatusSupplier
|
||||||
|
|
@ -23,6 +21,7 @@ import com.tangem.domain.tokens.GetCryptoCurrencyActionsUseCase
|
||||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||||
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
||||||
|
import com.tangem.utils.coroutines.AppCoroutineScope
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
|
|
@ -76,10 +75,10 @@ internal object AccountStatusUseCaseModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideGetWalletTotalBalanceUseCaseV2(
|
fun provideGetWalletTotalBalanceUseCase(
|
||||||
multiAccountStatusListSupplier: MultiAccountStatusListSupplier,
|
multiAccountStatusListSupplier: MultiAccountStatusListSupplier,
|
||||||
): GetWalletTotalBalanceUseCaseV2 {
|
): GetWalletTotalBalanceUseCase {
|
||||||
return GetWalletTotalBalanceUseCaseV2(
|
return GetWalletTotalBalanceUseCase(
|
||||||
multiAccountStatusListSupplier = multiAccountStatusListSupplier,
|
multiAccountStatusListSupplier = multiAccountStatusListSupplier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import kotlinx.coroutines.flow.map
|
||||||
*
|
*
|
||||||
* @param multiAccountStatusListSupplier Supplier that provides the status list for multiple accounts.
|
* @param multiAccountStatusListSupplier Supplier that provides the status list for multiple accounts.
|
||||||
*/
|
*/
|
||||||
class GetWalletTotalBalanceUseCaseV2(
|
class GetWalletTotalBalanceUseCase(
|
||||||
private val multiAccountStatusListSupplier: MultiAccountStatusListSupplier,
|
private val multiAccountStatusListSupplier: MultiAccountStatusListSupplier,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
1
domain/kyc/models/.gitignore
vendored
1
domain/kyc/models/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
||||||
/build
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
plugins {
|
|
||||||
alias(deps.plugins.kotlin.jvm)
|
|
||||||
alias(deps.plugins.kotlin.serialization)
|
|
||||||
id("configuration")
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation(deps.kotlin.serialization)
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
<?xml version="1.0" ?>
|
|
||||||
<SmellBaseline>
|
|
||||||
<ManuallySuppressedIssues/>
|
|
||||||
<CurrentIssues>
|
|
||||||
<ID>BooleanPropertyNaming:TokenActionsState.kt$TokenActionsState.ActionState.Swap$val showBadge: Boolean</ID>
|
|
||||||
<ID>CanBeNonNullable:BaseActionsFactory.kt$BaseActionsFactory$requirementsDeferred: Deferred<AssetRequirementsCondition?>?</ID>
|
|
||||||
<ID>CanBeNonNullable:CommonActionsFactory.kt$CommonActionsFactory$swapUnavailableReasonDeferred: Deferred<ScenarioUnavailabilityReason>?</ID>
|
|
||||||
<ID>ExplicitCollectionElementAccessMethod:GetWalletTotalBalanceUseCase.kt$GetWalletTotalBalanceUseCase$walletBalanceCache.put(userWalletId, content)</ID>
|
|
||||||
<ID>MultilineLambdaItParameter:BaseCurrencyStatusOperations.kt$BaseCurrencyStatusOperations${ singleQuoteStatusSupplier(params = SingleQuoteStatusProducer.Params(rawCurrencyId = it)) .firstOrNull() }</ID>
|
|
||||||
<ID>MultilineLambdaItParameter:BaseCurrencyStatusOperations.kt$BaseCurrencyStatusOperations${ val exception = IllegalStateException("$it") Error.DataError(exception) }</ID>
|
|
||||||
<ID>MultilineLambdaItParameter:FetchCurrencyStatusUseCase.kt$FetchCurrencyStatusUseCase${ when (it) { is StakingIdFactory.Error.UnableToGetAddress -> raise(IllegalStateException("$it")) StakingIdFactory.Error.UnsupportedCurrency -> Unit.right() } return@either }</ID>
|
|
||||||
<ID>MultilineLambdaItParameter:GetBalanceNotEnoughForFeeWarningUseCase.kt$GetBalanceNotEnoughForFeeWarningUseCase${ it is CryptoCurrency.Token && it.contractAddress.equals(feePaidToken.contractAddress, ignoreCase = true) && it.network.derivationPath == tokenStatus.currency.network.derivationPath }</ID>
|
|
||||||
<ID>MultilineLambdaItParameter:GetCryptoCurrencyActionsUseCase.kt$GetCryptoCurrencyActionsUseCase${ TokenActionsState( walletId = userWallet.walletId, cryptoCurrencyStatus = cryptoCurrencyStatus, states = it.toList(), ) }</ID>
|
|
||||||
<ID>MultilineLambdaItParameter:GetWalletTotalBalanceUseCase.kt$GetWalletTotalBalanceUseCase${ Timber.e("failed to load balances with error: $it") TotalFiatBalance.Failed }</ID>
|
|
||||||
<ID>MultilineLambdaItParameter:PriceChangeCalculator.kt$PriceChangeCalculator${ val weight = it.value.fiatAmount.orZero().divide(balance, 2, RoundingMode.HALF_UP) val priceChange = it.value.priceChange.orZero() weight * priceChange }</ID>
|
|
||||||
<ID>MultilineLambdaItParameter:WalletBalanceFetcher.kt$WalletBalanceFetcher${ val stakingId = stakingIdFactory.create(userWalletId = userWalletId, cryptoCurrency = it) if (stakingId.isLeft { it is StakingIdFactory.Error.UnableToGetAddress }) { Timber.e("Unable to get staking ID for user wallet $userWalletId and currency ${it.id}") } stakingId }</ID>
|
|
||||||
<ID>NamedArguments:ApplyTokenListSortingUseCase.kt$ApplyTokenListSortingUseCase$saveTokens(userWalletId, currencies, isGrouped, isSortedByBalance)</ID>
|
|
||||||
<ID>NoNameShadowing:WalletBalanceFetcher.kt$WalletBalanceFetcher${ it is StakingIdFactory.Error.UnableToGetAddress }</ID>
|
|
||||||
<ID>NullableBooleanCheck:GetCurrencyCheckUseCase.kt$GetCurrencyCheckUseCase$recipientAddress?.let { currencyChecksRepository.checkIfAccountFunded( userWalletId, network, recipientAddress, ) } ?: false</ID>
|
|
||||||
<ID>SuspendFunWithFlowReturnType:BaseCurrencyStatusOperations.kt$BaseCurrencyStatusOperations$suspend</ID>
|
|
||||||
<ID>SuspendFunWithFlowReturnType:GetNetworkCoinStatusUseCase.kt$GetNetworkCoinStatusUseCase$suspend</ID>
|
|
||||||
<ID>SuspendFunWithFlowReturnType:GetSingleCryptoCurrencyStatusUseCase.kt$GetSingleCryptoCurrencyStatusUseCase$suspend</ID>
|
|
||||||
<ID>UnnecessaryAbstractClass:MultiWalletCryptoCurrenciesSupplier.kt$MultiWalletCryptoCurrenciesSupplier$MultiWalletCryptoCurrenciesSupplier</ID>
|
|
||||||
<ID>UnsafeCallOnNullableType:CommonActionsFactory.kt$CommonActionsFactory$swapUnavailableReasonDeferred!!</ID>
|
|
||||||
</CurrentIssues>
|
|
||||||
</SmellBaseline>
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
<?xml version="1.0" ?>
|
|
||||||
<SmellBaseline>
|
|
||||||
<ManuallySuppressedIssues/>
|
|
||||||
<CurrentIssues>
|
|
||||||
<ID>ObjectExtendsThrowable:RemoveCurrencyError.kt$RemoveCurrencyError$HasLinkedTokens : RemoveCurrencyError</ID>
|
|
||||||
<ID>UseEmptyCounterpart:PromoAnalyticsEvent.kt$PromoAnalyticsEvent$mapOf()</ID>
|
|
||||||
<ID>UseEmptyCounterpart:TokenExchangeAnalyticsEvent.kt$TokenExchangeAnalyticsEvent$mapOf()</ID>
|
|
||||||
<ID>UseEmptyCounterpart:TokenOnrampAnalyticsEvent.kt$TokenOnrampAnalyticsEvent$mapOf()</ID>
|
|
||||||
<ID>UseEmptyCounterpart:TokenReceiveAnalyticsEvent.kt$TokenReceiveAnalyticsEvent$mapOf()</ID>
|
|
||||||
<ID>UseEmptyCounterpart:TokenReceiveNewAnalyticsEvent.kt$TokenReceiveNewAnalyticsEvent$mapOf()</ID>
|
|
||||||
<ID>UseEmptyCounterpart:TokenScreenAnalyticsEvent.kt$TokenScreenAnalyticsEvent$mapOf()</ID>
|
|
||||||
</CurrentIssues>
|
|
||||||
</SmellBaseline>
|
|
||||||
|
|
@ -5,7 +5,7 @@ import com.tangem.core.analytics.models.AnalyticsParam
|
||||||
|
|
||||||
sealed class PromoAnalyticsEvent(
|
sealed class PromoAnalyticsEvent(
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = mapOf(),
|
params: Map<String, String> = emptyMap(),
|
||||||
) : AnalyticsEvent(category = "Promotion", event = event, params = params) {
|
) : AnalyticsEvent(category = "Promotion", event = event, params = params) {
|
||||||
data class NoticePromotionBanner(
|
data class NoticePromotionBanner(
|
||||||
private val source: AnalyticsParam.ScreensSources,
|
private val source: AnalyticsParam.ScreensSources,
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_PARAM
|
||||||
|
|
||||||
class TokenExchangeAnalyticsEvent(
|
class TokenExchangeAnalyticsEvent(
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = mapOf(),
|
params: Map<String, String> = emptyMap(),
|
||||||
) : AnalyticsEvent("Token", event, params) {
|
) : AnalyticsEvent("Token", event, params) {
|
||||||
|
|
||||||
class CexTxStatusOpened(token: String, provider: String) : TokenScreenAnalyticsEvent(
|
class CexTxStatusOpened(token: String, provider: String) : TokenScreenAnalyticsEvent(
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_PARAM
|
||||||
|
|
||||||
sealed class TokenOnrampAnalyticsEvent(
|
sealed class TokenOnrampAnalyticsEvent(
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = mapOf(),
|
params: Map<String, String> = emptyMap(),
|
||||||
) : AnalyticsEvent("Onramp", event, params) {
|
) : AnalyticsEvent("Onramp", event, params) {
|
||||||
|
|
||||||
class OnrampStatusOpened(tokenSymbol: String, provider: String, fiatCurrency: String) : TokenOnrampAnalyticsEvent(
|
class OnrampStatusOpened(tokenSymbol: String, provider: String, fiatCurrency: String) : TokenOnrampAnalyticsEvent(
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_PARAM
|
||||||
|
|
||||||
sealed class TokenReceiveAnalyticsEvent(
|
sealed class TokenReceiveAnalyticsEvent(
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = mapOf(),
|
params: Map<String, String> = emptyMap(),
|
||||||
) : AnalyticsEvent("Token / Receive", event, params) {
|
) : AnalyticsEvent("Token / Receive", event, params) {
|
||||||
|
|
||||||
class ReceiveScreenOpened(token: String) : TokenReceiveAnalyticsEvent(
|
class ReceiveScreenOpened(token: String) : TokenReceiveAnalyticsEvent(
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_PARAM
|
||||||
|
|
||||||
sealed class TokenReceiveNewAnalyticsEvent(
|
sealed class TokenReceiveNewAnalyticsEvent(
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = mapOf(),
|
params: Map<String, String> = emptyMap(),
|
||||||
) : AnalyticsEvent("Token / Receive", event, params) {
|
) : AnalyticsEvent("Token / Receive", event, params) {
|
||||||
|
|
||||||
class ReceiveScreenOpened(
|
class ReceiveScreenOpened(
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
|
||||||
*/
|
*/
|
||||||
sealed class TokenScreenAnalyticsEvent(
|
sealed class TokenScreenAnalyticsEvent(
|
||||||
event: String,
|
event: String,
|
||||||
params: Map<String, String> = mapOf(),
|
params: Map<String, String> = emptyMap(),
|
||||||
) : AnalyticsEvent("Token", event, params) {
|
) : AnalyticsEvent("Token", event, params) {
|
||||||
|
|
||||||
/** Legacy event. It has a unique category, but it also is sent on TokenScreen */
|
/** Legacy event. It has a unique category, but it also is sent on TokenScreen */
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
package com.tangem.domain.tokens.model.remove
|
|
||||||
|
|
||||||
sealed class RemoveCurrencyError : Throwable() {
|
|
||||||
data class DataError(override val cause: Throwable) : RemoveCurrencyError()
|
|
||||||
|
|
||||||
object HasLinkedTokens : RemoveCurrencyError()
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
package com.tangem.domain.tokens.model.staking
|
|
||||||
|
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
|
||||||
import com.tangem.domain.staking.model.stakekit.Yield
|
|
||||||
|
|
||||||
fun Yield.getCurrentToken(rawCurrencyId: CryptoCurrency.RawID?) =
|
|
||||||
tokens.firstOrNull { rawCurrencyId?.value == it.coinGeckoId } ?: token
|
|
||||||
|
|
@ -89,10 +89,10 @@ class GetBalanceNotEnoughForFeeWarningUseCase(
|
||||||
)
|
)
|
||||||
.orEmpty()
|
.orEmpty()
|
||||||
|
|
||||||
val token = tokens.find {
|
val token = tokens.find { currency ->
|
||||||
it is CryptoCurrency.Token &&
|
currency is CryptoCurrency.Token &&
|
||||||
it.contractAddress.equals(feePaidToken.contractAddress, ignoreCase = true) &&
|
currency.contractAddress.equals(feePaidToken.contractAddress, ignoreCase = true) &&
|
||||||
it.network.derivationPath == tokenStatus.currency.network.derivationPath
|
currency.network.derivationPath == tokenStatus.currency.network.derivationPath
|
||||||
}
|
}
|
||||||
|
|
||||||
return if (token != null) {
|
return if (token != null) {
|
||||||
|
|
|
||||||
|
|
@ -106,11 +106,11 @@ class GetCryptoCurrencyActionsUseCase(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.map {
|
.map { states ->
|
||||||
TokenActionsState(
|
TokenActionsState(
|
||||||
walletId = userWallet.walletId,
|
walletId = userWallet.walletId,
|
||||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||||
states = it.toList(),
|
states = states.toList(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.flowOn(dispatchers.default)
|
.flowOn(dispatchers.default)
|
||||||
|
|
|
||||||
|
|
@ -36,13 +36,15 @@ class GetCurrencyCheckUseCase(
|
||||||
currencyStatus = feeCurrencyStatus,
|
currencyStatus = feeCurrencyStatus,
|
||||||
balanceAfterTransaction = feeCurrencyBalanceAfterTransaction ?: BigDecimal.ZERO,
|
balanceAfterTransaction = feeCurrencyBalanceAfterTransaction ?: BigDecimal.ZERO,
|
||||||
)
|
)
|
||||||
val isAccountFunded = recipientAddress?.let {
|
val isAccountFunded = if (recipientAddress != null) {
|
||||||
currencyChecksRepository.checkIfAccountFunded(
|
currencyChecksRepository.checkIfAccountFunded(
|
||||||
userWalletId,
|
userWalletId = userWalletId,
|
||||||
network,
|
network = network,
|
||||||
recipientAddress,
|
address = recipientAddress,
|
||||||
)
|
)
|
||||||
} ?: false
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
val utxoAmountLimit = if (currency is CryptoCurrency.Coin && amount != null && fee != null) {
|
val utxoAmountLimit = if (currency is CryptoCurrency.Coin && amount != null && fee != null) {
|
||||||
currencyChecksRepository.checkUtxoAmountLimit(
|
currencyChecksRepository.checkUtxoAmountLimit(
|
||||||
userWalletId = userWalletId,
|
userWalletId = userWalletId,
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesProducer as Producer
|
||||||
*
|
*
|
||||||
[REDACTED_AUTHOR]
|
[REDACTED_AUTHOR]
|
||||||
*/
|
*/
|
||||||
|
@Suppress("UnnecessaryAbstractClass")
|
||||||
abstract class MultiWalletCryptoCurrenciesSupplier(
|
abstract class MultiWalletCryptoCurrenciesSupplier(
|
||||||
override val factory: FlowProducer.Factory<Producer.Params, Producer>,
|
override val factory: FlowProducer.Factory<Producer.Params, Producer>,
|
||||||
override val keyCreator: (Producer.Params) -> String,
|
override val keyCreator: (Producer.Params) -> String,
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,7 @@ internal open class BaseActionsFactory(
|
||||||
* @param isAddressAvailable indicates whether the address is available
|
* @param isAddressAvailable indicates whether the address is available
|
||||||
* @param requirementsDeferred a deferred object containing the asset requirements condition
|
* @param requirementsDeferred a deferred object containing the asset requirements condition
|
||||||
*/
|
*/
|
||||||
|
@Suppress("CanBeNonNullable")
|
||||||
protected suspend fun ActionAvailabilityBuilder.addReceiveAction(
|
protected suspend fun ActionAvailabilityBuilder.addReceiveAction(
|
||||||
isAddressAvailable: Boolean,
|
isAddressAvailable: Boolean,
|
||||||
requirementsDeferred: Deferred<AssetRequirementsCondition?>?,
|
requirementsDeferred: Deferred<AssetRequirementsCondition?>?,
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,7 @@ internal class CommonActionsFactory(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("CanBeNonNullable")
|
||||||
private suspend fun createSwapAction(
|
private suspend fun createSwapAction(
|
||||||
userWallet: UserWallet,
|
userWallet: UserWallet,
|
||||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||||
|
|
@ -153,7 +154,7 @@ internal class CommonActionsFactory(
|
||||||
if (!isMultiCurrency) {
|
if (!isMultiCurrency) {
|
||||||
return ActionState.Swap(
|
return ActionState.Swap(
|
||||||
unavailabilityReason = ScenarioUnavailabilityReason.SingleWallet,
|
unavailabilityReason = ScenarioUnavailabilityReason.SingleWallet,
|
||||||
showBadge = false,
|
shouldShowBadge = false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -161,21 +162,23 @@ internal class CommonActionsFactory(
|
||||||
cryptoCurrency.isCustom -> {
|
cryptoCurrency.isCustom -> {
|
||||||
ActionState.Swap(
|
ActionState.Swap(
|
||||||
unavailabilityReason = ScenarioUnavailabilityReason.CustomToken(cryptoCurrency.name),
|
unavailabilityReason = ScenarioUnavailabilityReason.CustomToken(cryptoCurrency.name),
|
||||||
showBadge = false,
|
shouldShowBadge = false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
cryptoCurrencyStatus.value is CryptoCurrencyStatus.NoQuote -> {
|
cryptoCurrencyStatus.value is CryptoCurrencyStatus.NoQuote -> {
|
||||||
ActionState.Swap(
|
ActionState.Swap(
|
||||||
unavailabilityReason = ScenarioUnavailabilityReason.TokenNoQuotes(cryptoCurrency.name),
|
unavailabilityReason = ScenarioUnavailabilityReason.TokenNoQuotes(cryptoCurrency.name),
|
||||||
showBadge = false,
|
shouldShowBadge = false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val reason = swapUnavailableReasonDeferred!!.await()
|
val reason = requireNotNull(swapUnavailableReasonDeferred) {
|
||||||
|
"swapUnavailableReasonDeferred must not be null for available swap action"
|
||||||
|
}.await()
|
||||||
|
|
||||||
return ActionState.Swap(
|
return ActionState.Swap(
|
||||||
unavailabilityReason = reason,
|
unavailabilityReason = reason,
|
||||||
showBadge = reason == ScenarioUnavailabilityReason.None && shouldShowSwapStories,
|
shouldShowBadge = reason == ScenarioUnavailabilityReason.None && shouldShowSwapStories,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ internal class OutdatedDataActionsFactory(
|
||||||
sources.networkSource == StatusSource.ONLY_CACHE -> ScenarioUnavailabilityReason.UsedOutdatedData
|
sources.networkSource == StatusSource.ONLY_CACHE -> ScenarioUnavailabilityReason.UsedOutdatedData
|
||||||
else -> ScenarioUnavailabilityReason.DataLoading // CACHE source always when loading
|
else -> ScenarioUnavailabilityReason.DataLoading // CACHE source always when loading
|
||||||
},
|
},
|
||||||
showBadge = false,
|
shouldShowBadge = false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ internal class UnreachableActionsFactory(
|
||||||
ActionState.Send(unavailabilityReason = ScenarioUnavailabilityReason.Unreachable),
|
ActionState.Send(unavailabilityReason = ScenarioUnavailabilityReason.Unreachable),
|
||||||
ActionState.Swap(
|
ActionState.Swap(
|
||||||
unavailabilityReason = ScenarioUnavailabilityReason.Unreachable,
|
unavailabilityReason = ScenarioUnavailabilityReason.Unreachable,
|
||||||
showBadge = false,
|
shouldShowBadge = false,
|
||||||
),
|
),
|
||||||
ActionState.Sell(unavailabilityReason = ScenarioUnavailabilityReason.Unreachable),
|
ActionState.Sell(unavailabilityReason = ScenarioUnavailabilityReason.Unreachable),
|
||||||
ActionState.Stake(unavailabilityReason = ScenarioUnavailabilityReason.Unreachable, option = null),
|
ActionState.Stake(unavailabilityReason = ScenarioUnavailabilityReason.Unreachable, option = null),
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ data class TokenActionsState(
|
||||||
|
|
||||||
data class Swap(
|
data class Swap(
|
||||||
override val unavailabilityReason: ScenarioUnavailabilityReason,
|
override val unavailabilityReason: ScenarioUnavailabilityReason,
|
||||||
val showBadge: Boolean,
|
val shouldShowBadge: Boolean,
|
||||||
) : ActionState()
|
) : ActionState()
|
||||||
|
|
||||||
data class Send(override val unavailabilityReason: ScenarioUnavailabilityReason) : ActionState()
|
data class Send(override val unavailabilityReason: ScenarioUnavailabilityReason) : ActionState()
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,9 @@ object PriceChangeCalculator {
|
||||||
return createZeroPriceChange(source = walletTotalFiatBalance.source).lceContent()
|
return createZeroPriceChange(source = walletTotalFiatBalance.source).lceContent()
|
||||||
}
|
}
|
||||||
|
|
||||||
val total = statuses.sumOf {
|
val total = statuses.sumOf { status ->
|
||||||
val weight = it.value.fiatAmount.orZero().divide(balance, 2, RoundingMode.HALF_UP)
|
val weight = status.value.fiatAmount.orZero().divide(balance, 2, RoundingMode.HALF_UP)
|
||||||
val priceChange = it.value.priceChange.orZero()
|
val priceChange = status.value.priceChange.orZero()
|
||||||
|
|
||||||
weight * priceChange
|
weight * priceChange
|
||||||
}.stripTrailingZeros()
|
}.stripTrailingZeros()
|
||||||
|
|
|
||||||
|
|
@ -189,11 +189,11 @@ class WalletBalanceFetcher internal constructor(
|
||||||
userWalletId: UserWalletId,
|
userWalletId: UserWalletId,
|
||||||
currencies: Set<CryptoCurrency>,
|
currencies: Set<CryptoCurrency>,
|
||||||
): Either<Throwable, Unit> = either {
|
): Either<Throwable, Unit> = either {
|
||||||
val maybeStakingIds = currencies.map {
|
val maybeStakingIds = currencies.map { currency ->
|
||||||
val stakingId = stakingIdFactory.create(userWalletId = userWalletId, cryptoCurrency = it)
|
val stakingId = stakingIdFactory.create(userWalletId = userWalletId, cryptoCurrency = currency)
|
||||||
|
|
||||||
if (stakingId.isLeft { it is StakingIdFactory.Error.UnableToGetAddress }) {
|
if (stakingId.isLeft { it is StakingIdFactory.Error.UnableToGetAddress }) {
|
||||||
Timber.e("Unable to get staking ID for user wallet $userWalletId and currency ${it.id}")
|
Timber.e("Unable to get staking ID for user wallet $userWalletId and currency ${currency.id}")
|
||||||
}
|
}
|
||||||
|
|
||||||
stakingId
|
stakingId
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ internal class PortfolioTokenUMConverter(
|
||||||
if (action.unavailabilityReason == ScenarioUnavailabilityReason.None) {
|
if (action.unavailabilityReason == ScenarioUnavailabilityReason.None) {
|
||||||
when (action) {
|
when (action) {
|
||||||
is TokenActionsState.ActionState.Buy -> QuickActionUM.Buy
|
is TokenActionsState.ActionState.Buy -> QuickActionUM.Buy
|
||||||
is TokenActionsState.ActionState.Swap -> QuickActionUM.Exchange(action.showBadge)
|
is TokenActionsState.ActionState.Swap -> QuickActionUM.Exchange(action.shouldShowBadge)
|
||||||
is TokenActionsState.ActionState.Receive -> QuickActionUM.Receive
|
is TokenActionsState.ActionState.Receive -> QuickActionUM.Receive
|
||||||
is TokenActionsState.ActionState.Stake -> QuickActionUM.Stake
|
is TokenActionsState.ActionState.Stake -> QuickActionUM.Stake
|
||||||
is TokenActionsState.ActionState.YieldMode -> QuickActionUM.YieldMode(action.apy)
|
is TokenActionsState.ActionState.YieldMode -> QuickActionUM.YieldMode(action.apy)
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ internal class TokenDetailsActionButtonsConverter(
|
||||||
TokenDetailsActionButton.Swap(
|
TokenDetailsActionButton.Swap(
|
||||||
dimContent = action.unavailabilityReason != ScenarioUnavailabilityReason.None,
|
dimContent = action.unavailabilityReason != ScenarioUnavailabilityReason.None,
|
||||||
onClick = { clickIntents.onSwapClick(action.unavailabilityReason) },
|
onClick = { clickIntents.onSwapClick(action.unavailabilityReason) },
|
||||||
showBadge = action.showBadge,
|
showBadge = action.shouldShowBadge,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import com.tangem.common.ui.userwallet.state.UserWalletItemUM
|
||||||
import com.tangem.core.decompose.ui.UiMessageSender
|
import com.tangem.core.decompose.ui.UiMessageSender
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
import com.tangem.core.ui.message.SnackbarMessage
|
import com.tangem.core.ui.message.SnackbarMessage
|
||||||
import com.tangem.domain.account.status.usecase.GetWalletTotalBalanceUseCaseV2
|
import com.tangem.domain.account.status.usecase.GetWalletTotalBalanceUseCase
|
||||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||||
import com.tangem.domain.appcurrency.error.SelectedAppCurrencyError
|
import com.tangem.domain.appcurrency.error.SelectedAppCurrencyError
|
||||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
|
|
@ -37,7 +37,7 @@ import kotlinx.coroutines.flow.*
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList")
|
||||||
internal class DefaultUserWalletsFetcher @AssistedInject constructor(
|
internal class DefaultUserWalletsFetcher @AssistedInject constructor(
|
||||||
getWalletsUseCase: GetWalletsUseCase,
|
getWalletsUseCase: GetWalletsUseCase,
|
||||||
private val getWalletTotalBalanceUseCaseV2: GetWalletTotalBalanceUseCaseV2,
|
private val getWalletTotalBalanceUseCase: GetWalletTotalBalanceUseCase,
|
||||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||||
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||||
@Assisted private val onWalletClick: (UserWalletId) -> Unit,
|
@Assisted private val onWalletClick: (UserWalletId) -> Unit,
|
||||||
|
|
@ -99,7 +99,7 @@ internal class DefaultUserWalletsFetcher @AssistedInject constructor(
|
||||||
// We should not load balances in auth mode
|
// We should not load balances in auth mode
|
||||||
flowOf(Lce.Loading(walletIds.associateWith { TotalFiatBalance.Loading }))
|
flowOf(Lce.Loading(walletIds.associateWith { TotalFiatBalance.Loading }))
|
||||||
} else {
|
} else {
|
||||||
getWalletTotalBalanceUseCaseV2(userWalletIds = walletIds)
|
getWalletTotalBalanceUseCase(userWalletIds = walletIds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue