Updated on 2026-08-14

This commit is contained in:
Tangem 2023-02-17 07:53:30 +03:00
parent 26fe4e24b7
commit d6b583e5fd
7 changed files with 114 additions and 93 deletions

View file

@ -1,19 +1,15 @@
package com.tangem.tap.domain.extensions
import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.DerivationParams
import com.tangem.blockchain.common.DerivationStyle
import com.tangem.blockchain.common.Wallet
import com.tangem.blockchain.common.WalletManager
import com.tangem.blockchain.common.WalletManagerFactory
import com.tangem.common.card.EllipticCurve
import com.tangem.common.extensions.guard
import com.tangem.common.extensions.hexToBytes
import com.tangem.common.extensions.toMapKey
import com.tangem.common.hdWallet.DerivationPath
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.SaltPayWorkaround
import com.tangem.domain.common.ScanResponse
import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation
@ -137,23 +133,4 @@ private fun selectWallet(wallets: List<CardDTO.Wallet>): CardDTO.Wallet? {
1 -> wallets[0]
else -> wallets.firstOrNull { it.curve == EllipticCurve.Secp256k1 } ?: wallets[0]
}
}
fun WalletManagerFactory.makeSaltPayWalletManager(
scanResponse: ScanResponse,
): EthereumWalletManager {
val blockchain = scanResponse.getBlockchain()
if (blockchain != Blockchain.SaltPay)
throw IllegalArgumentException()
val token = SaltPayWorkaround.tokenFrom(blockchain)
val cardWallet = scanResponse.card.wallets.firstOrNull().guard {
throw NullPointerException("SaltPay card must have one wallet at least")
}
return makeWalletManager(
blockchain = blockchain,
publicKey = Wallet.PublicKey(cardWallet.publicKey, null, null),
tokens = listOf(token),
) as EthereumWalletManager
}

View file

@ -27,10 +27,10 @@ import com.tangem.tap.features.onboarding.OnboardingHelper
import com.tangem.tap.features.onboarding.OnboardingSaltPayHelper
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.saltPay.SaltPayActivationManagerFactory
import com.tangem.tap.features.onboarding.products.wallet.saltPay.SaltPayExceptionHandler
import com.tangem.tap.features.onboarding.products.wallet.saltPay.message.SaltPayActivationError
import com.tangem.tap.features.onboarding.products.wallet.saltPay.redux.OnboardingSaltPayAction
import com.tangem.tap.features.onboarding.products.wallet.saltPay.redux.OnboardingSaltPayState
import com.tangem.tap.preferencesStorage
import com.tangem.tap.scope
import com.tangem.tap.store
@ -187,7 +187,10 @@ object ScanCardProcessor {
if (scanResponse.isSaltPay()) {
if (scanResponse.isSaltPayVisa()) {
val (manager, config) = OnboardingSaltPayState.initDependency(scanResponse)
val manager = SaltPayActivationManagerFactory(
blockchain = scanResponse.getBlockchain(),
card = scanResponse.card,
).create()
val result = OnboardingSaltPayHelper.isOnboardingCase(scanResponse, manager)
delay(500)
withMainContext {
@ -197,7 +200,7 @@ object ScanCardProcessor {
if (isOnboardingCase) {
onWalletNotCreated()
store.dispatch(GlobalAction.Onboarding.Start(scanResponse, canSkipBackup = false))
store.dispatch(OnboardingSaltPayAction.SetDependencies(manager, config))
store.dispatch(OnboardingSaltPayAction.SetDependencies(manager))
store.dispatch(OnboardingSaltPayAction.Update)
navigateTo(AppScreen.OnboardingWallet) { onProgressStateChange(it) }
} else {

View file

@ -3,13 +3,13 @@ package com.tangem.tap.features.onboarding.products.wallet.redux
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.CompletionResult
import com.tangem.common.extensions.ifNotNull
import com.tangem.core.analytics.Analytics
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.ScanResponse
import com.tangem.domain.common.TapWorkarounds.isSaltPay
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.operations.backup.BackupService
import com.tangem.tap.backupService
import com.tangem.core.analytics.Analytics
import com.tangem.tap.common.analytics.events.Onboarding
import com.tangem.tap.common.extensions.dispatchDialogShow
import com.tangem.tap.common.extensions.dispatchOnMain
@ -22,8 +22,8 @@ import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.features.demo.DemoHelper
import com.tangem.tap.features.home.redux.HomeAction
import com.tangem.tap.features.onboarding.OnboardingHelper
import com.tangem.tap.features.onboarding.products.wallet.saltPay.SaltPayActivationManagerFactory
import com.tangem.tap.features.onboarding.products.wallet.saltPay.redux.OnboardingSaltPayAction
import com.tangem.tap.features.onboarding.products.wallet.saltPay.redux.OnboardingSaltPayState
import com.tangem.tap.features.wallet.redux.Artwork
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.preferencesStorage
@ -396,8 +396,11 @@ private fun initSaltPayOnBackupFinishedIfNeeded(
if (onboardingWalletState.isSaltPay && onboardingWalletState.onboardingSaltPayState == null) {
if (scanResponse == null) throw IllegalArgumentException()
val (manager, config) = OnboardingSaltPayState.initDependency(scanResponse)
store.dispatchOnMain(OnboardingSaltPayAction.SetDependencies(manager, config))
val manager = SaltPayActivationManagerFactory(
blockchain = scanResponse.getBlockchain(),
card = scanResponse.card,
).create()
store.dispatchOnMain(OnboardingSaltPayAction.SetDependencies(manager))
store.dispatchOnMain(OnboardingSaltPayAction.Update)
}
}

View file

@ -1,14 +1,20 @@
package com.tangem.tap.features.onboarding.products.wallet.saltPay
import android.net.Uri
import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager
import com.tangem.blockchain.blockchains.ethereum.SignedEthereumTransaction
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.AmountType
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.BlockchainSdkError
import com.tangem.blockchain.common.Token
import com.tangem.blockchain.common.TransactionSigner
import com.tangem.blockchain.common.Wallet
import com.tangem.blockchain.common.WalletManagerFactory
import com.tangem.blockchain.extensions.successOr
import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.guard
import com.tangem.common.extensions.hexToBytes
import com.tangem.common.extensions.isZero
import com.tangem.common.services.Result
import com.tangem.datasource.api.paymentology.AttestationResponse
@ -18,12 +24,15 @@ import com.tangem.datasource.api.paymentology.RegisterWalletRequest
import com.tangem.datasource.api.paymentology.RegisterWalletResponse
import com.tangem.datasource.api.paymentology.RegistrationResponse
import com.tangem.datasource.api.paymentology.tryExtractError
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.SaltPayWorkaround
import com.tangem.domain.common.extensions.successOr
import com.tangem.operations.attestation.AttestWalletKeyResponse
import com.tangem.tap.common.extensions.safeUpdate
import com.tangem.tap.domain.getFirstToken
import com.tangem.tap.domain.model.builders.UserWalletIdBuilder
import com.tangem.tap.features.onboarding.products.wallet.saltPay.message.SaltPayActivationError
import com.tangem.tap.store
import java.math.BigDecimal
/**
@ -200,4 +209,96 @@ class KYCUrlProvider(
.appendQueryParameter(kycProvider.externalIdParameterKey, kycRefId)
.build().toString()
}
}
class SaltPayActivationManagerFactory(
private val blockchain: Blockchain,
private val card: CardDTO,
) {
fun create(): SaltPayActivationManager {
val wallet = card.wallets.first()
val saltPayConfig = store.state.globalState.configManager?.config?.saltPayConfig.guard {
throw NullPointerException("SaltPayConfig is not initialized")
}
val wmFactory = store.state.globalState.tapWalletManager.walletManagerFactory
val paymentologyService = store.state.domainNetworks.paymentologyService
// return createDummyActivationManager(saltPayConfig, wmFactory, paymentologyService)
return createActivationPayManager(
cardId = card.cardId,
cardPublicKey = card.cardPublicKey,
kycProvider = saltPayConfig.kycProvider,
gnosisRegistrator = GnosisRegistrator(
walletManager = makeSaltPayWalletManager(
blockchain = blockchain,
walletPublicKey = wallet.publicKey,
wmFactory = wmFactory,
),
),
paymentologyService = paymentologyService,
)
}
private fun makeSaltPayWalletManager(
blockchain: Blockchain,
walletPublicKey: ByteArray,
wmFactory: WalletManagerFactory,
): EthereumWalletManager {
return wmFactory.makeWalletManager(
blockchain = blockchain,
publicKey = Wallet.PublicKey(walletPublicKey, null, null),
tokens = listOf(SaltPayWorkaround.tokenFrom(blockchain)),
) as EthereumWalletManager
}
private fun createActivationPayManager(
cardId: String,
cardPublicKey: ByteArray,
kycProvider: KYCProvider,
gnosisRegistrator: GnosisRegistrator,
paymentologyService: PaymentologyApiService,
): SaltPayActivationManager {
return SaltPayActivationManager(
cardId = cardId,
cardPublicKey = cardPublicKey,
kycProvider = kycProvider,
paymentologyService = paymentologyService,
gnosisRegistrator = gnosisRegistrator,
)
}
private fun createDummyActivationManager(
saltPayConfig: SaltPayConfig,
wmFactory: WalletManagerFactory,
paymentologyService: PaymentologyApiService,
): SaltPayActivationManager {
val fakeSource = DummySaltPayCardSource()
val walletManager = wmFactory.makeWalletManager(
blockchain = fakeSource.blockchain,
publicKey = fakeSource.blockchainPublicKey,
tokens = listOf(fakeSource.token),
) as EthereumWalletManager
return createActivationPayManager(
cardId = fakeSource.cardId,
cardPublicKey = fakeSource.cardPublicKey,
kycProvider = saltPayConfig.kycProvider,
gnosisRegistrator = GnosisRegistrator(walletManager),
paymentologyService = paymentologyService,
)
}
private data class DummySaltPayCardSource(
val blockchain: Blockchain = Blockchain.SaltPay,
val cardId: String = "FF03000001001057",
private val cardPublicKeyString: String = "039C2D2F9B68003766BFC29766761F55F4084E48B8B012BF439E115A79AB122D48",
private val walletPublicKeyString: String = "0399B2DF5B129FBF69097DAA7C44FB5849E578CCFC22228A409870C74B56C4C3D1",
) {
val cardPublicKey: ByteArray = cardPublicKeyString.hexToBytes()
val walletPublicKey: ByteArray = walletPublicKeyString.hexToBytes()
val blockchainPublicKey = Wallet.PublicKey(walletPublicKey, null, null)
val token: Token = SaltPayWorkaround.tokenFrom(blockchain)
}
}

View file

@ -2,7 +2,6 @@ package com.tangem.tap.features.onboarding.products.wallet.saltPay.redux
import com.tangem.blockchain.common.Amount
import com.tangem.tap.features.onboarding.products.wallet.saltPay.SaltPayActivationManager
import com.tangem.tap.features.onboarding.products.wallet.saltPay.SaltPayConfig
import org.rekotlin.Action
import java.math.BigDecimal
@ -14,7 +13,6 @@ sealed class OnboardingSaltPayAction : Action {
data class SetDependencies(
val registrationManager: SaltPayActivationManager,
val saltPayConfig: SaltPayConfig,
) : OnboardingSaltPayAction()
data class SetInProgress(val isInProgress: Boolean) : OnboardingSaltPayAction()

View file

@ -21,7 +21,6 @@ private fun internalReduce(anyAction: Action, onboardingWalletState: OnboardingW
return onboardingWalletState.copy(
onboardingSaltPayState = OnboardingSaltPayState(
saltPayManager = action.registrationManager,
saltPayConfig = action.saltPayConfig,
),
)
}

View file

@ -2,19 +2,10 @@ package com.tangem.tap.features.onboarding.products.wallet.saltPay.redux
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.WalletManagerFactory
import com.tangem.common.extensions.guard
import com.tangem.domain.common.SaltPayWorkaround
import com.tangem.domain.common.ScanResponse
import com.tangem.datasource.api.paymentology.PaymentologyApiService
import com.tangem.tap.common.toggleWidget.WidgetState
import com.tangem.tap.domain.extensions.makeSaltPayWalletManager
import com.tangem.tap.features.onboarding.products.wallet.saltPay.GnosisRegistrator
import com.tangem.tap.features.onboarding.products.wallet.saltPay.KYCProvider
import com.tangem.tap.features.onboarding.products.wallet.saltPay.SaltPayActivationManager
import com.tangem.tap.features.onboarding.products.wallet.saltPay.SaltPayConfig
import com.tangem.tap.features.wallet.redux.ProgressState
import com.tangem.tap.store
import java.math.BigDecimal
/**
@ -23,7 +14,6 @@ import java.math.BigDecimal
data class OnboardingSaltPayState(
@Transient
val saltPayManager: SaltPayActivationManager = SaltPayActivationManager.stub(),
val saltPayConfig: SaltPayConfig = SaltPayConfig.stub(),
val pinCode: String? = null,
val accessCode: String? = null,
val amountToClaim: Amount? = null,
@ -37,57 +27,7 @@ data class OnboardingSaltPayState(
val mainButtonState: WidgetState
get() = if (inProgress) ProgressState.Loading else ProgressState.Done
fun readyToClaim(): Boolean = amountToClaim != null
val pinLength: Int = 4
companion object {
fun initDependency(scanResponse: ScanResponse): Pair<SaltPayActivationManager, SaltPayConfig> {
val globalState = store.state.globalState
val saltPayConfig = globalState.configManager?.config?.saltPayConfig.guard {
throw NullPointerException("SaltPayConfig is not initialized")
}
val gnosisRegistrator = makeGnosisRegistrator(
scanResponse = scanResponse,
wmFactory = globalState.tapWalletManager.walletManagerFactory,
)
val registrationManager = makeSaltPayRegistrationManager(
scanResponse = scanResponse,
gnosisRegistrator = gnosisRegistrator,
paymentologyService = store.state.domainNetworks.paymentologyService,
kycProvider = saltPayConfig.kycProvider,
)
return registrationManager to saltPayConfig
}
fun makeSaltPayRegistrationManager(
scanResponse: ScanResponse,
gnosisRegistrator: GnosisRegistrator,
paymentologyService: PaymentologyApiService,
kycProvider: KYCProvider,
): SaltPayActivationManager {
if (!scanResponse.isSaltPay()) {
throw IllegalArgumentException("Can't initialize the OnboardingSaltPayMiddleware if card is not SalPay")
}
return SaltPayActivationManager(
cardId = scanResponse.card.cardId,
cardPublicKey = scanResponse.card.cardPublicKey,
kycProvider = kycProvider,
paymentologyService = paymentologyService,
gnosisRegistrator = gnosisRegistrator,
)
}
fun makeGnosisRegistrator(
scanResponse: ScanResponse,
wmFactory: WalletManagerFactory,
): GnosisRegistrator {
return GnosisRegistrator(
walletManager = wmFactory.makeSaltPayWalletManager(scanResponse),
)
}
}
}
enum class SaltPayActivationStep {