diff --git a/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt b/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt index d28fb50cbc..f39b16e9d7 100644 --- a/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt +++ b/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt @@ -2,7 +2,7 @@ package com.tangem.tap import com.tangem.TangemSdkLogger import com.tangem.blockchainsdk.BlockchainSDKFactory -import com.tangem.blockchainsdk.signer.TransactionSignerFactory +import com.tangem.data.card.TransactionSignerFactory import com.tangem.blockchainsdk.utils.ExcludedBlockchains import com.tangem.common.routing.AppRouter import com.tangem.core.analytics.filter.OneTimeEventFilter diff --git a/app/src/main/java/com/tangem/tap/TangemApplication.kt b/app/src/main/java/com/tangem/tap/TangemApplication.kt index c8408c6e91..e8323470e3 100644 --- a/app/src/main/java/com/tangem/tap/TangemApplication.kt +++ b/app/src/main/java/com/tangem/tap/TangemApplication.kt @@ -8,7 +8,7 @@ import com.tangem.Log import com.tangem.TangemSdkLogger import com.tangem.blockchain.network.BlockchainSdkRetrofitBuilder import com.tangem.blockchainsdk.BlockchainSDKFactory -import com.tangem.blockchainsdk.signer.TransactionSignerFactory +import com.tangem.data.card.TransactionSignerFactory import com.tangem.blockchainsdk.utils.ExcludedBlockchains import com.tangem.common.routing.AppRouter import com.tangem.core.analytics.Analytics diff --git a/app/src/main/java/com/tangem/tap/common/libs/blockchainsdk/DefaultTransactionSignerFactory.kt b/app/src/main/java/com/tangem/tap/common/libs/blockchainsdk/DefaultTransactionSignerFactory.kt index edd0ded835..e31c519069 100644 --- a/app/src/main/java/com/tangem/tap/common/libs/blockchainsdk/DefaultTransactionSignerFactory.kt +++ b/app/src/main/java/com/tangem/tap/common/libs/blockchainsdk/DefaultTransactionSignerFactory.kt @@ -3,18 +3,20 @@ package com.tangem.tap.common.libs.blockchainsdk import com.tangem.Message import com.tangem.TangemSdk import com.tangem.blockchain.common.TransactionSigner -import com.tangem.blockchainsdk.signer.TransactionSignerFactory +import com.tangem.data.card.TransactionSignerFactory +import com.tangem.domain.card.models.TwinKey import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.TangemSigner import com.tangem.tap.store internal class DefaultTransactionSignerFactory : TransactionSignerFactory { - override fun createTransactionSigner(cardId: String?, sdk: TangemSdk): TransactionSigner { + override fun createTransactionSigner(cardId: String?, sdk: TangemSdk, twinKey: TwinKey?): TransactionSigner { return TangemSigner( cardId = cardId, tangemSdk = sdk, initialMessage = Message(), + twinKey = twinKey, ) { signResponse -> store.dispatch(action = GlobalAction.IsSignWithRing(signResponse.isRing)) } diff --git a/app/src/main/java/com/tangem/tap/di/libs/blockchainsdk/TransactionSignerFactoryModule.kt b/app/src/main/java/com/tangem/tap/di/libs/blockchainsdk/TransactionSignerFactoryModule.kt index 36bc5ce13a..d0997c9038 100644 --- a/app/src/main/java/com/tangem/tap/di/libs/blockchainsdk/TransactionSignerFactoryModule.kt +++ b/app/src/main/java/com/tangem/tap/di/libs/blockchainsdk/TransactionSignerFactoryModule.kt @@ -1,6 +1,6 @@ package com.tangem.tap.di.libs.blockchainsdk -import com.tangem.blockchainsdk.signer.TransactionSignerFactory +import com.tangem.data.card.TransactionSignerFactory import com.tangem.tap.common.libs.blockchainsdk.DefaultTransactionSignerFactory import dagger.Module import dagger.Provides diff --git a/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt b/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt index f53d9d0736..7f5f095079 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt @@ -5,6 +5,7 @@ import com.tangem.TangemSdk import com.tangem.blockchain.common.TransactionSigner import com.tangem.blockchain.common.Wallet import com.tangem.common.CompletionResult +import com.tangem.domain.card.models.TwinKey import com.tangem.domain.models.scan.isRing import com.tangem.tap.domain.tasks.SignHashesTask import kotlinx.coroutines.suspendCancellableCoroutine @@ -14,6 +15,7 @@ class TangemSigner( private val cardId: String?, private val tangemSdk: TangemSdk, private val initialMessage: Message, + private val twinKey: TwinKey?, private val signerCallback: (TangemSignerResponse) -> Unit, ) : TransactionSigner { @@ -22,7 +24,7 @@ class TangemSigner( publicKey: Wallet.PublicKey, ): CompletionResult> { return suspendCancellableCoroutine { continuation -> - val task = SignHashesTask(hashes, publicKey) + val task = SignHashesTask(hashes, publicKey, twinKey?.getPairKey(publicKey.seedKey)) tangemSdk.startSessionWithRunnable( runnable = task, diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/SignHashesTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/SignHashesTask.kt index e5616aacd7..8d637b7c78 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/SignHashesTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/SignHashesTask.kt @@ -5,6 +5,8 @@ import com.tangem.common.CompletionResult import com.tangem.common.core.CardSession import com.tangem.common.core.CardSessionRunnable import com.tangem.common.core.CompletionCallback +import com.tangem.common.core.TangemSdkError +import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.operations.CommandResponse import com.tangem.operations.sign.SignHashesCommand @@ -18,7 +20,9 @@ class TangemSignHashesResponse( class SignHashesTask( private val hashes: Collection, private val publicKey: Wallet.PublicKey, + private val pairWalletPublicKey: ByteArray?, ) : CardSessionRunnable { + override fun run(session: CardSession, callback: CompletionCallback) { SignHashesCommand(hashes.toTypedArray(), publicKey.seedKey, publicKey.derivationPath).run(session) { response -> when (response) { @@ -35,8 +39,42 @@ class SignHashesTask( ), ) } - is CompletionResult.Failure -> + is CompletionResult.Failure -> { + when { + response.error is TangemSdkError.WalletNotFound && pairWalletPublicKey != null -> { + sign(session, pairWalletPublicKey, publicKey.derivationPath, callback) + } + else -> callback(CompletionResult.Failure(response.error)) + } + } + } + } + } + + private fun sign( + session: CardSession, + publicKey: ByteArray, + derivationPath: DerivationPath?, + callback: CompletionCallback, + ) { + SignHashesCommand(hashes.toTypedArray(), publicKey, derivationPath).run(session) { response -> + when (response) { + is CompletionResult.Success -> { + val card = session.environment.card + callback( + CompletionResult.Success( + TangemSignHashesResponse( + signatures = response.data.signatures, + totalSignedHashes = response.data.totalSignedHashes, + remainingSignatures = card?.wallet(publicKey)?.remainingSignatures, + batchId = card?.batchId, + ), + ), + ) + } + is CompletionResult.Failure -> { callback(CompletionResult.Failure(response.error)) + } } } } diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt index 17fb4389ab..736b070b7a 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt @@ -218,6 +218,7 @@ class WalletConnectSdkHelper { signer = store.inject(DaggerGraphState::transactionSignerFactory).createTransactionSigner( cardId = cardId, sdk = sdk, + twinKey = null, // use null here because twin doesn't support WC ), ) return when (result) { diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/CurrencyExchangeManager.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/CurrencyExchangeManager.kt index 6504558f4f..b117321609 100644 --- a/app/src/main/java/com/tangem/tap/network/exchangeServices/CurrencyExchangeManager.kt +++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/CurrencyExchangeManager.kt @@ -104,6 +104,7 @@ class CurrencyExchangeManager( } } +@Deprecated("Useless") suspend fun buyErc20TestnetTokens(card: CardDTO, walletManager: EthereumWalletManager, destinationAddress: String) { walletManager.safeUpdate(card.isDemoCard()) @@ -123,6 +124,7 @@ suspend fun buyErc20TestnetTokens(card: CardDTO, walletManager: EthereumWalletMa cardId = card.cardId.takeIf { isCardNotBackedUp }, tangemSdk = store.inject(DaggerGraphState::cardSdkConfigRepository).sdk, initialMessage = Message(), + twinKey = null, ) { signResponse -> store.dispatch( GlobalAction.UpdateWalletSignedHashes( diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt index bd75d53d4e..2333f95cf5 100644 --- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt +++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt @@ -1,7 +1,7 @@ package com.tangem.tap.proxy.redux import com.tangem.blockchainsdk.BlockchainSDKFactory -import com.tangem.blockchainsdk.signer.TransactionSignerFactory +import com.tangem.data.card.TransactionSignerFactory import com.tangem.blockchainsdk.utils.ExcludedBlockchains import com.tangem.common.routing.AppRouter import com.tangem.core.decompose.ui.UiMessageSender diff --git a/data/card/src/main/java/com/tangem/data/card/DefaultCardSdkConfigRepository.kt b/data/card/src/main/java/com/tangem/data/card/DefaultCardSdkConfigRepository.kt index e4006b694a..84aa2bcf9e 100644 --- a/data/card/src/main/java/com/tangem/data/card/DefaultCardSdkConfigRepository.kt +++ b/data/card/src/main/java/com/tangem/data/card/DefaultCardSdkConfigRepository.kt @@ -2,12 +2,12 @@ package com.tangem.data.card import com.tangem.TangemSdk import com.tangem.blockchain.common.TransactionSigner -import com.tangem.blockchainsdk.signer.TransactionSignerFactory import com.tangem.common.UserCodeType import com.tangem.common.core.CardIdDisplayFormat import com.tangem.common.core.UserCodeRequestPolicy import com.tangem.data.card.sdk.CardSdkProvider import com.tangem.domain.card.repository.CardSdkConfigRepository +import com.tangem.domain.card.models.TwinKey import com.tangem.domain.models.scan.ProductType /** @@ -61,8 +61,8 @@ internal class DefaultCardSdkConfigRepository( } } - override fun getCommonSigner(cardId: String?): TransactionSigner { - return transactionSignerFactory.createTransactionSigner(cardId = cardId, sdk = sdk) + override fun getCommonSigner(cardId: String?, twinKey: TwinKey?): TransactionSigner { + return transactionSignerFactory.createTransactionSigner(cardId = cardId, sdk = sdk, twinKey = twinKey) } override fun isLinkedTerminal() = sdk.config.linkedTerminal diff --git a/data/card/src/main/java/com/tangem/data/card/TransactionSignerFactory.kt b/data/card/src/main/java/com/tangem/data/card/TransactionSignerFactory.kt new file mode 100644 index 0000000000..4da2cdf41c --- /dev/null +++ b/data/card/src/main/java/com/tangem/data/card/TransactionSignerFactory.kt @@ -0,0 +1,13 @@ +package com.tangem.data.card + +import com.tangem.TangemSdk +import com.tangem.blockchain.common.TransactionSigner +import com.tangem.domain.card.models.TwinKey + +/** +[REDACTED_AUTHOR] + */ +interface TransactionSignerFactory { + + fun createTransactionSigner(cardId: String?, sdk: TangemSdk, twinKey: TwinKey?): TransactionSigner +} \ No newline at end of file diff --git a/data/card/src/main/java/com/tangem/data/card/di/CardDataModule.kt b/data/card/src/main/java/com/tangem/data/card/di/CardDataModule.kt index cfdd7984b5..278ec54ba3 100644 --- a/data/card/src/main/java/com/tangem/data/card/di/CardDataModule.kt +++ b/data/card/src/main/java/com/tangem/data/card/di/CardDataModule.kt @@ -1,6 +1,6 @@ package com.tangem.data.card.di -import com.tangem.blockchainsdk.signer.TransactionSignerFactory +import com.tangem.data.card.TransactionSignerFactory import com.tangem.data.card.DefaultCardRepository import com.tangem.data.card.DefaultCardSdkConfigRepository import com.tangem.data.card.sdk.CardSdkProvider diff --git a/domain/card/src/main/kotlin/com/tangem/domain/card/models/TwinKey.kt b/domain/card/src/main/kotlin/com/tangem/domain/card/models/TwinKey.kt new file mode 100644 index 0000000000..d105415c03 --- /dev/null +++ b/domain/card/src/main/kotlin/com/tangem/domain/card/models/TwinKey.kt @@ -0,0 +1,49 @@ +package com.tangem.domain.card.models + +import com.tangem.common.extensions.hexToBytes +import com.tangem.domain.models.scan.ProductType +import com.tangem.domain.models.scan.ScanResponse + +data class TwinKey( + val key1: ByteArray, + val key2: ByteArray, +) { + fun getPairKey(walletPublicKey: ByteArray): ByteArray? { + return when { + walletPublicKey.contentEquals(key1) -> key2 + walletPublicKey.contentEquals(key2) -> key1 + else -> null + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as TwinKey + + if (!key1.contentEquals(other.key1)) return false + if (!key2.contentEquals(other.key2)) return false + + return true + } + + override fun hashCode(): Int { + var result = key1.contentHashCode() + result = 31 * result + key2.contentHashCode() + return result + } + + companion object { + + fun getOrNull(scanResponse: ScanResponse): TwinKey? { + return if (scanResponse.productType == ProductType.Twins) { + val key1 = scanResponse.card.wallets.firstOrNull()?.publicKey ?: return null + val key2 = scanResponse.secondTwinPublicKey?.hexToBytes() ?: return null + TwinKey(key1 = key1, key2 = key2) + } else { + null + } + } + } +} \ No newline at end of file diff --git a/domain/card/src/main/kotlin/com/tangem/domain/card/repository/CardSdkConfigRepository.kt b/domain/card/src/main/kotlin/com/tangem/domain/card/repository/CardSdkConfigRepository.kt index fd2f4e3b54..ecf06c78d8 100644 --- a/domain/card/src/main/kotlin/com/tangem/domain/card/repository/CardSdkConfigRepository.kt +++ b/domain/card/src/main/kotlin/com/tangem/domain/card/repository/CardSdkConfigRepository.kt @@ -2,6 +2,7 @@ package com.tangem.domain.card.repository import com.tangem.TangemSdk import com.tangem.blockchain.common.TransactionSigner +import com.tangem.domain.card.models.TwinKey import com.tangem.domain.models.scan.ProductType /** @@ -28,7 +29,7 @@ interface CardSdkConfigRepository { fun updateCardIdDisplayFormat(productType: ProductType) /** Get common signer by [cardId] */ - fun getCommonSigner(cardId: String?): TransactionSigner + fun getCommonSigner(cardId: String?, twinKey: TwinKey?): TransactionSigner /** Check if linked terminal is enabled */ fun isLinkedTerminal(): Boolean? diff --git a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/AssociateAssetUseCase.kt b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/AssociateAssetUseCase.kt index 979c1c911d..b910f1c01c 100644 --- a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/AssociateAssetUseCase.kt +++ b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/AssociateAssetUseCase.kt @@ -35,7 +35,10 @@ class AssociateAssetUseCase( if (isBalanceZero(userWalletId, networkCoin)) { raise(AssociateAssetError.NotEnoughBalance(networkCoin)) } - val signer = cardSdkConfigRepository.getCommonSigner(cardId = null) + val signer = cardSdkConfigRepository.getCommonSigner( + cardId = null, + twinKey = null, // use null here because no assets support for Twin cards + ) catch( block = { diff --git a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/RetryIncompleteTransactionUseCase.kt b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/RetryIncompleteTransactionUseCase.kt index 83467e5a33..ac7534976a 100644 --- a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/RetryIncompleteTransactionUseCase.kt +++ b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/RetryIncompleteTransactionUseCase.kt @@ -23,7 +23,10 @@ class RetryIncompleteTransactionUseCase( currency: CryptoCurrency, ): Either { return either { - val signer = cardSdkConfigRepository.getCommonSigner(cardId = null) + val signer = cardSdkConfigRepository.getCommonSigner( + cardId = null, + twinKey = null, // use null here because no assets support for Twin cards + ) catch( block = { diff --git a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/SendTransactionUseCase.kt b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/SendTransactionUseCase.kt index 59f1d6382f..c6fc973fc9 100644 --- a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/SendTransactionUseCase.kt +++ b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/SendTransactionUseCase.kt @@ -16,6 +16,7 @@ import com.tangem.domain.common.TapWorkarounds.isStart2Coin import com.tangem.domain.common.TapWorkarounds.isTangemTwins import com.tangem.domain.demo.DemoConfig import com.tangem.domain.demo.DemoTransactionSender +import com.tangem.domain.card.models.TwinKey import com.tangem.domain.tokens.model.Network import com.tangem.domain.transaction.TransactionRepository import com.tangem.domain.transaction.error.SendTransactionError @@ -37,7 +38,10 @@ class SendTransactionUseCase( val card = userWallet.scanResponse.card val isCardNotBackedUp = card.backupStatus?.isActive != true && !card.isTangemTwins - val signer = cardSdkConfigRepository.getCommonSigner(cardId = card.cardId.takeIf { isCardNotBackedUp }) + val signer = cardSdkConfigRepository.getCommonSigner( + cardId = card.cardId.takeIf { isCardNotBackedUp }, + twinKey = TwinKey.getOrNull(scanResponse = userWallet.scanResponse), + ) val linkedTerminal = cardSdkConfigRepository.isLinkedTerminal() if (userWallet.scanResponse.card.isStart2Coin) { diff --git a/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/signer/TransactionSignerFactory.kt b/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/signer/TransactionSignerFactory.kt deleted file mode 100644 index da53a4d024..0000000000 --- a/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/signer/TransactionSignerFactory.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.tangem.blockchainsdk.signer - -import com.tangem.TangemSdk -import com.tangem.blockchain.common.TransactionSigner - -/** -[REDACTED_AUTHOR] - */ -interface TransactionSignerFactory { - - fun createTransactionSigner(cardId: String?, sdk: TangemSdk): TransactionSigner -} \ No newline at end of file