From ebcf2f40e5cc332ee95d4c1afa5e33e6ac50d879 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 18 Nov 2022 18:06:25 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../{CardStateHolder.kt => AppStateHolder.kt} | 4 +- .../tangem/tap/proxy/DerivationManagerImpl.kt | 44 +++++-- .../tangem/tap/proxy/UserWalletManagerImpl.kt | 123 ++++++++++++++---- core/datasource/build.gradle.kts | 1 - .../referral/domain/ReferralInteractorImpl.kt | 26 ++-- .../domain/converter/TokensConverter.kt | 35 +++-- .../referral/domain/models/ReferralData.kt | 2 +- .../tangem/lib/crypto/DerivationManager.kt | 12 +- .../tangem/lib/crypto/UserWalletManager.kt | 16 +-- .../com/tangem/lib/crypto/models/Currency.kt | 12 ++ .../tangem/lib/crypto/models/NativeToken.kt | 8 ++ .../lib/crypto/models/NonNativeToken.kt | 10 ++ .../com/tangem/lib/crypto/models/Token.kt | 10 -- 13 files changed, 222 insertions(+), 81 deletions(-) rename app/src/main/java/com/tangem/tap/proxy/{CardStateHolder.kt => AppStateHolder.kt} (65%) create mode 100644 libs/crypto/src/main/java/com/tangem/lib/crypto/models/Currency.kt create mode 100644 libs/crypto/src/main/java/com/tangem/lib/crypto/models/NativeToken.kt create mode 100644 libs/crypto/src/main/java/com/tangem/lib/crypto/models/NonNativeToken.kt delete mode 100644 libs/crypto/src/main/java/com/tangem/lib/crypto/models/Token.kt diff --git a/app/src/main/java/com/tangem/tap/proxy/CardStateHolder.kt b/app/src/main/java/com/tangem/tap/proxy/AppStateHolder.kt similarity index 65% rename from app/src/main/java/com/tangem/tap/proxy/CardStateHolder.kt rename to app/src/main/java/com/tangem/tap/proxy/AppStateHolder.kt index 2729f1fc99..130dd64665 100644 --- a/app/src/main/java/com/tangem/tap/proxy/CardStateHolder.kt +++ b/app/src/main/java/com/tangem/tap/proxy/AppStateHolder.kt @@ -2,10 +2,12 @@ package com.tangem.tap.proxy import com.tangem.common.card.Card import com.tangem.domain.common.ScanResponse +import com.tangem.tap.features.wallet.redux.WalletState -class CardStateHolder { +class AppStateHolder { val scanResponse: ScanResponse? = null + val walletState: WalletState? = null fun getActualCard(): Card? { return scanResponse?.card diff --git a/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt b/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt index e3aca88845..dd6d2a6e1c 100644 --- a/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt +++ b/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt @@ -1,31 +1,55 @@ package com.tangem.tap.proxy import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.Token import com.tangem.domain.common.TapWorkarounds.derivationStyle import com.tangem.domain.common.extensions.fromNetworkId import com.tangem.lib.crypto.DerivationManager +import com.tangem.lib.crypto.models.Currency +import com.tangem.lib.crypto.models.NonNativeToken +import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.tokens.redux.TokensMiddleware +import kotlin.coroutines.suspendCoroutine class DerivationManagerImpl( - val tokesMiddleware: TokensMiddleware, - val cardStateHolder: CardStateHolder, + private val tokesMiddleware: TokensMiddleware, + private val appStateHolder: AppStateHolder, ) : DerivationManager { - override suspend fun deriveMissingBlockchains(networkId: String) { - if (cardStateHolder.scanResponse != null) { //todo how to get Currency list from token - tokesMiddleware.deriveMissingBlockchains( - cardStateHolder.scanResponse, emptyList(), - ) { - + override suspend fun deriveMissingBlockchains(currency: Currency) = suspendCoroutine { continuation -> + val blockchain = Blockchain.fromNetworkId(currency.networkId) + val card = appStateHolder.getActualCard() + if (blockchain != null && card != null) { + val appToken = if (currency is NonNativeToken) { + Token( + symbol = currency.symbol, + contractAddress = currency.contractAddress, + decimals = currency.decimalCount, + ) + } else null + val blockchainNetwork = BlockchainNetwork(blockchain, card) + val appCurrency = com.tangem.tap.features.wallet.models.Currency.fromBlockchainNetwork( + blockchainNetwork, + appToken, + ) + if (appStateHolder.scanResponse != null) { + tokesMiddleware.deriveMissingBlockchains( + scanResponse = appStateHolder.scanResponse, + listOf(appCurrency), + ) { + continuation.resumeWith(Result.success(true)) + } } + } else { + continuation.resumeWith(Result.failure(IllegalStateException("no blockchain or card found"))) } } override fun hasDerivation(networkId: String): Boolean { - val scanResponse = cardStateHolder.scanResponse + val scanResponse = appStateHolder.scanResponse val blockchain = Blockchain.fromNetworkId(networkId) if (scanResponse != null && blockchain != null) { - val derivationPath = blockchain.derivationPath(cardStateHolder.getActualCard()?.derivationStyle)?.rawPath + val derivationPath = blockchain.derivationPath(appStateHolder.getActualCard()?.derivationStyle)?.rawPath if (derivationPath.isNullOrEmpty()) return false return scanResponse.hasDerivation( blockchain, diff --git a/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt b/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt index d8e04f93c9..cac76b8ab3 100644 --- a/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt +++ b/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt @@ -1,68 +1,140 @@ package com.tangem.tap.proxy import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.DerivationParams +import com.tangem.blockchain.common.DerivationStyle +import com.tangem.blockchain.common.WalletManagerFactory +import com.tangem.common.card.Card +import com.tangem.domain.common.TapWorkarounds.derivationStyle import com.tangem.domain.common.extensions.fromNetworkId import com.tangem.domain.common.extensions.toNetworkId import com.tangem.lib.crypto.UserWalletManager -import com.tangem.lib.crypto.models.Token +import com.tangem.lib.crypto.models.Currency +import com.tangem.lib.crypto.models.NativeToken +import com.tangem.lib.crypto.models.NonNativeToken import com.tangem.tap.common.redux.AppState import com.tangem.tap.domain.extensions.getUserWalletId +import com.tangem.tap.domain.extensions.makeWalletManagerForApp import com.tangem.tap.domain.tokens.UserTokensRepository import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.wallet.redux.WalletAction +import org.rekotlin.Action import org.rekotlin.Store class UserWalletManagerImpl( private val userTokensRepository: UserTokensRepository, - private val cardStateHolder: CardStateHolder, + private val appStateHolder: AppStateHolder, private val mainStore: Store, + private val walletManagerFactory: WalletManagerFactory, ) : UserWalletManager { - override suspend fun getUserTokens(): List { - val card = cardStateHolder.getActualCard() + override suspend fun getUserTokens(): List { + val card = appStateHolder.getActualCard() if (card != null) { userTokensRepository.getUserTokens(card) .filter { it.isToken() } .map { - Token( - id = it.coinId ?: "", - name = it.currencyName, - symbol = it.currencySymbol, - networkId = it.blockchain.toNetworkId(), - contractAddress = null, - decimalCount = it.decimals, - ) + if (it is com.tangem.tap.features.wallet.models.Currency.Token) { + NonNativeToken( + id = it.coinId ?: "", + name = it.currencyName, + symbol = it.currencySymbol, + networkId = it.blockchain.toNetworkId(), + contractAddress = it.token.contractAddress, + decimalCount = it.token.decimals, + ) + } else { + NativeToken( + id = it.coinId ?: "", + name = it.currencyName, + symbol = it.currencySymbol, + networkId = it.blockchain.toNetworkId(), + ) + } } } return emptyList() } override fun getWalletId(): String { - return cardStateHolder.getActualCard()?.getUserWalletId() ?: "" + return appStateHolder.getActualCard()?.getUserWalletId() ?: "" } - override suspend fun isTokenAdded(token: Token): Boolean { - val card = cardStateHolder.getActualCard() + override suspend fun isTokenAdded(currency: Currency): Boolean { + val card = appStateHolder.getActualCard() if (card != null) { return userTokensRepository.getUserTokens(card) - .any { it.coinId.equals(token.id) } //todo ensure that its the same ids + .any { it.coinId.equals(currency.id) } //todo ensure that its the same ids } return false } //todo check is it sync operation - override fun addToken(token: Token) { - val card = cardStateHolder.getActualCard() + override fun addToken(currency: Currency) { + val action = if (currency is NativeToken) { + val card = appStateHolder.getActualCard() + if (card != null) { + addNativeTokenToWalletAction(currency, card) + } else { + throw IllegalStateException("card not found") + } + } else { + addNonNativeTokenToWalletAction(currency as NonNativeToken) + } + + mainStore.dispatch(action) + } + + override fun getWalletAddress(currency: Currency): String { + val blockchain = Blockchain.fromNetworkId(currency.networkId) + val card = appStateHolder.getActualCard() + if (blockchain != null && card != null) { + val blockchainNetwork = BlockchainNetwork(blockchain, card) + val walletManager = appStateHolder.walletState?.getWalletManager(blockchainNetwork) + if (walletManager != null) { + return walletManager.wallet.address + } else { + throw IllegalStateException("no wallet manager found") + } + } else { + throw IllegalStateException("no blockchain or card found") + } + } + + private fun addNativeTokenToWalletAction(token: NativeToken, card: Card): Action { + val blockchain = Blockchain.fromNetworkId(token.networkId) + val scanResponse = appStateHolder.scanResponse + if (blockchain != null && scanResponse != null) { + val blockchainNetwork = BlockchainNetwork(blockchain, card) + var walletManager = appStateHolder.walletState?.getWalletManager(blockchainNetwork) + if (walletManager == null) { + walletManager = walletManagerFactory.makeWalletManagerForApp( + scanResponse = scanResponse, + blockchain = blockchain, + derivationParams = createDerivationParams(card.derivationStyle), + ) + } + return WalletAction.MultiWallet.AddBlockchain( + blockchain = blockchainNetwork, + walletManager = walletManager, + save = true, + ) + } else { + throw IllegalStateException("blockchain is not supported") + } + } + + private fun addNonNativeTokenToWalletAction(token: NonNativeToken): Action { + val card = appStateHolder.getActualCard() val blockchain = Blockchain.fromNetworkId(token.networkId) if (card != null && blockchain != null) { - val addAction = WalletAction.MultiWallet.AddToken( + return WalletAction.MultiWallet.AddToken( token = com.tangem.blockchain.common.Token( id = token.id, name = token.name, symbol = token.symbol, - contractAddress = token.contractAddress - ?: "", //todo clarify where to find that if data from back null - decimals = token.decimalCount ?: 0, //todo clarify where to find that if data from back null + contractAddress = token.contractAddress, + decimals = token.decimalCount, ), blockchain = BlockchainNetwork( blockchain, @@ -70,11 +142,12 @@ class UserWalletManagerImpl( ), save = true, ) - mainStore.dispatch(addAction) + } else { + throw IllegalStateException("no card or blockchain found") } } - override fun getWalletAddress(token: Token): String { - return "" + private fun createDerivationParams(derivationStyle: DerivationStyle?): DerivationParams? { + return derivationStyle?.let { DerivationParams.Default(derivationStyle) } //todo clarify if its need to add Custom } } \ No newline at end of file diff --git a/core/datasource/build.gradle.kts b/core/datasource/build.gradle.kts index c85c0841b9..7d8f651682 100644 --- a/core/datasource/build.gradle.kts +++ b/core/datasource/build.gradle.kts @@ -6,7 +6,6 @@ plugins { } android { - defaultConfig { compileSdk = AppConfig.compileSdkVersion minSdk = AppConfig.minSdkVersion diff --git a/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralInteractorImpl.kt b/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralInteractorImpl.kt index 69695dd1b8..8b2716f539 100644 --- a/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralInteractorImpl.kt +++ b/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralInteractorImpl.kt @@ -1,11 +1,11 @@ package com.tangem.feature.referral.domain -import com.tangem.lib.crypto.DerivationManager -import com.tangem.lib.crypto.UserWalletManager -import com.tangem.lib.crypto.models.Token import com.tangem.feature.referral.domain.converter.TokensConverter import com.tangem.feature.referral.domain.models.ReferralData import com.tangem.feature.referral.domain.models.TokenData +import com.tangem.lib.crypto.DerivationManager +import com.tangem.lib.crypto.UserWalletManager +import com.tangem.lib.crypto.models.Currency internal class ReferralInteractorImpl( private val repository: ReferralRepository, @@ -24,13 +24,13 @@ internal class ReferralInteractorImpl( override suspend fun startReferral(): ReferralData { if (tokensForReferral.isNotEmpty()) { - val token = tokensConverter.convert(tokensForReferral.first()) - deriveOrAddTokens(token) - val publicAddress = userWalletManager.getWalletAddress(token) + val currency = tokensConverter.convert(tokensForReferral.first()) + deriveOrAddTokens(currency) + val publicAddress = userWalletManager.getWalletAddress(currency) return repository.startReferral( walletId = userWalletManager.getWalletId(), - networkId = token.networkId ?: "", - tokenId = token.id, + networkId = currency.networkId, + tokenId = currency.id, address = publicAddress, ) } else { @@ -38,12 +38,12 @@ internal class ReferralInteractorImpl( } } - private fun deriveOrAddTokens(token: Token) { - if (!derivationManager.hasDerivation()) { - derivationManager.deriveMissingBlockchains(token.networkId) + private suspend fun deriveOrAddTokens(currency: Currency) { + if (!derivationManager.hasDerivation(currency.networkId)) { + derivationManager.deriveMissingBlockchains(currency) } - if (!userWalletManager.isTokenAdded(token)) { - userWalletManager.addToken(token) + if (!userWalletManager.isTokenAdded(currency)) { + userWalletManager.addToken(currency) } } diff --git a/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/converter/TokensConverter.kt b/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/converter/TokensConverter.kt index 5a98e0f2a0..4ee8e69395 100644 --- a/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/converter/TokensConverter.kt +++ b/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/converter/TokensConverter.kt @@ -1,19 +1,32 @@ package com.tangem.feature.referral.domain.converter -import com.tangem.lib.crypto.models.Token import com.tangem.feature.referral.domain.models.TokenData +import com.tangem.lib.crypto.models.Currency +import com.tangem.lib.crypto.models.NativeToken +import com.tangem.lib.crypto.models.NonNativeToken import com.tangem.utils.converter.Converter -class TokensConverter : Converter { +class TokensConverter : Converter { - override fun convert(value: TokenData): Token { - return Token( - id = value.id, - name = value.name, - symbol = value.symbol, - networkId = value.networkId, - contractAddress = value.contractAddress, - decimalCount = value.decimalCount, - ) + override fun convert(value: TokenData): Currency { + return if (value.decimalCount != null && + value.contractAddress != null + ) { + NonNativeToken( + id = value.id, + name = value.name, + symbol = value.symbol, + networkId = value.networkId, + contractAddress = value.contractAddress, + decimalCount = value.decimalCount, + ) + } else { + NativeToken( + id = value.id, + name = value.name, + symbol = value.symbol, + networkId = value.networkId, + ) + } } } \ No newline at end of file diff --git a/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/models/ReferralData.kt b/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/models/ReferralData.kt index 79216aec7d..f5cc061cb0 100644 --- a/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/models/ReferralData.kt +++ b/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/models/ReferralData.kt @@ -34,7 +34,7 @@ data class TokenData( val id: String, val name: String, val symbol: String, - val networkId: String?, + val networkId: String, val contractAddress: String?, val decimalCount: Int?, ) diff --git a/libs/crypto/src/main/java/com/tangem/lib/crypto/DerivationManager.kt b/libs/crypto/src/main/java/com/tangem/lib/crypto/DerivationManager.kt index ed5f1ffe3f..b9b2cfecea 100644 --- a/libs/crypto/src/main/java/com/tangem/lib/crypto/DerivationManager.kt +++ b/libs/crypto/src/main/java/com/tangem/lib/crypto/DerivationManager.kt @@ -1,8 +1,18 @@ package com.tangem.lib.crypto +import com.tangem.lib.crypto.models.Currency + interface DerivationManager { - suspend fun deriveMissingBlockchains(networkId: String) + /** + * Derives missing blockchain and returns flag true if did it successfully + * + * @param currency to derive (Native token or not) + */ + suspend fun deriveMissingBlockchains(currency: Currency): Boolean + /** + * Checks that given [networkId] has derivations + */ fun hasDerivation(networkId: String): Boolean } \ No newline at end of file diff --git a/libs/crypto/src/main/java/com/tangem/lib/crypto/UserWalletManager.kt b/libs/crypto/src/main/java/com/tangem/lib/crypto/UserWalletManager.kt index 0ea6a506d3..6df9887170 100644 --- a/libs/crypto/src/main/java/com/tangem/lib/crypto/UserWalletManager.kt +++ b/libs/crypto/src/main/java/com/tangem/lib/crypto/UserWalletManager.kt @@ -1,6 +1,6 @@ package com.tangem.lib.crypto -import com.tangem.lib.crypto.models.Token +import com.tangem.lib.crypto.models.Currency /** * Provider for user tokens data @@ -10,7 +10,7 @@ interface UserWalletManager { /** * Returns all user tokens (merged from local and backend) */ - suspend fun getUserTokens(): List + suspend fun getUserTokens(): List /** * Returns user walletId @@ -20,21 +20,21 @@ interface UserWalletManager { /** * Checks that token added to user wallet * - * @param token to receive referral payments + * @param currency to receive referral payments */ - suspend fun isTokenAdded(token: Token): Boolean + suspend fun isTokenAdded(currency: Currency): Boolean /** * Adds token to wallet if its not * - * @param token to add to wallet + * @param currency to add to wallet */ - fun addToken(token: Token) + fun addToken(currency: Currency) /** * Returns wallet public address for token * - * @param token for which find address + * @param currency for which find address */ - fun getWalletAddress(token: Token): String + fun getWalletAddress(currency: Currency): String } \ No newline at end of file diff --git a/libs/crypto/src/main/java/com/tangem/lib/crypto/models/Currency.kt b/libs/crypto/src/main/java/com/tangem/lib/crypto/models/Currency.kt new file mode 100644 index 0000000000..82afac8e25 --- /dev/null +++ b/libs/crypto/src/main/java/com/tangem/lib/crypto/models/Currency.kt @@ -0,0 +1,12 @@ +package com.tangem.lib.crypto.models + +/** + * Currency data class that can be native blockchain Token + * or custom Token (used in this lib to replace and divide logic Currency from app module) + */ +abstract class Currency( + open val id: String, + open val name: String, + open val symbol: String, + open val networkId: String, +) \ No newline at end of file diff --git a/libs/crypto/src/main/java/com/tangem/lib/crypto/models/NativeToken.kt b/libs/crypto/src/main/java/com/tangem/lib/crypto/models/NativeToken.kt new file mode 100644 index 0000000000..f8ab7464d6 --- /dev/null +++ b/libs/crypto/src/main/java/com/tangem/lib/crypto/models/NativeToken.kt @@ -0,0 +1,8 @@ +package com.tangem.lib.crypto.models + +data class NativeToken( + override val id: String, + override val name: String, + override val symbol: String, + override val networkId: String, +) : Currency(id, name, symbol, networkId) \ No newline at end of file diff --git a/libs/crypto/src/main/java/com/tangem/lib/crypto/models/NonNativeToken.kt b/libs/crypto/src/main/java/com/tangem/lib/crypto/models/NonNativeToken.kt new file mode 100644 index 0000000000..a2d812cd1b --- /dev/null +++ b/libs/crypto/src/main/java/com/tangem/lib/crypto/models/NonNativeToken.kt @@ -0,0 +1,10 @@ +package com.tangem.lib.crypto.models + +class NonNativeToken( + override val id: String, + override val name: String, + override val symbol: String, + override val networkId: String, + val contractAddress: String, + val decimalCount: Int, +) : Currency(id, name, symbol, networkId) \ No newline at end of file diff --git a/libs/crypto/src/main/java/com/tangem/lib/crypto/models/Token.kt b/libs/crypto/src/main/java/com/tangem/lib/crypto/models/Token.kt deleted file mode 100644 index eb9593843e..0000000000 --- a/libs/crypto/src/main/java/com/tangem/lib/crypto/models/Token.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.tangem.lib.crypto.models - -data class Token( - val id: String, - val name: String, - val symbol: String, - val networkId: String, - val contractAddress: String?, - val decimalCount: Int?, -) \ No newline at end of file