Updated on 2026-08-14

This commit is contained in:
Tangem 2024-10-10 15:56:02 +04:00
commit 369ed25ac6
515 changed files with 6100 additions and 12756 deletions

View file

@ -4,19 +4,12 @@ import com.tangem.blockchain.common.Token
import com.tangem.blockchain.common.Wallet
import com.tangem.core.analytics.Analytics
import com.tangem.core.analytics.models.Basic
import com.tangem.datasource.config.ConfigManager
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.operations.attestation.Attestation
import com.tangem.tap.common.extensions.inject
import com.tangem.tap.common.extensions.setContext
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.features.disclaimer.createDisclaimer
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.store
import com.tangem.tap.tangemSdkManager
import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider
@ -54,30 +47,13 @@ class TapWalletManager(
tangemSdkManager.changeDisplayedCardIdNumbersCount(scanResponse)
val featureToggles = store.inject(DaggerGraphState::feedbackManagerFeatureToggles)
if (!featureToggles.isLocalLogsEnabled) {
store.state.globalState.feedbackManager?.infoHolder?.setCardInfo(scanResponse)
}
updateConfigManager(scanResponse)
withMainContext {
// Order is important
store.dispatch(DisclaimerAction.SetDisclaimer(card.createDisclaimer()))
store.dispatch(TwinCardsAction.IfTwinsPrepareState(scanResponse))
store.dispatch(GlobalAction.SaveScanResponse(scanResponse))
store.dispatch(GlobalAction.SetIfCardVerifiedOnline(!attestationFailed))
}
}
fun updateConfigManager(data: ScanResponse) {
val configManager = store.state.globalState.configManager
if (data.cardTypesResolver.isStart2Coin()) {
configManager?.turnOff(ConfigManager.IS_TOP_UP_ENABLED)
} else {
configManager?.resetToDefault(ConfigManager.IS_TOP_UP_ENABLED)
}
}
}
fun Wallet.getFirstToken(): Token? = getTokens().toList().getOrNull(index = 0)

View file

@ -12,8 +12,8 @@ import com.tangem.common.extensions.toMapKey
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.data.common.currency.getNetwork
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.card.BackendId
import com.tangem.domain.card.repository.DerivationsRepository
import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.Network
@ -21,6 +21,7 @@ import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.operations.derivation.ExtendedPublicKeysMap
import com.tangem.tap.domain.sdk.TangemSdkManager
import com.tangem.tap.domain.tasks.UserWalletIdPreflightReadFilter
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.withContext
import timber.log.Timber
@ -47,7 +48,7 @@ internal class DefaultDerivationsRepository(
getNetwork(
blockchain = Blockchain.fromNetworkId(it.value) ?: return@mapNotNull null,
extraDerivationPath = null,
derivationStyleProvider = userWallet.scanResponse.derivationStyleProvider,
scanResponse = userWallet.scanResponse,
)
},
)
@ -73,17 +74,17 @@ internal class DefaultDerivationsRepository(
override suspend fun hasMissedDerivations(
userWalletId: UserWalletId,
networksWithDerivationPath: Map<Network.ID, String?>,
networksWithDerivationPath: Map<BackendId, String?>,
): Boolean {
val userWallet = userWalletsStore.getSyncOrNull(userWalletId) ?: error("User wallet not found")
val derivations = MissedDerivationsFinder(scanResponse = userWallet.scanResponse)
.findByNetworks(
networksWithDerivationPath.mapNotNull { (networkId, extraDerivationPath) ->
networksWithDerivationPath.mapNotNull { (backendId, extraDerivationPath) ->
getNetwork(
blockchain = Blockchain.fromNetworkId(networkId.value) ?: return@mapNotNull null,
blockchain = Blockchain.fromNetworkId(backendId) ?: return@mapNotNull null,
extraDerivationPath = extraDerivationPath,
derivationStyleProvider = userWallet.scanResponse.derivationStyleProvider,
scanResponse = userWallet.scanResponse,
)
},
)
@ -92,15 +93,20 @@ internal class DefaultDerivationsRepository(
}
override suspend fun derivePublicKeys(userWalletId: UserWalletId, derivations: Derivations): DerivedKeys {
tangemSdkManager.derivePublicKeys(cardId = null, derivations = derivations)
.doOnSuccess { response ->
updatePublicKeys(userWalletId = userWalletId, keys = response.entries)
.doOnSuccess {
validateDerivations(scanResponse = it.scanResponse, derivations = derivations)
return response.entries
}
.doOnFailure { throw it }
}
// todo replace it in task [REDACTED_JIRA]
val preflightReadFilter = UserWalletIdPreflightReadFilter(userWalletId)
tangemSdkManager.derivePublicKeys(
cardId = null,
derivations = derivations,
preflightReadFilter = preflightReadFilter,
).doOnSuccess { response ->
updatePublicKeys(userWalletId = userWalletId, keys = response.entries)
.doOnSuccess {
validateDerivations(scanResponse = it.scanResponse, derivations = derivations)
return response.entries
}
.doOnFailure { throw it }
}
.doOnFailure { throw it }
error("This code should never be reached")

View file

@ -0,0 +1,16 @@
package com.tangem.tap.domain.scanCard
import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
/**
* Add custom token feature toggles
*
[REDACTED_AUTHOR]
*/
class CardScanningFeatureToggles internal constructor(
private val featureTogglesManager: FeatureTogglesManager,
) {
val isNewCardScanningEnabled: Boolean
get() = featureTogglesManager.isFeatureEnabled(name = "NEW_CARD_SCANNING_ENABLED")
}

View file

@ -12,7 +12,7 @@ import com.tangem.tap.store
// TODO: Remove this object after feature toggle was removed and use ScanCardUseCase instead
internal class DefaultScanCardProcessor : ScanCardProcessor {
private val isNewCardScanningEnabled: Boolean
get() = store.inject(DaggerGraphState::customTokenFeatureToggles).isNewCardScanningEnabled
get() = store.inject(DaggerGraphState::cardScanningFeatureToggles).isNewCardScanningEnabled
override suspend fun scan(
cardId: String?,

View file

@ -2,7 +2,6 @@ package com.tangem.tap.domain.scanCard
import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemError
import com.tangem.common.core.TangemSdkError
import com.tangem.common.doOnFailure
import com.tangem.common.doOnSuccess
import com.tangem.common.routing.AppRoute
@ -18,12 +17,10 @@ import com.tangem.tap.common.analytics.paramsInterceptor.CardContextInterceptor
import com.tangem.tap.common.extensions.*
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.features.disclaimer.createDisclaimer
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
import com.tangem.tap.features.disclaimer.redux.DisclaimerCallback
import com.tangem.tap.features.disclaimer.redux.DisclaimerSource
import com.tangem.tap.features.onboarding.OnboardingHelper
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupStartedSource
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.scope
import com.tangem.tap.store
@ -102,6 +99,8 @@ internal object LegacyScanProcessor {
}
}
// TODO: [REDACTED_JIRA]
@Suppress("UnusedPrivateMember")
private suspend inline fun showDisclaimerIfNeed(
scanResponse: ScanResponse,
crossinline disclaimerWillShow: () -> Unit = {},
@ -109,7 +108,6 @@ internal object LegacyScanProcessor {
crossinline onFailure: suspend (error: TangemError) -> Unit,
) {
val disclaimer = scanResponse.card.createDisclaimer()
store.dispatchOnMain(DisclaimerAction.SetDisclaimer(disclaimer))
if (disclaimer.isAccepted()) {
nextHandler(scanResponse)
@ -120,23 +118,9 @@ internal object LegacyScanProcessor {
withContext(Dispatchers.Main.immediate) {
disclaimerWillShow()
store.dispatch(
DisclaimerAction.Show(
from = DisclaimerSource.Home,
callback = DisclaimerCallback(
onAccept = {
scope.launch(Dispatchers.Main.immediate) {
nextHandler(scanResponse)
}
},
onDismiss = {
scope.launch(Dispatchers.Main.immediate) {
onFailure(TangemSdkError.UserCancelled())
}
},
),
),
)
store.dispatchNavigationAction {
push(AppRoute.Disclaimer(isTosAccepted = false))
}
}
}
}
@ -149,10 +133,6 @@ internal object LegacyScanProcessor {
crossinline onWalletNotCreated: suspend () -> Unit,
crossinline onSuccess: suspend (ScanResponse) -> Unit,
) {
val globalState = store.state.globalState
val tapWalletManager = globalState.tapWalletManager
tapWalletManager.updateConfigManager(scanResponse)
store.dispatchOnMain(TwinCardsAction.IfTwinsPrepareState(scanResponse))
if (OnboardingHelper.isOnboardingCase(scanResponse)) {
@ -162,6 +142,7 @@ internal object LegacyScanProcessor {
store.dispatchOnMain(
GlobalAction.Onboarding.Start(
scanResponse = scanResponse,
source = BackupStartedSource.Onboarding,
canSkipBackup = scanResponse.card.canSkipBackup,
),
)

View file

@ -59,12 +59,8 @@ internal object UseCaseScanProcessor {
),
)
add(AnalyticsChain(Basic.CardWasScanned(analyticsSource)))
val pushNotificationsToggles =
store.inject(getDependency = DaggerGraphState::pushNotificationsFeatureToggles)
if (pushNotificationsToggles.isPushNotificationsEnabled) {
add(DisclaimerChain(store, disclaimerWillShow))
}
add(CheckForOnboardingChain(store, store.state.globalState.tapWalletManager))
add(DisclaimerChain(store, disclaimerWillShow))
add(CheckForOnboardingChain(store))
}
scanCardUseCase(cardId, afterScanChains = chains).fold(

View file

@ -16,10 +16,10 @@ import com.tangem.tap.common.extensions.inject
import com.tangem.tap.common.extensions.setContext
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.domain.TapWalletManager
import com.tangem.tap.features.onboarding.OnboardingHelper
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupStartedSource
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
import kotlinx.coroutines.delay
@ -32,17 +32,14 @@ import org.rekotlin.Store
* - [ScanChainException.OnboardingNeeded] if onboarding required.
*
* @param store the [Store] that holds the state of the app.
* @param tapWalletManager manager responsible for handling operations related to the Wallet.
*
* @see Chain for more information about the Chain interface.
*/
class CheckForOnboardingChain(
private val store: Store<AppState>,
private val tapWalletManager: TapWalletManager,
) : ResultChain<ScanCardException, ScanResponse>() {
override suspend fun launch(previousChainResult: ScanResponse): ScanChainResult {
tapWalletManager.updateConfigManager(previousChainResult)
store.dispatchOnMain(TwinCardsAction.IfTwinsPrepareState(previousChainResult))
return when {
@ -52,6 +49,7 @@ class CheckForOnboardingChain(
store.dispatchOnMain(
GlobalAction.Onboarding.Start(
scanResponse = previousChainResult,
source = BackupStartedSource.Onboarding,
canSkipBackup = previousChainResult.card.canSkipBackup,
),
)

View file

@ -1,21 +1,15 @@
package com.tangem.tap.domain.scanCard.chains
import arrow.core.left
import arrow.core.right
import com.tangem.common.routing.AppRoute
import com.tangem.domain.card.ScanCardException
import com.tangem.domain.core.chain.Chain
import com.tangem.domain.core.chain.ResultChain
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.extensions.dispatchNavigationAction
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.features.disclaimer.Disclaimer
import com.tangem.tap.features.disclaimer.createDisclaimer
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
import com.tangem.tap.features.disclaimer.redux.DisclaimerCallback
import com.tangem.tap.features.disclaimer.redux.DisclaimerSource
import kotlinx.coroutines.suspendCancellableCoroutine
import org.rekotlin.Store
import kotlin.coroutines.resume
/**
* Handles disclaimer display after the card scanning operation.
@ -40,31 +34,13 @@ internal class DisclaimerChain(
previousChainResult.right()
} else {
disclaimerWillShow()
showDisclaimer(disclaimer, previousChainResult)
}
}
private suspend fun showDisclaimer(disclaimer: Disclaimer, response: ScanResponse): ScanChainResult {
store.dispatchOnMain(DisclaimerAction.SetDisclaimer(disclaimer))
// TODO: [REDACTED_JIRA]
store.dispatchNavigationAction {
push(route = AppRoute.Disclaimer(isTosAccepted = false))
}
return suspendCancellableCoroutine { continuation ->
store.dispatchOnMain(
DisclaimerAction.Show(
from = DisclaimerSource.Home,
callback = DisclaimerCallback(
onAccept = {
if (continuation.isActive) {
continuation.resume(response.right())
}
},
onDismiss = {
if (continuation.isActive) {
continuation.resume(ScanChainException.DisclaimerWasCanceled.left())
}
},
),
),
)
previousChainResult.right()
}
}
}

View file

@ -17,6 +17,7 @@ import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.operations.derivation.DerivationTaskResponse
import com.tangem.operations.preflightread.PreflightReadFilter
import com.tangem.operations.wallet.CreateWalletResponse
import com.tangem.tap.domain.tasks.product.CreateProductWalletTaskResponse
@ -59,6 +60,7 @@ interface TangemSdkManager {
suspend fun derivePublicKeys(
cardId: String?,
derivations: Map<ByteArrayKey, List<DerivationPath>>,
preflightReadFilter: PreflightReadFilter?,
): CompletionResult<DerivationTaskResponse>
suspend fun deriveExtendedPublicKey(
@ -99,6 +101,7 @@ interface TangemSdkManager {
)
suspend fun <T> runTaskAsync(
runnable: CardSessionRunnable<T>,
preflightReadFilter: PreflightReadFilter?,
cardId: String? = null,
initialMessage: Message? = null,
accessCode: String? = null,

View file

@ -29,6 +29,7 @@ import com.tangem.operations.derivation.DerivationTaskResponse
import com.tangem.operations.derivation.DeriveMultipleWalletPublicKeysTask
import com.tangem.operations.derivation.DeriveWalletPublicKeyTask
import com.tangem.operations.pins.SetUserCodeCommand
import com.tangem.operations.preflightread.PreflightReadFilter
import com.tangem.operations.usersetttings.SetUserCodeRecoveryAllowedTask
import com.tangem.operations.wallet.CreateWalletResponse
import com.tangem.tap.derivationsFinder
@ -157,6 +158,7 @@ class DefaultTangemSdkManager(
Message(resources.getString(R.string.initial_message_create_wallet_body))
},
iconScanRes = if (scanResponse.cardTypesResolver.isRing()) R.drawable.img_hand_scan_ring else null,
preflightReadFilter = null,
)
.doOnResult { tangemSdk.config.setupForProduct(ProductType.ANY) }
}
@ -195,6 +197,7 @@ class DefaultTangemSdkManager(
} else {
Message(resources.getString(R.string.initial_message_create_wallet_body))
},
preflightReadFilter = null,
)
.doOnResult { tangemSdk.config.setupForProduct(ProductType.ANY) }
}
@ -210,8 +213,13 @@ class DefaultTangemSdkManager(
override suspend fun derivePublicKeys(
cardId: String?,
derivations: Map<ByteArrayKey, List<DerivationPath>>,
preflightReadFilter: PreflightReadFilter?,
): CompletionResult<DerivationTaskResponse> {
return runTaskAsyncReturnOnMain(DeriveMultipleWalletPublicKeysTask(derivations), cardId)
return runTaskAsyncReturnOnMain(
runnable = DeriveMultipleWalletPublicKeysTask(derivations),
cardId = cardId,
preflightReadFilter = preflightReadFilter,
)
}
override suspend fun deriveExtendedPublicKey(
@ -317,13 +325,21 @@ class DefaultTangemSdkManager(
override suspend fun <T> runTaskAsync(
runnable: CardSessionRunnable<T>,
preflightReadFilter: PreflightReadFilter?,
cardId: String?,
initialMessage: Message?,
accessCode: String?,
@DrawableRes iconScanRes: Int?,
): CompletionResult<T> = withContext(Dispatchers.Main) {
suspendCancellableCoroutine { continuation ->
tangemSdk.startSessionWithRunnable(runnable, cardId, initialMessage, accessCode, iconScanRes) { result ->
tangemSdk.startSessionWithRunnable(
runnable = runnable,
cardId = cardId,
initialMessage = initialMessage,
accessCode = accessCode,
preflightReadFilter = preflightReadFilter,
iconScanRes = iconScanRes,
) { result ->
if (continuation.isActive) continuation.resume(result)
}
}
@ -333,8 +349,14 @@ class DefaultTangemSdkManager(
runnable: CardSessionRunnable<T>,
cardId: String? = null,
initialMessage: Message? = null,
preflightReadFilter: PreflightReadFilter? = null,
): CompletionResult<T> {
val result = runTaskAsync(runnable, cardId, initialMessage)
val result = runTaskAsync(
runnable = runnable,
cardId = cardId,
initialMessage = initialMessage,
preflightReadFilter = preflightReadFilter,
)
return withContext(Dispatchers.Main) { result }
}
@ -386,6 +408,7 @@ class DefaultTangemSdkManager(
runnable = CreateFirstTwinWalletTask(cardId),
cardId = cardId,
initialMessage = initialMessage,
preflightReadFilter = null,
)
}
@ -404,7 +427,7 @@ class DefaultTangemSdkManager(
preparingMessage = preparingMessage,
creatingWalletMessage = creatingWalletMessage,
)
return runTaskAsync(task, null, initialMessage)
return runTaskAsync(runnable = task, cardId = null, initialMessage = initialMessage, preflightReadFilter = null)
}
override fun changeProductType(isRing: Boolean) {
@ -427,6 +450,7 @@ class DefaultTangemSdkManager(
runnable = FinalizeTwinTask(secondCardPublicKey, issuerKeyPair),
cardId = cardId,
initialMessage = initialMessage,
preflightReadFilter = null,
)
}

View file

@ -18,6 +18,7 @@ import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.operations.derivation.DerivationTaskResponse
import com.tangem.operations.preflightread.PreflightReadFilter
import com.tangem.operations.wallet.CreateWalletResponse
import com.tangem.tap.domain.sdk.TangemSdkManager
import com.tangem.tap.domain.sdk.mocks.MockProvider
@ -72,6 +73,7 @@ class MockTangemSdkManager(
override suspend fun derivePublicKeys(
cardId: String?,
derivations: Map<ByteArrayKey, List<DerivationPath>>,
preflightReadFilter: PreflightReadFilter?,
): CompletionResult<DerivationTaskResponse> {
return MockProvider.getDerivationTaskResponse()
}
@ -135,6 +137,7 @@ class MockTangemSdkManager(
override suspend fun <T> runTaskAsync(
runnable: CardSessionRunnable<T>,
preflightReadFilter: PreflightReadFilter?,
cardId: String?,
initialMessage: Message?,
accessCode: String?,

View file

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

View file

@ -4,12 +4,12 @@ import com.github.salomonbrys.kotson.registerTypeAdapter
import com.google.gson.GsonBuilder
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.extensions.calculateSha256
import com.tangem.tap.common.extensions.stripZeroPlainString
import com.tangem.tap.domain.walletconnect2.domain.models.binance.WcBinanceTradeOrder
import com.tangem.tap.domain.walletconnect2.domain.models.binance.WcBinanceTransferOrder
import com.tangem.tap.domain.walletconnect2.domain.models.binance.tradeOrderSerializer
import com.tangem.tap.features.details.redux.walletconnect.BinanceMessageData
import com.tangem.tap.features.details.redux.walletconnect.TradeData
import com.tangem.utils.extensions.stripZeroPlainString
import timber.log.Timber
internal object BnbHelper {

View file

@ -241,16 +241,22 @@ class WalletConnectSdkHelper {
private suspend fun signTransaction(data: WcTransactionData, cardId: String?): String? {
val dataToSign = EthereumUtils.buildTransactionToSign(
transactionData = data.transaction,
nonce = null,
blockchain = data.walletManager.wallet.blockchain,
) ?: return null
)
val command = SignHashCommand(
hash = dataToSign.hash,
walletPublicKey = data.walletManager.wallet.publicKey.seedKey,
derivationPath = data.walletManager.wallet.publicKey.derivationPath,
)
return when (val result = tangemSdkManager.runTaskAsync(command, initialMessage = Message(), cardId = cardId)) {
return when (
val result = tangemSdkManager.runTaskAsync(
runnable = command,
initialMessage = Message(),
cardId = cardId,
preflightReadFilter = null,
)
) {
is CompletionResult.Success -> {
val hash = EthereumUtils.prepareTransactionToSend(
signature = result.data.signature,
@ -293,7 +299,14 @@ class WalletConnectSdkHelper {
walletPublicKey = wallet.publicKey.seedKey,
derivationPath = wallet.publicKey.derivationPath,
)
return when (val result = tangemSdkManager.runTaskAsync(command, initialMessage = Message(), cardId = cardId)) {
return when (
val result = tangemSdkManager.runTaskAsync(
runnable = command,
initialMessage = Message(),
cardId = cardId,
preflightReadFilter = null,
)
) {
is CompletionResult.Success -> {
val key = wallet.publicKey.blockchainKey.toDecompressedPublicKey()
getBnbResultString(
@ -387,7 +400,13 @@ class WalletConnectSdkHelper {
walletPublicKey = wallet.publicKey.seedKey,
derivationPath = wallet.publicKey.derivationPath,
)
return when (val result = tangemSdkManager.runTaskAsync(command, cardId)) {
return when (
val result = tangemSdkManager.runTaskAsync(
runnable = command,
cardId = cardId,
preflightReadFilter = null,
)
) {
is CompletionResult.Success -> {
val signedHash = result.data.signature
@ -422,7 +441,13 @@ class WalletConnectSdkHelper {
walletPublicKey = wallet.publicKey.seedKey,
derivationPath = wallet.publicKey.derivationPath,
)
return when (val result = tangemSdkManager.runTaskAsync(command, cardId)) {
return when (
val result = tangemSdkManager.runTaskAsync(
runnable = command,
cardId = cardId,
preflightReadFilter = null,
)
) {
is CompletionResult.Success -> {
val signedHash = result.data.signature