diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index a3ce75396a..274048b425 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -73,7 +73,7 @@ private val walletStoresRepository by lazy { WalletStoresRepository.provideDefau private val walletManagersRepository by lazy { WalletManagersRepository.provideDefaultImplementation( walletManagerFactory = WalletManagerFactory( - blockchainSdkConfig = store.state.globalState.configManager + config = store.state.globalState.configManager ?.config ?.blockchainSdkConfig ?: BlockchainSdkConfig(), diff --git a/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletIdBuilder.kt b/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletIdBuilder.kt index ebe875ad66..6a3b71d604 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletIdBuilder.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletIdBuilder.kt @@ -63,6 +63,12 @@ class UserWalletIdBuilder private constructor( ) } + fun walletPublicKey(publicKey: ByteArray): UserWalletId { + return UserWalletIdBuilder( + publicKey = publicKey, + ).build()!! + } + private fun findPublicKey(wallets: List): ByteArray? { return wallets.firstOrNull() ?.publicKey diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt index 222768169b..36f4635c4a 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt @@ -199,9 +199,9 @@ object ScanCardProcessor { val isOnboardingCase = result.data if (isOnboardingCase) { onWalletNotCreated() - store.dispatchOnMain(GlobalAction.Onboarding.Start(scanResponse, canSkipBackup = false)) - store.dispatchOnMain(OnboardingSaltPayAction.SetDependencies(manager, config)) - store.dispatchOnMain(OnboardingSaltPayAction.Update) + store.dispatch(GlobalAction.Onboarding.Start(scanResponse, canSkipBackup = false)) + store.dispatch(OnboardingSaltPayAction.SetDependencies(manager, config)) + store.dispatch(OnboardingSaltPayAction.Update) navigateTo(AppScreen.OnboardingWallet) { onProgressStateChange(it) } } else { delay(DELAY_SDK_DIALOG_CLOSE) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/GnosisRegistrator.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/GnosisRegistrator.kt index 8921be37f3..8882281ca9 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/GnosisRegistrator.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/GnosisRegistrator.kt @@ -149,6 +149,11 @@ class GnosisRegistrator( } suspend fun transferFrom(amountToClaim: BigDecimal, signer: TransactionSigner): Result { + if (walletManager.txCount == -1L) { + walletManager.safeUpdate().successOr { + return Result.Failure(BlockchainSdkError.WrappedThrowable(it.error)) + } + } val amount = Amount(token, amountToClaim) val feeAmount = walletManager.getFeeToTransferFrom(amount, addressTreasureSafe) .extractFeeAmount().successOr { return it } diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayActivationManager.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayActivationManager.kt index ddc768c890..e99c85ae58 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayActivationManager.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayActivationManager.kt @@ -7,6 +7,7 @@ import com.tangem.blockchain.common.AmountType import com.tangem.blockchain.common.BlockchainSdkError import com.tangem.blockchain.common.TransactionSigner import com.tangem.blockchain.extensions.successOr +import com.tangem.common.core.TangemSdkError import com.tangem.common.extensions.guard import com.tangem.common.extensions.isZero import com.tangem.common.extensions.toHexString @@ -23,10 +24,10 @@ import com.tangem.datasource.api.paymentology.models.response.tryExtractError import com.tangem.datasource.config.models.KYCProvider import com.tangem.datasource.config.models.SaltPayConfig import com.tangem.domain.common.extensions.successOr -import com.tangem.domain.common.util.UserWalletId 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 kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -39,11 +40,12 @@ import com.tangem.blockchain.extensions.Result as BlockchainResult class SaltPayActivationManager( val cardId: String, val cardPublicKey: ByteArray, - val walletPublicKey: ByteArray, private val kycProvider: KYCProvider, private val paymentologyService: PaymentologyApiService, private val gnosisRegistrator: GnosisRegistrator, ) { + + val walletPublicKey = gnosisRegistrator.walletManager.wallet.publicKey.seedKey val kycUrlProvider = KYCUrlProvider(walletPublicKey, kycProvider) private val approvalValue: BigDecimal = BigDecimal(2).pow(256).minus(BigDecimal.ONE) @@ -73,18 +75,12 @@ class SaltPayActivationManager( } suspend fun checkRegistration(): Result { + val requestItem = CheckRegistrationRequests.Item(cardId, cardPublicKey.toHexString()) + val request = CheckRegistrationRequests(listOf(requestItem)) + val response: RegistrationResponse = withContext(Dispatchers.IO) { performRequest { - paymentologyService.api.checkRegistration( - request = CheckRegistrationRequests( - requests = listOf( - CheckRegistrationRequests.Item( - cardId = cardId, - publicKey = cardPublicKey.toHexString(), - ), - ), - ), - ) + paymentologyService.api.checkRegistration(request) } } .successOr { return it } @@ -104,14 +100,10 @@ class SaltPayActivationManager( } suspend fun requestAttestationChallenge(): Result { + val requestItem = CheckRegistrationRequests.Item(cardId, cardPublicKey.toHexString()) return withContext(Dispatchers.IO) { performRequest { - paymentologyService.api.requestAttestationChallenge( - request = CheckRegistrationRequests.Item( - cardId = cardId, - publicKey = cardPublicKey.toHexString(), - ), - ) + paymentologyService.api.requestAttestationChallenge(requestItem) } } .successOr { return it } @@ -139,7 +131,9 @@ class SaltPayActivationManager( pin = pinCode, ) return withContext(Dispatchers.IO) { - performRequest { paymentologyService.api.registerWallet(request) } + performRequest { + paymentologyService.api.registerWallet(request) + } } .successOr { return it } .tryExtractError() @@ -159,7 +153,13 @@ class SaltPayActivationManager( suspend fun claim(amountToClaim: BigDecimal, signer: TransactionSigner): Result { gnosisRegistrator.transferFrom(amountToClaim, signer).successOr { - return Result.Failure(SaltPayActivationError.ClaimTransactionFailed) + val userCancelledError = (it.error as? BlockchainSdkError.WrappedTangemError) + ?.tangemError as? TangemSdkError.UserCancelled + + return when (userCancelledError) { + null -> Result.Failure(SaltPayActivationError.ClaimTransactionFailed) + else -> Result.Failure(userCancelledError) + } } return Result.Success(Unit) } @@ -202,7 +202,6 @@ class SaltPayActivationManager( gnosisRegistrator = GnosisRegistrator.stub(), cardId = "", cardPublicKey = byteArrayOf(), - walletPublicKey = byteArrayOf(), ) } } @@ -212,7 +211,7 @@ class KYCUrlProvider( kycProvider: KYCProvider, ) { - val kycRefId = UserWalletId(walletPublicKey).stringValue + val kycRefId = UserWalletIdBuilder.walletPublicKey(walletPublicKey).stringValue val requestUrl: String = makeWebRequestUrl(kycProvider) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt index e25117369f..90ebec0825 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt @@ -4,6 +4,7 @@ import com.tangem.Message import com.tangem.blockchain.common.Amount import com.tangem.blockchain.extensions.successOr import com.tangem.common.Filter +import com.tangem.common.core.TangemSdkError import com.tangem.common.extensions.guard import com.tangem.common.services.Result import com.tangem.core.analytics.Analytics @@ -199,7 +200,11 @@ private fun handleOnboardingSaltPayAction(anyAction: Action, appState: () -> App } state.saltPayManager.claim(amountToClaim.value!!, signer).successOr { dispatchOnMain(OnboardingSaltPayAction.SetStep(SaltPayActivationStep.Claim)) - onException(it.error) + if (it.error is TangemSdkError.UserCancelled) { + handleInProgress = false + } else { + onException(it.error) + } return@launch } @@ -278,6 +283,7 @@ suspend fun SaltPayActivationManager.update( val registrationResponse = checkRegistration().successOr { return it } val amountToClaim = getAmountToClaimIfNeeded(this, currentAmountToClaim) + dispatchOnMain(OnboardingSaltPayAction.SetAmountToClaim(amountToClaim)) val newStep = try { determineStep(currentStep, amountToClaim, registrationResponse) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayState.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayState.kt index 6a556ebb91..344834807f 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayState.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayState.kt @@ -67,14 +67,10 @@ data class OnboardingSaltPayState( if (!scanResponse.cardTypesResolver.isSaltPay()) { throw IllegalArgumentException("Can't initialize the OnboardingSaltPayMiddleware if card is not SalPay") } - val saltPaySingleWallet = scanResponse.card.wallets.firstOrNull().guard { - throw NullPointerException("SaltPay card must have one wallet at least") - } return SaltPayActivationManager( cardId = scanResponse.card.cardId, cardPublicKey = scanResponse.card.cardPublicKey, - walletPublicKey = saltPaySingleWallet.publicKey, kycProvider = kycProvider, paymentologyService = paymentologyService, gnosisRegistrator = gnosisRegistrator, diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/ui/OnboardingSaltPayView.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/ui/OnboardingSaltPayView.kt index 8614da5fd0..d4549041e1 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/ui/OnboardingSaltPayView.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/ui/OnboardingSaltPayView.kt @@ -103,7 +103,7 @@ internal class OnboardingSaltPayView( val uri = Uri.parse(state.onboardingSaltPayState.saltPayCardArtworkUrl) walletFragment.loadImageIntoImageView(uri, imvFrontCard) } - imvFirstBackupCard.load(R.drawable.card_placeholder_wallet) + imvFirstBackupCard.load(R.drawable.img_salt_pay_visa) // if (state.onboardingSaltPayState?.saltPayCardArtworkUrl == null) { // //if saltPay url not loaded -> load from resource diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt index 611c9d8bc4..d2202cc249 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt @@ -105,7 +105,7 @@ class OnboardingWalletFragment : BaseFragment(R.layout.fragment_onboarding_walle cardsWidget.toFolded(false) if (viewBackupCount > backupCardsCounts) { - flCardsContainer.removeViewAt(viewBackupCount - 1) + flCardsContainer.removeViews(0, viewBackupCount - backupCardsCounts) } else { flCardsContainer.inflate(R.layout.view_onboarding_card, true) } @@ -115,7 +115,12 @@ class OnboardingWalletFragment : BaseFragment(R.layout.fragment_onboarding_walle } private fun createLeapfrogWidget(container: FrameLayout, deviceScaleFactor: Float): LeapfrogWidget { - val leapfrogCalculator = PropertyCalculator(yTranslationFactor = 25f * deviceScaleFactor) + val leapfrogCalculator = PropertyCalculator( + yTranslationFactor = when (container.childCount) { + 3 -> 25f + else -> 35f + } * deviceScaleFactor, + ) return LeapfrogWidget(container, leapfrogCalculator) } diff --git a/buildSrc/src/main/java/Versions.kt b/buildSrc/src/main/java/Versions.kt index 4c2bb90b8e..0a9a6e9661 100644 --- a/buildSrc/src/main/java/Versions.kt +++ b/buildSrc/src/main/java/Versions.kt @@ -61,7 +61,7 @@ object Versions { // endregion Other libraries // region Tangem - const val tangemBlockchainSdk = "develop-154" + const val tangemBlockchainSdk = "develop-155" // const val tangemBlockchainSdk = "0.0.1" // Keep it! - used for local builds const val tangemCardSdk = "develop-186" diff --git a/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt b/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt index 05e17fa6c4..f0ef4a65fc 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt @@ -80,11 +80,11 @@ internal class ConfigManagerImpl @Inject constructor() : ConfigManager { authToken = configValues.blockchairAuthorizationToken, ), blockcypherTokens = configValues.blockcypherTokens, - quickNodeCredentials = QuickNodeCredentials( + quickNodeSolanaCredentials = QuickNodeCredentials( apiKey = configValues.quiknodeApiKey, subdomain = configValues.quiknodeSubdomain, ), - bscQuickNodeCredentials = QuickNodeCredentials( + quickNodeBscCredentials = QuickNodeCredentials( apiKey = configValues.bscQuiknodeApiKey, subdomain = configValues.bscQuiknodeSubdomain, ), diff --git a/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt b/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt index ad23a4379d..88268d02de 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt @@ -24,6 +24,8 @@ class ConfigValueModel( val quiknodeApiKey: String, val bscQuiknodeSubdomain: String, val bscQuiknodeApiKey: String, + val nowNodesApiKey: String, + val getBlockApiKey: String, val blockcypherTokens: Set?, val infuraProjectId: String?, val appsFlyer: AppsFlyer, diff --git a/core/res/src/main/res/values-it/strings.xml b/core/res/src/main/res/values-it/strings.xml index 50874e78ca..fd7be8b8db 100644 --- a/core/res/src/main/res/values-it/strings.xml +++ b/core/res/src/main/res/values-it/strings.xml @@ -134,13 +134,13 @@ To access all the networks you need to scan the card Scan your card Tokens - You have to set up a single access code to protect all your wallets. + You have to set up a single access code to protect all your wallets Protect - You can set an individual access code on each card later. + You can set up an individual access code on each card later Personalize - The access code can be restored with a linked card, don\'t keep all cards in one place. + The access code can be restored with a linked card, don\'t keep all cards in one place Restore - Choose any word, phrase, or number you want as your access code. + Choose any word, phrase, or number you want as your access code Create Access Code Re-enter your Access Code Access code must be at least 4 characters long @@ -178,7 +178,7 @@ Connect Creating a backup Tap the SaltPay card - To start the backup process you have to add Tangem card as your backup + To start the backup process you have to add the Tangem card as your backup Finalize the backup process by creating an access code Tap the Tangem card No backup card @@ -219,7 +219,7 @@ Show the wallet\'s address Top up your wallet The twinning process is partly complete. You can\'t exit it now. - If the process of creating the wallet gets interrupted in any way, you\'ll have to start over. + If the process of creating the wallet gets interrupted in any way, you\'ll have to start over You can backup your keys up to two other blank Tangem Wallet cards. Access code can be restored with one of backup cards. All the backup cards can be used as full-functional with the identical keys.