Updated on 2026-08-14
This commit is contained in:
parent
73028360f4
commit
eaba6ee88d
21 changed files with 282 additions and 81 deletions
|
|
@ -1,18 +1,17 @@
|
|||
package com.tangem.tap.domain.walletStores.repository.implementation
|
||||
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.catching
|
||||
import com.tangem.common.doOnSuccess
|
||||
import com.tangem.common.mapFailure
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.domain.common.BlockchainNetwork
|
||||
import com.tangem.domain.common.DerivationStyleProvider
|
||||
import com.tangem.domain.common.TapWorkarounds.isTestCard
|
||||
import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation
|
||||
import com.tangem.domain.common.extensions.makeWalletManagerForApp
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.wallets.legacy.WalletManagersRepository
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
|
|
@ -70,7 +69,7 @@ internal class DefaultWalletManagersRepository(
|
|||
}
|
||||
val derivationParams = getDerivationParams(
|
||||
derivationPath = blockchainNetwork?.derivationPath,
|
||||
card = scanResponse.card,
|
||||
derivationStyleProvider = scanResponse.derivationStyleProvider,
|
||||
)
|
||||
|
||||
val walletManager = blockchain?.let {
|
||||
|
|
@ -209,17 +208,16 @@ internal class DefaultWalletManagersRepository(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getDerivationParams(derivationPath: String?, card: CardDTO): DerivationParams? {
|
||||
return derivationPath?.let {
|
||||
DerivationParams.Custom(
|
||||
path = DerivationPath(it),
|
||||
)
|
||||
} ?: if (!card.settings.isHDWalletAllowed) {
|
||||
null
|
||||
} else if (card.useOldStyleDerivation) {
|
||||
DerivationParams.Default(DerivationStyle.LEGACY)
|
||||
private fun getDerivationParams(
|
||||
derivationPath: String?,
|
||||
derivationStyleProvider: DerivationStyleProvider,
|
||||
): DerivationParams? {
|
||||
val derivationStyle = derivationStyleProvider.getDerivationStyle() ?: return null
|
||||
|
||||
return if (derivationPath == null) {
|
||||
DerivationParams.Default(derivationStyle)
|
||||
} else {
|
||||
DerivationParams.Default(DerivationStyle.NEW)
|
||||
DerivationParams.Custom(DerivationPath(derivationPath))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ import com.tangem.domain.common.extensions.toCoinId
|
|||
import com.tangem.domain.common.extensions.toNetworkId
|
||||
import com.tangem.domain.tokens.legacy.TradeCryptoAction
|
||||
import com.tangem.domain.tokens.models.CryptoCurrency
|
||||
import com.tangem.domain.tokens.models.Network
|
||||
import com.tangem.feature.swap.presentation.SwapFragment
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Token
|
||||
|
|
@ -53,11 +54,18 @@ class TradeCryptoMiddleware {
|
|||
is TradeCryptoAction.SendCrypto -> preconfigureAndOpenSendScreen(action)
|
||||
is TradeCryptoAction.FinishSelling -> openReceiptUrl(action.transactionId)
|
||||
is TradeCryptoAction.Swap -> {
|
||||
openSwap(currency = store.state.walletState.selectedWalletData?.currency?.toSwapCurrency())
|
||||
openSwap(
|
||||
currency = store.state.walletState.selectedWalletData?.currency?.toSwapCurrency(),
|
||||
derivationPath = store.state.walletState.selectedWalletData?.currency?.derivationPath,
|
||||
)
|
||||
}
|
||||
is TradeCryptoAction.New.Buy -> proceedNewBuyAction(state, action)
|
||||
is TradeCryptoAction.New.Sell -> proceedNewSellAction(action)
|
||||
is TradeCryptoAction.New.Swap -> openSwap(currency = action.cryptoCurrency.toSwapCurrency())
|
||||
is TradeCryptoAction.New.Swap -> openSwap(
|
||||
currency = action.cryptoCurrency.toSwapCurrency(),
|
||||
derivationPath = action.cryptoCurrency.network.derivationPath.value,
|
||||
network = action.cryptoCurrency.network,
|
||||
)
|
||||
is TradeCryptoAction.New.SendToken -> handleNewSendToken(action = action)
|
||||
is TradeCryptoAction.New.SendCoin -> handleNewSendCoin(action = action)
|
||||
}
|
||||
|
|
@ -240,10 +248,11 @@ class TradeCryptoMiddleware {
|
|||
)?.let { store.dispatchOpenUrl(it) }
|
||||
}
|
||||
|
||||
private fun openSwap(currency: SwapCurrency?) {
|
||||
private fun openSwap(currency: SwapCurrency?, derivationPath: String?, network: Network? = null) {
|
||||
val bundle = bundleOf(
|
||||
SwapFragment.CURRENCY_BUNDLE_KEY to Json.encodeToString(currency),
|
||||
SwapFragment.DERIVATION_PATH to store.state.walletState.selectedWalletData?.currency?.derivationPath,
|
||||
SwapFragment.DERIVATION_PATH to derivationPath,
|
||||
SwapFragment.NETWORK to network,
|
||||
)
|
||||
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(screen = AppScreen.Swap, bundle = bundle))
|
||||
|
|
@ -266,11 +275,11 @@ class TradeCryptoMiddleware {
|
|||
}
|
||||
is CryptoCurrency.Token -> {
|
||||
SwapCurrency.NonNativeToken(
|
||||
id = id.value,
|
||||
id = id.rawCurrencyId ?: "",
|
||||
name = name,
|
||||
symbol = symbol,
|
||||
networkId = blockchain.toNetworkId(),
|
||||
logoUrl = getIconUrl(id.value),
|
||||
logoUrl = getIconUrl(id.rawCurrencyId ?: ""),
|
||||
contractAddress = contractAddress,
|
||||
decimalCount = decimals,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
|
|||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.common.BlockchainNetwork
|
||||
import com.tangem.domain.common.extensions.fromNetworkId
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||
import com.tangem.lib.crypto.TransactionManager
|
||||
import com.tangem.lib.crypto.models.*
|
||||
import com.tangem.lib.crypto.models.transactions.SendTxResult
|
||||
|
|
@ -35,6 +37,8 @@ class TransactionManagerImpl(
|
|||
private val appStateHolder: AppStateHolder,
|
||||
private val analytics: AnalyticsEventHandler,
|
||||
private val cardSdkConfigRepository: CardSdkConfigRepository,
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val walletFeatureToggles: WalletFeatureToggles,
|
||||
) : TransactionManager {
|
||||
|
||||
override suspend fun sendApproveTransaction(
|
||||
|
|
@ -409,9 +413,20 @@ class TransactionManagerImpl(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getActualWalletManager(blockchain: Blockchain, derivationPath: String?): WalletManager {
|
||||
val blockchainNetwork = BlockchainNetwork(blockchain, derivationPath, emptyList())
|
||||
val walletManager = appStateHolder.walletState?.getWalletManager(blockchainNetwork)
|
||||
private suspend fun getActualWalletManager(blockchain: Blockchain, derivationPath: String?): WalletManager {
|
||||
val walletManager = if (walletFeatureToggles.isRedesignedScreenEnabled) {
|
||||
val selectedUserWallet = requireNotNull(
|
||||
appStateHolder.userWalletsListManager?.selectedUserWalletSync,
|
||||
) { "userWallet or userWalletsListManager is null" }
|
||||
walletManagersFacade.getOrCreateWalletManager(
|
||||
selectedUserWallet,
|
||||
blockchain,
|
||||
derivationPath,
|
||||
)
|
||||
} else {
|
||||
val blockchainNetwork = BlockchainNetwork(blockchain, derivationPath, emptyList())
|
||||
appStateHolder.walletState?.getWalletManager(blockchainNetwork)
|
||||
}
|
||||
return requireNotNull(walletManager) { "no wallet manager found" }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import com.tangem.domain.common.extensions.fromNetworkId
|
|||
import com.tangem.domain.common.extensions.toCoinId
|
||||
import com.tangem.domain.common.extensions.toNetworkId
|
||||
import com.tangem.domain.userwallets.UserWalletIdBuilder
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||
import com.tangem.lib.crypto.UserWalletManager
|
||||
import com.tangem.lib.crypto.models.Currency
|
||||
import com.tangem.lib.crypto.models.Currency.NativeToken
|
||||
|
|
@ -29,6 +31,8 @@ import com.tangem.tap.features.wallet.models.Currency as WalletCurrency
|
|||
|
||||
class UserWalletManagerImpl(
|
||||
private val appStateHolder: AppStateHolder,
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val walletFeatureToggles: WalletFeatureToggles,
|
||||
) : UserWalletManager {
|
||||
|
||||
override suspend fun getUserTokens(
|
||||
|
|
@ -142,13 +146,13 @@ class UserWalletManagerImpl(
|
|||
}
|
||||
}
|
||||
|
||||
override fun getWalletAddress(networkId: String, derivationPath: String?): String {
|
||||
override suspend fun getWalletAddress(networkId: String, derivationPath: String?): String {
|
||||
val blockchain = requireNotNull(Blockchain.fromNetworkId(networkId)) { "blockchain not found" }
|
||||
val walletManager = getActualWalletManager(blockchain, derivationPath)
|
||||
return walletManager.wallet.address
|
||||
}
|
||||
|
||||
override fun getLastTransactionHash(networkId: String, derivationPath: String?): String? {
|
||||
override suspend fun getLastTransactionHash(networkId: String, derivationPath: String?): String? {
|
||||
val blockchain = requireNotNull(Blockchain.fromNetworkId(networkId)) { "blockchain not found" }
|
||||
val walletManager = getActualWalletManager(blockchain, derivationPath)
|
||||
return walletManager.wallet.recentTransactions
|
||||
|
|
@ -187,7 +191,7 @@ class UserWalletManagerImpl(
|
|||
return balances
|
||||
}
|
||||
|
||||
override fun getNativeTokenBalance(networkId: String, derivationPath: String?): ProxyAmount? {
|
||||
override suspend fun getNativeTokenBalance(networkId: String, derivationPath: String?): ProxyAmount? {
|
||||
val blockchain = requireNotNull(Blockchain.fromNetworkId(networkId)) { "blockchain not found" }
|
||||
val walletManager = getActualWalletManager(blockchain, derivationPath)
|
||||
return walletManager.wallet.amounts.firstNotNullOfOrNull {
|
||||
|
|
@ -220,10 +224,24 @@ class UserWalletManagerImpl(
|
|||
appStateHolder.mainStore?.dispatchOnMain(WalletAction.LoadData.Refresh)
|
||||
}
|
||||
|
||||
@kotlin.jvm.Throws(IllegalArgumentException::class)
|
||||
private fun getActualWalletManager(blockchain: Blockchain, derivationPath: String?): WalletManager {
|
||||
val blockchainNetwork = BlockchainNetwork(blockchain, derivationPath, emptyList())
|
||||
return requireNotNull(appStateHolder.walletState?.getWalletManager(blockchainNetwork)) {
|
||||
@Throws(IllegalArgumentException::class)
|
||||
private suspend fun getActualWalletManager(blockchain: Blockchain, derivationPath: String?): WalletManager {
|
||||
val walletManager = if (walletFeatureToggles.isRedesignedScreenEnabled) {
|
||||
val selectedUserWallet = requireNotNull(
|
||||
appStateHolder.userWalletsListManager?.selectedUserWalletSync,
|
||||
) { "userWallet or userWalletsListManager is null" }
|
||||
walletManagersFacade.getOrCreateWalletManager(
|
||||
selectedUserWallet,
|
||||
blockchain,
|
||||
derivationPath,
|
||||
)
|
||||
} else {
|
||||
val blockchainNetwork = BlockchainNetwork(blockchain, derivationPath, emptyList())
|
||||
return requireNotNull(appStateHolder.walletState?.getWalletManager(blockchainNetwork)) {
|
||||
"No wallet manager found"
|
||||
}
|
||||
}
|
||||
return requireNotNull(walletManager) {
|
||||
"No wallet manager found"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
|
|||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.feature.learn2earn.domain.api.Learn2earnDependencyProvider
|
||||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||
import com.tangem.lib.crypto.DerivationManager
|
||||
import com.tangem.lib.crypto.TransactionManager
|
||||
import com.tangem.lib.crypto.UserWalletManager
|
||||
|
|
@ -32,9 +34,15 @@ class ProxyModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideUserWalletManager(appStateHolder: AppStateHolder): UserWalletManager {
|
||||
fun provideUserWalletManager(
|
||||
appStateHolder: AppStateHolder,
|
||||
walletManagersFacade: WalletManagersFacade,
|
||||
walletFeatureToggles: WalletFeatureToggles,
|
||||
): UserWalletManager {
|
||||
return UserWalletManagerImpl(
|
||||
appStateHolder = appStateHolder,
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
walletFeatureToggles = walletFeatureToggles,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -44,11 +52,15 @@ class ProxyModule {
|
|||
appStateHolder: AppStateHolder,
|
||||
analytics: AnalyticsEventHandler,
|
||||
cardSdkConfigRepository: CardSdkConfigRepository,
|
||||
walletManagersFacade: WalletManagersFacade,
|
||||
walletFeatureToggles: WalletFeatureToggles,
|
||||
): TransactionManager {
|
||||
return TransactionManagerImpl(
|
||||
appStateHolder = appStateHolder,
|
||||
analytics = analytics,
|
||||
cardSdkConfigRepository = cardSdkConfigRepository,
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
walletFeatureToggles = walletFeatureToggles,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,13 +65,25 @@ internal class DefaultCurrenciesRepository(
|
|||
lazyMessage = { "Saved tokens empty. Can not perform add currencies action" },
|
||||
)
|
||||
|
||||
val filteredCurrencies = currencies.toMutableList()
|
||||
filteredCurrencies.filterNot { currency ->
|
||||
val blockchain = getBlockchain(networkId = currency.network.id)
|
||||
val networkId = blockchain.toNetworkId()
|
||||
val contractAddress = (currency as? CryptoCurrency.Token)?.contractAddress
|
||||
savedCurrencies.tokens.firstOrNull { token ->
|
||||
token.contractAddress == contractAddress &&
|
||||
token.networkId == networkId &&
|
||||
token.derivationPath == currency.network.derivationPath.value
|
||||
} != null
|
||||
}
|
||||
|
||||
val newCoins = createCoinsForNewTokens(
|
||||
userWalletId = userWalletId,
|
||||
newTokens = currencies.filterIsInstance<CryptoCurrency.Token>(),
|
||||
newTokens = filteredCurrencies.filterIsInstance<CryptoCurrency.Token>(),
|
||||
savedCurrencies = savedCurrencies.tokens,
|
||||
)
|
||||
|
||||
val newCurrencies = newCoins + currencies
|
||||
val newCurrencies = newCoins + filteredCurrencies
|
||||
|
||||
storeAndPushTokens(
|
||||
userWalletId = userWalletId,
|
||||
|
|
@ -276,7 +288,7 @@ internal class DefaultCurrenciesRepository(
|
|||
private suspend fun fetchUserMarketCoinsByIds(userWalletId: UserWalletId, userTokens: UserTokensResponse) {
|
||||
try {
|
||||
val networkIds = userTokens.tokens.joinToString(separator = ",") { it.networkId }
|
||||
val response = tangemTechApi.getCoins(networkIds)
|
||||
val response = tangemTechApi.getCoins(networkIds = networkIds)
|
||||
|
||||
userMarketCoinsStore.store(userWalletId, response)
|
||||
} catch (e: Throwable) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package com.tangem.data.tokens.repository
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.datasource.local.token.UserMarketCoinsStore
|
||||
import com.tangem.domain.common.extensions.toNetworkId
|
||||
import com.tangem.domain.tokens.models.CryptoCurrency
|
||||
import com.tangem.domain.tokens.repository.MarketCryptoCurrencyRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
|
@ -10,9 +12,11 @@ class DefaultMarketCryptoCurrencyRepository(
|
|||
) : MarketCryptoCurrencyRepository {
|
||||
|
||||
override suspend fun isExchangeable(userWalletId: UserWalletId, cryptoCurrencyId: CryptoCurrency.ID): Boolean {
|
||||
val blockchain = Blockchain.fromId(cryptoCurrencyId.rawNetworkId)
|
||||
val apiNetworkId = blockchain.toNetworkId()
|
||||
return userMarketCoinsStore.getSyncOrNull(userWalletId)?.coins
|
||||
?.firstOrNull { it.id == cryptoCurrencyId.rawCurrencyId }
|
||||
?.networks
|
||||
?.firstOrNull { it.networkId == cryptoCurrencyId.rawNetworkId }?.exchangeable ?: false
|
||||
?.firstOrNull { it.networkId == apiNetworkId }?.exchangeable ?: false
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,14 @@
|
|||
package com.tangem.domain.walletmanager.utils
|
||||
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.DerivationParams
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.common.WalletManagerFactory
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.datasource.config.ConfigManager
|
||||
import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation
|
||||
import com.tangem.domain.common.DerivationStyleProvider
|
||||
import com.tangem.domain.common.extensions.makeWalletManagerForApp
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
|
||||
internal class WalletManagerFactory(
|
||||
|
|
@ -23,7 +24,7 @@ internal class WalletManagerFactory(
|
|||
blockchain: Blockchain,
|
||||
derivationPath: DerivationPath?,
|
||||
): WalletManager? {
|
||||
val derivationParams = getDerivationParams(derivationPath, scanResponse.card)
|
||||
val derivationParams = getDerivationParams(derivationPath, scanResponse.derivationStyleProvider)
|
||||
|
||||
return sdkWalletManagerFactory.makeWalletManagerForApp(
|
||||
scanResponse = scanResponse,
|
||||
|
|
@ -32,12 +33,11 @@ internal class WalletManagerFactory(
|
|||
)
|
||||
}
|
||||
|
||||
private fun getDerivationParams(derivationPath: DerivationPath?, card: CardDTO): DerivationParams? {
|
||||
val derivationStyle = when {
|
||||
!card.settings.isHDWalletAllowed -> return null
|
||||
card.useOldStyleDerivation -> DerivationStyle.LEGACY
|
||||
else -> DerivationStyle.NEW
|
||||
}
|
||||
private fun getDerivationParams(
|
||||
derivationPath: DerivationPath?,
|
||||
derivationStyleProvider: DerivationStyleProvider,
|
||||
): DerivationParams? {
|
||||
val derivationStyle = derivationStyleProvider.getDerivationStyle() ?: return null
|
||||
|
||||
return if (derivationPath == null) {
|
||||
DerivationParams.Default(derivationStyle)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,18 @@ dependencies {
|
|||
/** Network */
|
||||
implementation(deps.retrofit)
|
||||
|
||||
/** Domain */
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.legacy)
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.domain.wallets.models)
|
||||
|
||||
/** Data */
|
||||
implementation(projects.data.tokens)
|
||||
|
||||
/** Tangem SDKs */
|
||||
implementation(deps.tangem.blockchain)
|
||||
|
||||
/** DI */
|
||||
implementation(deps.hilt.android)
|
||||
kapt(deps.hilt.kapt)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,18 @@
|
|||
package com.tangem.feature.swap
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.data.tokens.utils.CryptoCurrencyFactory
|
||||
import com.tangem.datasource.api.oneinch.OneInchApi
|
||||
import com.tangem.datasource.api.oneinch.OneInchApiFactory
|
||||
import com.tangem.datasource.api.oneinch.OneInchErrorsHandler
|
||||
import com.tangem.datasource.api.oneinch.errors.OneIncResponseException
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.config.ConfigManager
|
||||
import com.tangem.domain.common.extensions.fromNetworkId
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.tokens.models.CryptoCurrency
|
||||
import com.tangem.domain.tokens.models.Network
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.swap.converters.ApproveConverter
|
||||
import com.tangem.feature.swap.converters.QuotesConverter
|
||||
import com.tangem.feature.swap.converters.SwapConverter
|
||||
|
|
@ -20,6 +27,7 @@ import com.tangem.feature.swap.domain.models.mapErrors
|
|||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
import com.tangem.blockchain.common.Token as SdkToken
|
||||
|
||||
internal class SwapRepositoryImpl @Inject constructor(
|
||||
private val tangemTechApi: TangemTechApi,
|
||||
|
|
@ -152,6 +160,37 @@ internal class SwapRepositoryImpl @Inject constructor(
|
|||
return configManager.config.swapReferrerAccount?.fee?.toDoubleOrNull() ?: 0.0
|
||||
}
|
||||
|
||||
override suspend fun getCryptoCurrency(
|
||||
userWallet: UserWallet,
|
||||
currency: Currency,
|
||||
network: Network,
|
||||
): CryptoCurrency? {
|
||||
val blockchain = Blockchain.fromNetworkId(currency.networkId) ?: return null
|
||||
val cryptoCurrencyFactory = CryptoCurrencyFactory()
|
||||
return when (currency) {
|
||||
is Currency.NativeToken -> {
|
||||
cryptoCurrencyFactory.createCoin(
|
||||
blockchain = blockchain,
|
||||
extraDerivationPath = network.derivationPath.value,
|
||||
derivationStyleProvider = userWallet.scanResponse.derivationStyleProvider,
|
||||
)
|
||||
}
|
||||
is Currency.NonNativeToken -> {
|
||||
val sdkToken = SdkToken(
|
||||
symbol = currency.symbol,
|
||||
contractAddress = currency.contractAddress,
|
||||
decimals = currency.decimalCount,
|
||||
)
|
||||
cryptoCurrencyFactory.createToken(
|
||||
sdkToken = sdkToken,
|
||||
blockchain = blockchain,
|
||||
extraDerivationPath = network.derivationPath.value,
|
||||
derivationStyleProvider = userWallet.scanResponse.derivationStyleProvider,
|
||||
)
|
||||
}
|
||||
} as CryptoCurrency
|
||||
}
|
||||
|
||||
private fun getOneInchApi(networkId: String): OneInchApi {
|
||||
return oneInchApiFactory.getApi(networkId)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,38 @@
|
|||
plugins {
|
||||
alias(deps.plugins.kotlin.jvm)
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
alias(deps.plugins.kotlin.kapt)
|
||||
alias(deps.plugins.kotlin.serialization)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.tangem.domain.swap"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
/** Libs */
|
||||
implementation(project(":libs:crypto"))
|
||||
implementation(project(":core:utils"))
|
||||
implementation(projects.libs.crypto)
|
||||
|
||||
/** DI */
|
||||
implementation(deps.hilt.core)
|
||||
kapt(deps.hilt.kapt)
|
||||
|
||||
/** Domain */
|
||||
implementation(projects.domain.tokens)
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.wallets)
|
||||
implementation(projects.domain.wallets.models)
|
||||
|
||||
/** Core modules */
|
||||
implementation(projects.core.utils)
|
||||
|
||||
/** Feature Apis */
|
||||
implementation(projects.features.wallet.api)
|
||||
|
||||
/** Other Libraries **/
|
||||
implementation(deps.kotlin.serialization)
|
||||
implementation(deps.kotlin.coroutines)
|
||||
implementation(deps.arrow.core)
|
||||
implementation(deps.timber)
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.feature.swap.domain
|
||||
|
||||
import com.tangem.domain.tokens.models.Network
|
||||
import com.tangem.feature.swap.domain.models.SwapAmount
|
||||
import com.tangem.feature.swap.domain.models.domain.Currency
|
||||
import com.tangem.feature.swap.domain.models.domain.PermissionOptions
|
||||
|
|
@ -7,7 +8,7 @@ import com.tangem.feature.swap.domain.models.ui.*
|
|||
|
||||
interface SwapInteractor {
|
||||
|
||||
fun initDerivationPath(derivationPath: String?)
|
||||
fun initDerivationPathAndNetwork(derivationPath: String?, network: Network?)
|
||||
|
||||
/**
|
||||
* Init tokens to swap, load tokens list available to swap for given network
|
||||
|
|
|
|||
|
|
@ -1,37 +1,48 @@
|
|||
package com.tangem.feature.swap.domain
|
||||
|
||||
import com.tangem.domain.tokens.models.Network
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
|
||||
import com.tangem.feature.swap.domain.cache.SwapDataCache
|
||||
import com.tangem.feature.swap.domain.converters.CryptoCurrencyConverter
|
||||
import com.tangem.feature.swap.domain.converters.SwapCurrencyConverter
|
||||
import com.tangem.feature.swap.domain.models.DataError
|
||||
import com.tangem.feature.swap.domain.models.SwapAmount
|
||||
import com.tangem.feature.swap.domain.models.domain.*
|
||||
import com.tangem.feature.swap.domain.models.domain.Currency
|
||||
import com.tangem.feature.swap.domain.models.toStringWithRightOffset
|
||||
import com.tangem.feature.swap.domain.models.ui.*
|
||||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||
import com.tangem.lib.crypto.TransactionManager
|
||||
import com.tangem.lib.crypto.UserWalletManager
|
||||
import com.tangem.lib.crypto.models.*
|
||||
import com.tangem.lib.crypto.models.transactions.SendTxResult
|
||||
import com.tangem.utils.toFiatString
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("LargeClass")
|
||||
@Suppress("LargeClass", "LongParameterList")
|
||||
internal class SwapInteractorImpl @Inject constructor(
|
||||
private val transactionManager: TransactionManager,
|
||||
private val userWalletManager: UserWalletManager,
|
||||
private val repository: SwapRepository,
|
||||
private val cache: SwapDataCache,
|
||||
private val allowPermissionsHandler: AllowPermissionsHandler,
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val walletFeatureToggles: WalletFeatureToggles,
|
||||
private val getSelectedWalletUseCase: GetSelectedWalletUseCase,
|
||||
) : SwapInteractor {
|
||||
|
||||
private val cryptoCurrencyConverter = CryptoCurrencyConverter()
|
||||
private val swapCurrencyConverter = SwapCurrencyConverter()
|
||||
private val amountFormatter = AmountFormatter()
|
||||
private var derivationPath: String? = null
|
||||
private var network: Network? = null
|
||||
|
||||
override fun initDerivationPath(derivationPath: String?) {
|
||||
override fun initDerivationPathAndNetwork(derivationPath: String?, network: Network?) {
|
||||
this.derivationPath = derivationPath
|
||||
this.network = network
|
||||
}
|
||||
|
||||
override suspend fun initTokensToSwap(initialCurrency: Currency): TokensDataState {
|
||||
|
|
@ -55,7 +66,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
allLoadedTokens.firstOrNull { it.symbol == token.symbol }?.let {
|
||||
loadedOnWalletsMap.add(it.symbol)
|
||||
it
|
||||
} ?: cryptoCurrencyConverter.convertBack(token)
|
||||
} ?: swapCurrencyConverter.convertBack(token)
|
||||
}
|
||||
val loadedTokens = allLoadedTokens
|
||||
.filter {
|
||||
|
|
@ -195,7 +206,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
txData = SwapTxData(
|
||||
networkId = networkId,
|
||||
amountToSend = amount,
|
||||
currencyToSend = cryptoCurrencyConverter.convert(currencyToSend),
|
||||
currencyToSend = swapCurrencyConverter.convert(currencyToSend),
|
||||
feeAmount = fee.feeValue,
|
||||
gasLimit = fee.gasLimit,
|
||||
destinationAddress = swapStateData.swapModel.transaction.toWalletAddress,
|
||||
|
|
@ -210,8 +221,11 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
)
|
||||
return when (result) {
|
||||
is SendTxResult.Success -> {
|
||||
userWalletManager.addToken(cryptoCurrencyConverter.convert(currencyToGet), derivationPath)
|
||||
userWalletManager.refreshWallet()
|
||||
if (walletFeatureToggles.isRedesignedScreenEnabled) {
|
||||
onSuccessNewFlow(currencyToGet)
|
||||
} else {
|
||||
onSuccessLegacyFlow(currencyToGet)
|
||||
}
|
||||
TxState.TxSent(
|
||||
fromAmount = amountFormatter.formatSwapAmountToUI(
|
||||
swapStateData.swapModel.fromTokenAmount,
|
||||
|
|
@ -244,6 +258,32 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
return ONE_INCH_SUPPORTED_NETWORKS.contains(networkId)
|
||||
}
|
||||
|
||||
private suspend fun onSuccessLegacyFlow(currency: Currency) {
|
||||
userWalletManager.addToken(swapCurrencyConverter.convert(currency), derivationPath)
|
||||
userWalletManager.refreshWallet()
|
||||
}
|
||||
|
||||
private suspend fun onSuccessNewFlow(currency: Currency) {
|
||||
val network = network ?: return
|
||||
getSelectedWalletUseCase().fold(
|
||||
ifRight = { userWallet ->
|
||||
getAndAddCryptoCurrency(userWallet, currency, network)
|
||||
},
|
||||
ifLeft = {
|
||||
Timber.e("Swap Error on getSelectedWalletUseCase")
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun getAndAddCryptoCurrency(userWallet: UserWallet, currency: Currency, network: Network) {
|
||||
repository.getCryptoCurrency(userWallet, currency, network)?.let {
|
||||
currenciesRepository.addCurrencies(
|
||||
userWallet.walletId,
|
||||
listOf(it),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTangemFee(): Double {
|
||||
return repository.getTangemFee()
|
||||
}
|
||||
|
|
@ -409,7 +449,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
val feeData = transactionManager.getFee(
|
||||
networkId = networkId,
|
||||
amountToSend = amount.value,
|
||||
currencyToSend = cryptoCurrencyConverter.convert(fromToken),
|
||||
currencyToSend = swapCurrencyConverter.convert(fromToken),
|
||||
destinationAddress = swapData.transaction.toWalletAddress,
|
||||
increaseBy = INCREASE_GAS_LIMIT_BY,
|
||||
data = swapData.transaction.data,
|
||||
|
|
@ -562,7 +602,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
val tokensBalance =
|
||||
userWalletManager.getCurrentWalletTokensBalance(
|
||||
networkId = networkId,
|
||||
extraTokens = tokensToSync.map { cryptoCurrencyConverter.convert(it) },
|
||||
extraTokens = tokensToSync.map { swapCurrencyConverter.convert(it) },
|
||||
derivationPath = derivationPath,
|
||||
)
|
||||
cache.cacheBalances(
|
||||
|
|
@ -623,7 +663,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getWalletAddress(networkId: String): String {
|
||||
private suspend fun getWalletAddress(networkId: String): String {
|
||||
return userWalletManager.getWalletAddress(networkId, derivationPath)
|
||||
}
|
||||
|
||||
|
|
@ -638,7 +678,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun checkFeeIsEnough(
|
||||
private suspend fun checkFeeIsEnough(
|
||||
fee: BigDecimal?,
|
||||
spendAmount: SwapAmount,
|
||||
networkId: String,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
package com.tangem.feature.swap.domain
|
||||
|
||||
import com.tangem.domain.tokens.models.CryptoCurrency
|
||||
import com.tangem.domain.tokens.models.Network
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.swap.domain.models.data.AggregatedSwapDataModel
|
||||
import com.tangem.feature.swap.domain.models.domain.ApproveModel
|
||||
import com.tangem.feature.swap.domain.models.domain.Currency
|
||||
|
|
@ -63,4 +66,6 @@ interface SwapRepository {
|
|||
* Example: 0.35%
|
||||
*/
|
||||
fun getTangemFee(): Double
|
||||
|
||||
suspend fun getCryptoCurrency(userWallet: UserWallet, currency: Currency, network: Network): CryptoCurrency?
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ import com.tangem.feature.swap.domain.models.domain.Currency
|
|||
import com.tangem.utils.converter.TwoWayConverter
|
||||
import com.tangem.lib.crypto.models.Currency as CryptoCurrency
|
||||
|
||||
class CryptoCurrencyConverter : TwoWayConverter<Currency, CryptoCurrency> {
|
||||
class SwapCurrencyConverter : TwoWayConverter<Currency, CryptoCurrency> {
|
||||
|
||||
override fun convert(value: Currency): CryptoCurrency {
|
||||
return when (value) {
|
||||
|
|
@ -1,18 +1,18 @@
|
|||
package com.tangem.feature.swap.domain.di
|
||||
|
||||
import com.tangem.feature.swap.domain.AllowPermissionsHandlerImpl
|
||||
import com.tangem.feature.swap.domain.BlockchainInteractor
|
||||
import com.tangem.feature.swap.domain.BlockchainInteractorImpl
|
||||
import com.tangem.feature.swap.domain.SwapInteractor
|
||||
import com.tangem.feature.swap.domain.SwapInteractorImpl
|
||||
import com.tangem.feature.swap.domain.SwapRepository
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.wallets.legacy.WalletsStateHolder
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
|
||||
import com.tangem.feature.swap.domain.*
|
||||
import com.tangem.feature.swap.domain.cache.SwapDataCacheImpl
|
||||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||
import com.tangem.lib.crypto.TransactionManager
|
||||
import com.tangem.lib.crypto.UserWalletManager
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Qualifier
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
|
|
@ -25,6 +25,9 @@ class SwapDomainModule {
|
|||
swapRepository: SwapRepository,
|
||||
userWalletManager: UserWalletManager,
|
||||
transactionManager: TransactionManager,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
walletFeatureToggles: WalletFeatureToggles,
|
||||
@SwapScope getSelectedWalletUseCase: GetSelectedWalletUseCase,
|
||||
): SwapInteractor {
|
||||
return SwapInteractorImpl(
|
||||
transactionManager = transactionManager,
|
||||
|
|
@ -32,6 +35,9 @@ class SwapDomainModule {
|
|||
repository = swapRepository,
|
||||
cache = SwapDataCacheImpl(),
|
||||
allowPermissionsHandler = AllowPermissionsHandlerImpl(),
|
||||
currenciesRepository = currenciesRepository,
|
||||
walletFeatureToggles = walletFeatureToggles,
|
||||
getSelectedWalletUseCase = getSelectedWalletUseCase,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -42,4 +48,15 @@ class SwapDomainModule {
|
|||
transactionManager = transactionManager,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@SwapScope
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesGetSelectedWalletUseCase(walletsStateHolder: WalletsStateHolder): GetSelectedWalletUseCase {
|
||||
return GetSelectedWalletUseCase(walletsStateHolder = walletsStateHolder)
|
||||
}
|
||||
}
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class SwapScope
|
||||
|
|
@ -38,6 +38,7 @@ dependencies {
|
|||
|
||||
/** Domain */
|
||||
implementation(projects.features.swap.domain)
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.settings)
|
||||
|
||||
/** Other libraries */
|
||||
|
|
|
|||
|
|
@ -83,5 +83,6 @@ class SwapFragment : Fragment() {
|
|||
companion object {
|
||||
const val CURRENCY_BUNDLE_KEY = "swap_currency"
|
||||
const val DERIVATION_PATH = "DERIVATION_STYLE"
|
||||
const val NETWORK = "NETWORK"
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
|
|||
import com.tangem.core.ui.utils.InputNumberFormatter
|
||||
import com.tangem.domain.balancehiding.IsBalanceHiddenUseCase
|
||||
import com.tangem.domain.balancehiding.ListenToFlipsUseCase
|
||||
import com.tangem.domain.tokens.models.Network
|
||||
import com.tangem.feature.swap.analytics.SwapEvents
|
||||
import com.tangem.feature.swap.domain.BlockchainInteractor
|
||||
import com.tangem.feature.swap.domain.SwapInteractor
|
||||
|
|
@ -16,10 +17,7 @@ import com.tangem.feature.swap.domain.models.domain.Currency
|
|||
import com.tangem.feature.swap.domain.models.domain.PermissionOptions
|
||||
import com.tangem.feature.swap.domain.models.formatToUIRepresentation
|
||||
import com.tangem.feature.swap.domain.models.ui.*
|
||||
import com.tangem.feature.swap.models.SwapPermissionState
|
||||
import com.tangem.feature.swap.models.SwapStateHolder
|
||||
import com.tangem.feature.swap.models.UiActions
|
||||
import com.tangem.feature.swap.models.toDomainApproveType
|
||||
import com.tangem.feature.swap.models.*
|
||||
import com.tangem.feature.swap.presentation.SwapFragment
|
||||
import com.tangem.feature.swap.router.SwapNavScreen
|
||||
import com.tangem.feature.swap.router.SwapRouter
|
||||
|
|
@ -56,6 +54,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
?: error("no expected parameter Currency found"),
|
||||
)
|
||||
private val derivationPath = savedStateHandle.get<String>(SwapFragment.DERIVATION_PATH)
|
||||
private val network = savedStateHandle.get<Network>(SwapFragment.NETWORK)
|
||||
|
||||
private var isBalanceHidden = true
|
||||
|
||||
|
|
@ -87,7 +86,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
get() = swapRouter.currentScreen
|
||||
|
||||
init {
|
||||
swapInteractor.initDerivationPath(derivationPath)
|
||||
swapInteractor.initDerivationPathAndNetwork(derivationPath, network)
|
||||
initTokens(currency)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -523,7 +523,7 @@ internal class WalletViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onSwapClick(cryptoCurrencyStatus: CryptoCurrencyStatus) {
|
||||
// todo implement onSwapClick [REDACTED_JIRA]
|
||||
reduxStateHolder.dispatch(TradeCryptoAction.New.Swap(cryptoCurrencyStatus.currency))
|
||||
}
|
||||
|
||||
override fun onSingleCurrencySendClick(cryptoCurrencyStatus: CryptoCurrencyStatus?) {
|
||||
|
|
@ -698,8 +698,7 @@ internal class WalletViewModel @Inject constructor(
|
|||
val state = uiState as? WalletState.ContentState ?: return
|
||||
val userWallet = getWallet(state.walletsListConfig.selectedWalletIndex)
|
||||
viewModelScope.launch(dispatchers.io) {
|
||||
getCryptoCurrencyActionsUseCase
|
||||
.invoke(userWallet.walletId, cryptoCurrencyStatus)
|
||||
getCryptoCurrencyActionsUseCase(userWallet.walletId, cryptoCurrencyStatus)
|
||||
.take(count = 1)
|
||||
.collectLatest {
|
||||
uiState = stateFactory.getStateWithTokenActionBottomSheet(it)
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ interface UserWalletManager {
|
|||
* @param derivationPath if null uses default
|
||||
*/
|
||||
@Throws(IllegalStateException::class)
|
||||
fun getWalletAddress(networkId: String, derivationPath: String?): String
|
||||
suspend fun getWalletAddress(networkId: String, derivationPath: String?): String
|
||||
|
||||
/**
|
||||
* Return balances from wallet found by networkId
|
||||
|
|
@ -69,7 +69,7 @@ interface UserWalletManager {
|
|||
): Map<String, ProxyAmount>
|
||||
|
||||
@Throws(IllegalStateException::class)
|
||||
fun getNativeTokenBalance(networkId: String, derivationPath: String?): ProxyAmount?
|
||||
suspend fun getNativeTokenBalance(networkId: String, derivationPath: String?): ProxyAmount?
|
||||
|
||||
/**
|
||||
* @param networkId
|
||||
|
|
@ -84,5 +84,5 @@ interface UserWalletManager {
|
|||
fun getUserAppCurrency(): ProxyFiatCurrency
|
||||
|
||||
@Throws(IllegalStateException::class)
|
||||
fun getLastTransactionHash(networkId: String, derivationPath: String?): String?
|
||||
suspend fun getLastTransactionHash(networkId: String, derivationPath: String?): String?
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue