diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index a005e3f952..6a80a26d24 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -4,7 +4,6 @@ import android.content.Intent import android.content.pm.ActivityInfo import android.os.Bundle import android.view.View -import android.view.Window import androidx.appcompat.app.AppCompatActivity import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsControllerCompat @@ -26,7 +25,6 @@ import com.tangem.tap.common.shop.GooglePayService import com.tangem.tap.common.shop.GooglePayService.Companion.LOAD_PAYMENT_DATA_REQUEST_CODE import com.tangem.tap.common.shop.googlepay.GooglePayUtil.createPaymentsClient import com.tangem.tap.domain.TangemSdkManager -import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction import com.tangem.tap.features.shop.redux.ShopAction import com.tangem.wallet.R import com.tangem.wallet.databinding.ActivityMainBinding @@ -67,7 +65,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler { backupService = BackupService.init(tangemSdk, this) store.dispatch(GlobalAction.SetResources(getAndroidResources())) - store.dispatch(WalletConnectAction.RestoreSessions) store.dispatch( ShopAction.CheckIfGooglePayAvailable( GooglePayService(createPaymentsClient(this), this) diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index 08da1e8b3b..ca63f4a459 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -1,17 +1,17 @@ package com.tangem.tap import android.app.Application +import android.content.Context +import android.content.pm.PackageManager import coil.ImageLoader import coil.ImageLoaderFactory import com.appsflyer.AppsFlyerLib -import com.google.firebase.ktx.Firebase -import com.google.firebase.remoteconfig.ktx.remoteConfig -import com.google.firebase.remoteconfig.ktx.remoteConfigSettings import com.tangem.Log import com.tangem.LogFormat import com.tangem.blockchain.network.BlockchainSdkRetrofitBuilder import com.tangem.domain.DomainLayer import com.tangem.network.common.MoshiConverter +import com.tangem.tap.common.AndroidAssetReader import com.tangem.tap.common.analytics.GlobalAnalyticsHandler import com.tangem.tap.common.feedback.AdditionalFeedbackInfo import com.tangem.tap.common.feedback.FeedbackManager @@ -21,10 +21,9 @@ import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.appReducer import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.common.shop.TangemShopService +import com.tangem.tap.domain.configurable.config.Config import com.tangem.tap.domain.configurable.config.ConfigManager import com.tangem.tap.domain.configurable.config.FeaturesLocalLoader -import com.tangem.tap.domain.configurable.config.FeaturesRemoteLoader -import com.tangem.tap.domain.configurable.warningMessage.RemoteWarningLoader import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager import com.tangem.tap.domain.tokens.CurrenciesRepository import com.tangem.tap.domain.walletconnect.WalletConnectRepository @@ -37,7 +36,7 @@ import timber.log.Timber val store = Store( reducer = ::appReducer, middleware = AppState.getMiddleware(), - state = AppState() + state = AppState(), ) val logConfig = LogConfig() @@ -49,101 +48,100 @@ lateinit var walletConnectRepository: WalletConnectRepository lateinit var shopService: TangemShopService class TapApplication : Application(), ImageLoaderFactory { + override fun onCreate() { super.onCreate() - DomainLayer.init() if (BuildConfig.DEBUG) { Timber.plant(Timber.DebugTree()) - Firebase.remoteConfig.setConfigSettingsAsync(remoteConfigSettings { - this.minimumFetchIntervalInSeconds = 60 - }) - } else { - Firebase.remoteConfig.setConfigSettingsAsync(remoteConfigSettings { - this.minimumFetchIntervalInSeconds = 3600 - }) } - NetworkConnectivity.createInstance(store, this) - preferencesStorage = PreferencesStorage(this) - currenciesRepository = CurrenciesRepository( - this, store.state.domainNetworks.tangemTechService - ) - walletConnectRepository = WalletConnectRepository(this) - foregroundActivityObserver = ForegroundActivityObserver() registerActivityLifecycleCallbacks(foregroundActivityObserver.callbacks) - initFeedbackManager() - loadConfigs() + + DomainLayer.init() + NetworkConnectivity.createInstance(store, this) + preferencesStorage = PreferencesStorage(this) + currenciesRepository = CurrenciesRepository(this, store.state.domainNetworks.tangemTechService) + walletConnectRepository = WalletConnectRepository(this) + + val configLoader = FeaturesLocalLoader(AndroidAssetReader(this), MoshiConverter.defaultMoshi()) + initConfigManager(configLoader, ::initWithConfigDependency) + initWarningMessagesManager() BlockchainSdkRetrofitBuilder.enableNetworkLogging = BuildConfig.DEBUG - - initAppsFlyer() } override fun newImageLoader(): ImageLoader { return createCoilImageLoader(context = this) } - private fun loadConfigs() { - val moshi = MoshiConverter.defaultMoshi() - val localLoader = FeaturesLocalLoader(this, moshi) - val remoteLoader = FeaturesRemoteLoader(moshi) - val configManager = ConfigManager(localLoader, remoteLoader) - configManager.load { config -> + private fun initConfigManager(loader: FeaturesLocalLoader, onComplete: (Config) -> Unit) { + val configManager = ConfigManager() + configManager.load(loader) { config -> store.dispatch(GlobalAction.SetConfigManager(configManager)) - shopService = TangemShopService( - application = this, - shopifyShop = config.shopify!! - ) - store.state.globalState.feedbackManager?.initChat( - context = this, - zendeskConfig = config.zendesk!! - ) + onComplete(config) } - val warningsManager = WarningMessagesManager(RemoteWarningLoader(moshi)) - warningsManager.load { store.dispatch(GlobalAction.SetWarningManager(warningsManager)) } } - private fun initFeedbackManager() { - val infoHolder = AdditionalFeedbackInfo() - infoHolder.setAppVersion(this) - - val logLevels = listOf( - Log.Level.ApduCommand, - Log.Level.Apdu, - Log.Level.Tlv, - Log.Level.Nfc, - Log.Level.Command, - Log.Level.Session, - Log.Level.View, - Log.Level.Network, - Log.Level.Error, - ) - val logWriter = TangemLogCollector( - levels = logLevels, - messageFormatter = LogFormat.StairsFormatter(), - ) - Log.addLogger(logWriter) - - store.dispatch( - GlobalAction.SetFeedbackManager( - FeedbackManager( - infoHolder = infoHolder, - logCollector = logWriter, - preferencesStorage = preferencesStorage, - ), - ), - ) + private fun initWithConfigDependency(config: Config) { + shopService = TangemShopService(this, config.shopify!!) + initAppsFlyer(this, config) + initFeedbackManager(this, preferencesStorage, config) } - private fun initAppsFlyer() { - val devKey = store.state.globalState.configManager?.config?.appsFlyerDevKey ?: return - AppsFlyerLib.getInstance().init(devKey, null, this) - AppsFlyerLib.getInstance().start(this) - val analyticsHandler = GlobalAnalyticsHandler.createDefaultAnalyticHandlers(this) + private fun initAppsFlyer(context: Context, config: Config) { + AppsFlyerLib.getInstance().init(config.appsFlyerDevKey, null, context) + AppsFlyerLib.getInstance().start(context) + val analyticsHandler = GlobalAnalyticsHandler.createDefaultAnalyticHandlers(context) store.dispatch(GlobalAction.SetAnanlyticHandlers(analyticsHandler)) } + + private fun initFeedbackManager(context: Context, preferencesStorage: PreferencesStorage, config: Config) { + fun initAdditionalFeedbackInfo(context: Context): AdditionalFeedbackInfo = AdditionalFeedbackInfo().apply { + appVersion = try { + val pInfo = context.packageManager.getPackageInfo(context.packageName, 0) + pInfo.versionName + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + "x.y.z" + } + } + + fun initTangemLogCollector(): TangemLogCollector { + val logLevels = listOf( + Log.Level.ApduCommand, + Log.Level.Apdu, + Log.Level.Tlv, + Log.Level.Nfc, + Log.Level.Command, + Log.Level.Session, + Log.Level.View, + Log.Level.Network, + Log.Level.Error, + ) + return TangemLogCollector(logLevels, LogFormat.StairsFormatter()) + } + + val additionalFeedbackInfo = initAdditionalFeedbackInfo(context) + val tangemLogCollector = initTangemLogCollector() + Log.addLogger(tangemLogCollector) + + val feedbackManager = FeedbackManager( + infoHolder = additionalFeedbackInfo, + logCollector = tangemLogCollector, + preferencesStorage = preferencesStorage, + ) + feedbackManager.initChat( + context = context, + zendeskConfig = config.zendesk!!, + ) + store.dispatch(GlobalAction.SetFeedbackManager(feedbackManager)) + } + + private fun initWarningMessagesManager() { + store.dispatch(GlobalAction.SetWarningManager(WarningMessagesManager())) + } } data class LogConfig( diff --git a/app/src/main/java/com/tangem/tap/common/AssetReader.kt b/app/src/main/java/com/tangem/tap/common/AssetReader.kt new file mode 100644 index 0000000000..3f5eb10dd9 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/AssetReader.kt @@ -0,0 +1,20 @@ +package com.tangem.tap.common + +import android.content.Context +import com.tangem.tap.common.extensions.readAssetAsString + +/** +[REDACTED_AUTHOR] + */ +interface AssetReader { + fun readAssetAsString(name: String): String +} + +class AndroidAssetReader( + private val context: Context, +) : AssetReader { + + override fun readAssetAsString(name: String): String { + return context.readAssetAsString(name) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/DialogManager.kt b/app/src/main/java/com/tangem/tap/common/DialogManager.kt index 96cf1b874b..ef357f782f 100644 --- a/app/src/main/java/com/tangem/tap/common/DialogManager.kt +++ b/app/src/main/java/com/tangem/tap/common/DialogManager.kt @@ -113,7 +113,6 @@ class DialogManager : StoreSubscriber { data = state.dialog.data, session = state.dialog.session, sessionId = state.dialog.sessionId, - cardId = state.dialog.cardId, dAppName = state.dialog.dAppName, context = context, ) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/AppsFlyerAnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/AppsFlyerAnalyticsHandler.kt index 64beb11b4a..16fa1644ab 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/AppsFlyerAnalyticsHandler.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/AppsFlyerAnalyticsHandler.kt @@ -1,6 +1,6 @@ package com.tangem.tap.common.analytics -import android.app.Application +import android.content.Context import com.appsflyer.AFInAppEventParameterName import com.appsflyer.AFInAppEventType import com.appsflyer.AppsFlyerLib @@ -8,7 +8,7 @@ import com.shopify.buy3.Storefront import com.tangem.common.card.Card import com.tangem.common.core.TangemSdkError -class AppsFlyerAnalyticsHandler(val context: Application): AnalyticsHandler() { +class AppsFlyerAnalyticsHandler(val context: Context): AnalyticsHandler() { override fun triggerEvent( event: AnalyticsEvent, @@ -16,8 +16,7 @@ class AppsFlyerAnalyticsHandler(val context: Application): AnalyticsHandler() { blockchain: String?, params: Map ) { - AppsFlyerLib.getInstance().logEvent(context, - event.event, prepareParams(card, blockchain)) + AppsFlyerLib.getInstance().logEvent(context, event.event, prepareParams(card, blockchain)) } override fun logCardSdkError( diff --git a/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsHandler.kt index c500f330b2..197f396621 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsHandler.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsHandler.kt @@ -1,6 +1,6 @@ package com.tangem.tap.common.analytics -import android.app.Application +import android.content.Context import com.shopify.buy3.Storefront import com.tangem.common.card.Card import com.tangem.common.core.TangemSdkError @@ -42,7 +42,7 @@ class GlobalAnalyticsHandler(val analyticsHandlers: List) : } companion object { - fun createDefaultAnalyticHandlers(context: Application): GlobalAnalyticsHandler { + fun createDefaultAnalyticHandlers(context: Context): GlobalAnalyticsHandler { return GlobalAnalyticsHandler( listOf( FirebaseAnalyticsHandler, diff --git a/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt b/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt index ddc7a41b23..70912f24a6 100644 --- a/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt +++ b/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt @@ -1,7 +1,5 @@ package com.tangem.tap.common.feedback -import android.content.Context -import android.content.pm.PackageManager import android.os.Build import com.tangem.blockchain.common.Amount import com.tangem.blockchain.common.AmountType @@ -45,15 +43,6 @@ class AdditionalFeedbackInfo { var fee: String = "" var token: String = "" - fun setAppVersion(context: Context) { - try { - val pInfo = context.packageManager.getPackageInfo(context.packageName, 0) - appVersion = pInfo.versionName - } catch (e: PackageManager.NameNotFoundException) { - e.printStackTrace() - } - } - fun setCardInfo(data: ScanResponse) { cardId = data.card.cardId cardBlockchain = data.walletData?.blockchain ?: "" diff --git a/app/src/main/java/com/tangem/tap/domain/TapErrors.kt b/app/src/main/java/com/tangem/tap/domain/TapErrors.kt index 45a963ddaa..8219a52319 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapErrors.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapErrors.kt @@ -31,13 +31,13 @@ sealed class TapError( object InsufficientBalance : TapError(R.string.send_error_insufficient_balance) object BlockchainInternalError : TapError(R.string.send_error_blockchain_internal) object AmountExceedsBalance : TapError(R.string.send_validation_amount_exceeds_balance) + data class AmountLowerExistentialDeposit(override val args: List) : TapError(R.string.send_error_minimum_balance_format) object FeeExceedsBalance : TapError(R.string.send_validation_invalid_fee) object TotalExceedsBalance : TapError(R.string.send_validation_invalid_total) object InvalidAmountValue : TapError(R.string.send_validation_invalid_amount) object InvalidFeeValue : TapError(R.string.send_error_invalid_fee_value) data class DustAmount(override val args: List) : TapError(R.string.send_error_dust_amount_format) object DustChange : TapError(R.string.send_error_dust_change) - data class CreateAccountUnderfunded(override val args: List) : TapError(R.string.send_error_no_target_account) data class UnsupportedState( val stateError: String, diff --git a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt index 16ab2b0629..507e6023d4 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -23,6 +23,7 @@ import com.tangem.tap.domain.extensions.makePrimaryWalletManager import com.tangem.tap.domain.extensions.makeWalletManagersForApp import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.demo.isDemoCard +import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.network.NetworkConnectivity import com.tangem.tap.store @@ -88,14 +89,16 @@ class TapWalletManager { withMainContext { store.dispatch(WalletAction.ResetState(data.card.cardId)) + store.dispatch(WalletConnectAction.ResetState) store.dispatch(GlobalAction.SaveScanNoteResponse(data)) store.dispatch(WalletAction.SetIfTestnetCard(data.card.isTestCard)) store.dispatch(WalletAction.MultiWallet.SetIsMultiwalletAllowed(data.card.isMultiwalletAllowed)) + store.dispatch(WalletConnectAction.RestoreSessions(data)) store.dispatch( WalletAction.MultiWallet.ShowWalletBackupWarning( show = data.card.settings.isBackupAllowed - && data.card.backupStatus == Card.BackupStatus.NoBackup - ) + && data.card.backupStatus == Card.BackupStatus.NoBackup, + ), ) loadData(data) } diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigLoaders.kt b/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigLoaders.kt index 4c19bab889..ba33d98210 100644 --- a/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigLoaders.kt +++ b/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigLoaders.kt @@ -1,12 +1,8 @@ package com.tangem.tap.domain.configurable.config -import android.content.Context -import com.google.firebase.ktx.Firebase -import com.google.firebase.remoteconfig.ktx.remoteConfig import com.squareup.moshi.JsonAdapter import com.squareup.moshi.Moshi -import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler -import com.tangem.tap.common.extensions.readAssetAsString +import com.tangem.tap.common.AssetReader import com.tangem.tap.domain.configurable.Loader import timber.log.Timber @@ -14,8 +10,8 @@ import timber.log.Timber [REDACTED_AUTHOR] */ class FeaturesLocalLoader( - private val context: Context, - private val moshi: Moshi, + private val assetReader: AssetReader, + private val moshi: Moshi, ) : Loader { override fun load(onComplete: (ConfigModel) -> Unit) { @@ -23,8 +19,8 @@ class FeaturesLocalLoader( val featureAdapter: JsonAdapter = moshi.adapter(FeatureModel::class.java) val valuesAdapter: JsonAdapter = moshi.adapter(ConfigValueModel::class.java) - val jsonFeatures = context.readAssetAsString(Loader.featuresName) - val jsonConfigValues = context.readAssetAsString(Loader.configValuesName) + val jsonFeatures = assetReader.readAssetAsString(Loader.featuresName) + val jsonConfigValues = assetReader.readAssetAsString(Loader.configValuesName) ConfigModel(featureAdapter.fromJson(jsonFeatures), valuesAdapter.fromJson(jsonConfigValues)) } catch (ex: Exception) { @@ -33,31 +29,4 @@ class FeaturesLocalLoader( } onComplete(config) } -} - -class FeaturesRemoteLoader( - private val moshi: Moshi, -) : Loader { - - override fun load(onComplete: (ConfigModel) -> Unit) { - val emptyConfig = ConfigModel.empty() - val remoteConfig = Firebase.remoteConfig - remoteConfig.fetchAndActivate().addOnCompleteListener { - if (it.isSuccessful) { - val config = remoteConfig.getValue(Loader.featuresName) - val jsonConfig = config.asString() - if (jsonConfig.isEmpty()) { - onComplete(emptyConfig) - return@addOnCompleteListener - } - val featureAdapter: JsonAdapter = moshi.adapter(FeatureModel::class.java) - onComplete(ConfigModel(featureAdapter.fromJson(jsonConfig), null)) - } else { - onComplete(emptyConfig) - } - }.addOnFailureListener { - FirebaseAnalyticsHandler.logException("remote_config_error.features", it) - onComplete(emptyConfig) - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt b/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt index bb94004636..62f367cb33 100644 --- a/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt @@ -24,26 +24,19 @@ data class Config( val zendesk: ZendeskConfig? = null, ) -class ConfigManager( - private val localLoader: Loader, - private val remoteLoader: Loader -) { +class ConfigManager { var config: Config = Config() private set private var defaultConfig = Config() - fun load(onComplete: ((config: Config) -> Unit)? = null) { - localLoader.load { configModel -> + fun load(configLoader: Loader, onComplete: ((config: Config) -> Unit)? = null) { + configLoader.load { configModel -> setupFeature(configModel.features) setupKey(configModel.configValues) onComplete?.invoke(config) } - // Uncomment to enable remote config -// remoteLoader.load { config -> -// setupFeature(config.features) -// } } fun turnOff(name: String) { diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningLoader.kt b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningLoader.kt deleted file mode 100644 index c95fc39a24..0000000000 --- a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningLoader.kt +++ /dev/null @@ -1,52 +0,0 @@ -package com.tangem.tap.domain.configurable.warningMessage - -import com.google.firebase.ktx.Firebase -import com.google.firebase.remoteconfig.ktx.remoteConfig -import com.squareup.moshi.JsonAdapter -import com.squareup.moshi.Moshi -import com.squareup.moshi.Types -import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler -import com.tangem.tap.domain.configurable.Loader - -/** -[REDACTED_AUTHOR] - */ -class RemoteWarningLoader( - private val moshi: Moshi, -) : Loader> { - - override fun load(onComplete: (List) -> Unit) { - val emptyConfig = listOf() - val remoteConfig = Firebase.remoteConfig - remoteConfig.fetchAndActivate().addOnCompleteListener { - if (!it.isSuccessful) { - onComplete(emptyConfig) - return@addOnCompleteListener - } - - val config = remoteConfig.getValue(Loader.warnings) - val jsonConfig = config.asString() - if (jsonConfig.isEmpty()) { - onComplete(emptyConfig) - return@addOnCompleteListener - } - - val adapterType = Types.newParameterizedType(List::class.java, WarningMessage::class.java) - val warningsAdapter: JsonAdapter> = moshi.adapter(adapterType) - try { - val warnings = warningsAdapter.fromJson(jsonConfig) ?: listOf() - onComplete(warnings) - } catch (ex: Exception) { - handleError(ex) - onComplete(emptyConfig) - } - }.addOnFailureListener { - handleError(it) - onComplete(emptyConfig) - } - } - - private fun handleError(ex: Exception) { - FirebaseAnalyticsHandler.logException("remote_config_error.warnings", ex) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt index 10dbcb2cbb..683302ba73 100644 --- a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt @@ -1,35 +1,17 @@ package com.tangem.tap.domain.configurable.warningMessage import com.tangem.blockchain.common.Blockchain -import com.tangem.common.extensions.VoidCallback import com.tangem.tap.common.extensions.containsAny import com.tangem.tap.common.extensions.removeBy -import com.tangem.wallet.BuildConfig import com.tangem.wallet.R /** [REDACTED_AUTHOR] */ -class WarningMessagesManager( - private val warningLoader: RemoteWarningLoader, -) { +class WarningMessagesManager { private val warningsList: MutableList = mutableListOf() - fun load(onComplete: VoidCallback? = null) { - // exclude annoying remote debug warnings - if (BuildConfig.DEBUG) { - onComplete?.invoke() - return - } - warningLoader.load { remoteList -> - warningsList.clear() - warningsList.addAll(remoteList) - sortByPriority() - onComplete?.invoke() - } - } - fun addWarning(warning: WarningMessage) { if (findWarning(warning) == null) { warningsList.add(warning) @@ -37,7 +19,10 @@ class WarningMessagesManager( } } - fun getWarnings(location: WarningMessage.Location, forBlockchains: List = emptyList()): List { + fun getWarnings( + location: WarningMessage.Location, + forBlockchains: List = emptyList(), + ): List { return warningsList .filter { !it.isHidden && it.location.contains(location) } .filter { @@ -94,7 +79,7 @@ class WarningMessagesManager( null, R.string.alert_title, R.string.alert_developer_card, - WarningMessage.Origin.Local + WarningMessage.Origin.Local, ) fun alreadySignedHashesWarning(): WarningMessage = WarningMessage( @@ -106,7 +91,7 @@ class WarningMessagesManager( null, R.string.alert_title, R.string.alert_card_signed_transactions, - WarningMessage.Origin.Local + WarningMessage.Origin.Local, ) fun signedHashesMultiWalletWarning(): WarningMessage = WarningMessage( @@ -131,7 +116,7 @@ class WarningMessagesManager( null, R.string.warning_rate_app_title, R.string.warning_rate_app_message, - WarningMessage.Origin.Local + WarningMessage.Origin.Local, ) fun isAlreadySignedHashesWarning(warning: WarningMessage): Boolean { @@ -147,7 +132,7 @@ class WarningMessagesManager( null, R.string.warning_failed_to_verify_card_title, R.string.warning_failed_to_verify_card_message, - WarningMessage.Origin.Local + WarningMessage.Origin.Local, ) fun remainingSignaturesNotEnough(remainingSignatures: Int): WarningMessage = WarningMessage( @@ -160,7 +145,7 @@ class WarningMessagesManager( titleResId = R.string.alert_title, messageResId = R.string.warning_low_signatures_format, origin = WarningMessage.Origin.Local, - messageFormatArg = remainingSignatures.toString() + messageFormatArg = remainingSignatures.toString(), ) fun testCardWarning(): WarningMessage = WarningMessage( @@ -172,7 +157,7 @@ class WarningMessagesManager( null, R.string.alert_title, R.string.warning_testnet_card_message, - WarningMessage.Origin.Local + WarningMessage.Origin.Local, ) fun demoCardWarning(): WarningMessage = WarningMessage( @@ -184,7 +169,7 @@ class WarningMessagesManager( null, R.string.alert_title, R.string.alert_demo_message, - WarningMessage.Origin.Local + WarningMessage.Origin.Local, ) const val REMAINING_SIGNATURES_WARNING = 10 diff --git a/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt index 43c91a54fb..1d02623442 100644 --- a/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt @@ -13,6 +13,7 @@ import com.tangem.common.extensions.toHexString import com.tangem.domain.common.ScanResponse import com.tangem.network.common.MoshiConverter import com.tangem.operations.wallet.CreateWalletResponse +import com.tangem.tap.common.AssetReader import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.AnalyticsHandler import com.tangem.tap.tangemSdkManager @@ -119,10 +120,6 @@ class TwinCardsManager( } } -interface AssetReader { - fun readAssetAsString(name: String): String -} - private class Issuer( val id: String, val privateKey: String, diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectManager.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectManager.kt index 7e4fae297a..45c3dee2e3 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectManager.kt @@ -1,7 +1,9 @@ package com.tangem.tap.domain.walletconnect import com.tangem.blockchain.common.Blockchain +import com.tangem.common.card.EllipticCurve import com.tangem.common.extensions.guard +import com.tangem.domain.common.ScanResponse import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.redux.global.GlobalAction @@ -69,7 +71,7 @@ class WalletConnectManager { remotePeerId = null, session = session, client = client, - wallet = WalletForSession(cardId = "") + wallet = WalletForSession(), ) setupConnectionTimeoutCheck(session) } @@ -110,8 +112,12 @@ class WalletConnectManager { } } - fun restoreSessions() { + fun restoreSessions(scanResponse: ScanResponse) { + val walletPublicKey = scanResponse.card.wallets.firstOrNull { it.curve == EllipticCurve.Secp256k1 }?.publicKey + ?: return val sessions = walletConnectRepository.loadSavedSessions() + // filter sessions for this particular card + .filter { it.wallet.walletPublicKey.contentEquals(walletPublicKey) } this.sessions = sessions .map { session -> WalletConnectActiveData( @@ -126,8 +132,8 @@ class WalletConnectManager { setListeners(it.client) it.client.connect(it.session, tangemPeerMeta, it.peerId, it.remotePeerId) } - } - .map { it.session to it }.toMap().toMutableMap() + }.associateBy { it.session }.toMutableMap() + store.dispatchOnMain(WalletConnectAction.SetSessionsRestored(sessions)) } diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectNetworkUtils.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectNetworkUtils.kt index 3da00c517b..6b2a457e43 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectNetworkUtils.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectNetworkUtils.kt @@ -12,6 +12,9 @@ class WalletConnectNetworkUtils { peer: WCPeerMeta, ): Blockchain? { return when { + peer.url.contains("pancakeswap.finance") -> { + Blockchain.BSC + } chainId != null -> { Blockchain.fromChainId(chainId) } 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 04f1ec8141..b23a5e1456 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 @@ -92,7 +92,6 @@ class WalletConnectSdkHelper { ) ) val dialogData = TransactionRequestDialogData( - cardId = session.wallet.cardId, dAppName = session.peerMeta.name, dAppUrl = session.peerMeta.url, amount = value.toFormattedString(decimals), @@ -235,7 +234,6 @@ class WalletConnectSdkHelper { val dialogData = PersonalSignDialogData( - cardId = session.wallet.cardId, dAppName = session.peerMeta.name, message = messageString, session = session.session, @@ -272,11 +270,11 @@ class WalletConnectSdkHelper { suspend fun signPersonalMessage(hashToSign: ByteArray, wallet: WalletForSession): String? { val key = wallet.derivedPublicKey ?: wallet.walletPublicKey val command = SignHashCommand(hashToSign, wallet.walletPublicKey!!, wallet.derivationPath) - return when (val result = tangemSdkManager.runTaskAsync(command, wallet.cardId)) { + return when (val result = tangemSdkManager.runTaskAsync(command)) { is CompletionResult.Success -> { val hash = result.data.signature return EthereumUtils.prepareSignedMessageData( - hash, hashToSign, CryptoUtils.decompressPublicKey(key!!) + hash, hashToSign, CryptoUtils.decompressPublicKey(key!!), ) } is CompletionResult.Failure -> { diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect/WcWalletManagerFactory.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect/WcWalletManagerFactory.kt index 72134d880b..144f3b873d 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect/WcWalletManagerFactory.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect/WcWalletManagerFactory.kt @@ -1,13 +1,10 @@ package com.tangem.tap.domain.walletconnect import com.tangem.blockchain.common.Blockchain -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.domain.common.ScanResponse import com.tangem.domain.common.TapWorkarounds.isTestCard -import com.tangem.tap.domain.extensions.getPrimaryCurve import com.tangem.tap.domain.extensions.makeWalletManagerForApp import com.tangem.tap.domain.tokens.CurrenciesRepository import com.tangem.tap.domain.tokens.models.BlockchainNetwork @@ -17,51 +14,25 @@ import com.tangem.tap.features.wallet.redux.WalletState class WcWalletManagerFactory( private val factory: WalletManagerFactory, private val currenciesRepository: CurrenciesRepository, - ) { - - suspend fun getWalletManager( - wallet: WalletForSession, blockchain: Blockchain, walletState: WalletState +) { + fun getWalletManager( + wallet: WalletForSession, blockchain: Blockchain, walletState: WalletState, ): WalletManager? { val blockchainToMake = if (blockchain == Blockchain.Ethereum && wallet.isTestNet) { Blockchain.EthereumTestnet } else { blockchain } - val blockchainNetwork = BlockchainNetwork( blockchain = blockchainToMake, derivationPath = wallet.derivationPath?.rawPath, - tokens = emptyList() + tokens = emptyList(), ) - - return if (walletState.cardId == wallet.cardId) { - walletState.getWalletManager(blockchainNetwork) - } else { - val blockchainNetworkWithTokens = currenciesRepository - .loadSavedCurrencies( - cardId = wallet.cardId, - isHdWalletSupported = wallet.derivationPath != null - ).firstOrNull { it == blockchainNetwork } - - if (blockchainNetworkWithTokens != null) { - factory.makeWalletManager( - blockchain = blockchainToMake, - publicKey = Wallet.PublicKey( - wallet.walletPublicKey!!, - wallet.derivedPublicKey, - wallet.derivationPath - ), - tokens = blockchainNetworkWithTokens.tokens, - curve = blockchainToMake.getPrimaryCurve() ?: EllipticCurve.Secp256k1 - ) - } else { - null - } - } + return walletState.getWalletManager(blockchainNetwork) } suspend fun getWalletManager( - scanResponse: ScanResponse, blockchain: Blockchain, walletState: WalletState + scanResponse: ScanResponse, blockchain: Blockchain, walletState: WalletState, ): WalletManager? { val card = scanResponse.card val blockchainToMake = if (blockchain == Blockchain.Ethereum && card.isTestCard) { @@ -69,14 +40,13 @@ class WcWalletManagerFactory( } else { blockchain } - val blockchainNetwork = BlockchainNetwork( blockchain = blockchainToMake, - card = card + card = card, ) return if (walletState.cardId == card.cardId) { - walletState.getWalletManager(blockchainNetwork) + walletState.getWalletManager(blockchainNetwork) } else { if (currenciesRepository .loadSavedCurrencies(card.cardId, card.settings.isHDWalletAllowed) @@ -84,7 +54,7 @@ class WcWalletManagerFactory( ) { factory.makeWalletManagerForApp( scanResponse = scanResponse, - blockchainNetwork = blockchainNetwork + blockchainNetwork = blockchainNetwork, ) } else { null diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index 7825d58a8f..a465940186 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -98,14 +98,16 @@ class DetailsMiddleware { fun handle(action: DetailsAction.ResetToFactory) { when (action) { is DetailsAction.ResetToFactory.Start -> { - store.dispatch(NavigationAction.NavigateTo(AppScreen.ResetToFactory)) - } - is DetailsAction.ResetToFactory.Proceed -> { val card = store.state.detailsState.cardSettingsState?.card ?: return if (card.isTangemTwins()) { store.dispatch(DetailsAction.ReCreateTwinsWallet) return + } else { + store.dispatch(NavigationAction.NavigateTo(AppScreen.ResetToFactory)) } + } + is DetailsAction.ResetToFactory.Proceed -> { + val card = store.state.detailsState.cardSettingsState?.card ?: return scope.launch { val result = tangemSdkManager.resetToFactorySettings(card) withContext(Dispatchers.Main) { diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectAction.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectAction.kt index 14a871fbd9..0258af7316 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectAction.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectAction.kt @@ -1,6 +1,7 @@ package com.tangem.tap.features.details.redux.walletconnect import com.tangem.blockchain.common.Blockchain +import com.tangem.domain.common.ScanResponse import com.tangem.tap.common.redux.NotificationAction import com.tangem.wallet.R import com.trustwallet.walletconnect.models.binance.WCBinanceTradeOrder @@ -11,11 +12,9 @@ import com.trustwallet.walletconnect.models.session.WCSession import org.rekotlin.Action sealed class WalletConnectAction : Action { - + object ResetState : WalletConnectAction() data class HandleDeepLink(val wcUri: String?) : WalletConnectAction() - - object RestoreSessions : WalletConnectAction() - + data class RestoreSessions(val scanResponse: ScanResponse) : WalletConnectAction() data class StartWalletConnect( val copiedUri: String?, ) : WalletConnectAction() diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt index d98fb0b0f5..39529bf6f1 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt @@ -22,14 +22,13 @@ import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.wallet.redux.WalletState import com.tangem.tap.scope import com.tangem.tap.store -import com.tangem.wallet.R import kotlinx.coroutines.launch import org.rekotlin.Action import org.rekotlin.Middleware import timber.log.Timber class WalletConnectMiddleware { - private val walletConnectManager = WalletConnectManager() + private var walletConnectManager = WalletConnectManager() val walletConnectMiddleware: Middleware = { dispatch, state -> { next -> { action -> @@ -43,8 +42,9 @@ class WalletConnectMiddleware { if (DemoHelper.tryHandle(state, action)) return when (action) { + is WalletConnectAction.ResetState -> walletConnectManager = WalletConnectManager() is WalletConnectAction.RestoreSessions -> { - walletConnectManager.restoreSessions() + walletConnectManager.restoreSessions(action.scanResponse) } is WalletConnectAction.HandleDeepLink -> { if (!action.wcUri.isNullOrBlank()) { @@ -74,7 +74,13 @@ class WalletConnectMiddleware { is WalletConnectAction.ChooseNetwork -> { val data = state()?.walletConnectState?.newSessionData ?: return scope.launch { - prepareWalletManager(data.scanResponse, store.state.walletState, action.blockchain, data.session) + prepareWalletManager( + scanResponse = data.scanResponse, + walletState = store.state.walletState, + blockchain = action.blockchain, + session = data.session, + walletConnectManager = walletConnectManager, + ) } } is WalletConnectAction.ShowClipboardOrScanQrDialog -> { @@ -110,7 +116,8 @@ class WalletConnectMiddleware { ) } is WalletConnectAction.ScanCard -> { - scanCard(action.session, action.chainId) + val scanResponse = store.state.globalState.scanResponse ?: return + scanCard(scanResponse, action.session, action.chainId) } is WalletConnectAction.ApproveSession -> { walletConnectManager.approve(action.session) @@ -150,7 +157,6 @@ class WalletConnectMiddleware { data = messageData, session = action.sessionData.session, sessionId = action.id, - cardId = action.sessionData.wallet.cardId, dAppName = action.sessionData.peerMeta.name, ), ), @@ -164,7 +170,6 @@ class WalletConnectMiddleware { data = messageData, session = action.sessionData.session, sessionId = action.id, - cardId = action.sessionData.wallet.cardId, dAppName = action.sessionData.peerMeta.name, ), ), @@ -189,28 +194,26 @@ class WalletConnectMiddleware { currenciesRepository = currenciesRepository, ) val walletState = store.state.walletState - scope.launch { - val walletManager = factory.getWalletManager( - wallet = action.session.wallet, - blockchain = blockchain, - walletState = walletState, - ).guard { - store.dispatchOnMain( - GlobalAction.ShowDialog( - WalletConnectDialog.AddNetwork(blockchain.fullName), - ), - ) - return@launch - } - val updatedWallet = action.session.wallet.copy( - walletPublicKey = walletManager.wallet.publicKey.seedKey, - derivedPublicKey = walletManager.wallet.publicKey.derivedKey, - derivationPath = walletManager.wallet.publicKey.derivationPath, - blockchain = action.blockchain, + val walletManager = factory.getWalletManager( + wallet = action.session.wallet, + blockchain = blockchain, + walletState = walletState, + ).guard { + store.dispatchOnMain( + GlobalAction.ShowDialog( + WalletConnectDialog.AddNetwork(blockchain.fullName), + ), ) - val updatedSession = action.session.copy(wallet = updatedWallet) - store.dispatchOnMain(WalletConnectAction.UpdateBlockchain(updatedSession)) + return } + val updatedWallet = action.session.wallet.copy( + walletPublicKey = walletManager.wallet.publicKey.seedKey, + derivedPublicKey = walletManager.wallet.publicKey.derivedKey, + derivationPath = walletManager.wallet.publicKey.derivationPath, + blockchain = action.blockchain, + ) + val updatedSession = action.session.copy(wallet = updatedWallet) + store.dispatchOnMain(WalletConnectAction.UpdateBlockchain(updatedSession)) } is WalletConnectAction.UpdateBlockchain -> { walletConnectManager.updateBlockchain(action.updatedSession) @@ -218,24 +221,16 @@ class WalletConnectMiddleware { } } - private fun scanCard(session: WalletConnectSession, chainId: Int?) { + private fun scanCard(scanResponse: ScanResponse, session: WalletConnectSession, chainId: Int?) { val blockchain = WalletConnectNetworkUtils.parseBlockchain( chainId = chainId, peer = session.peerMeta, - ) ?: Blockchain.Ethereum + ).guard { + store.dispatchOnMain(GlobalAction.ShowDialog(WalletConnectDialog.UnsupportedNetwork)) + return + } - store.dispatch( - GlobalAction.ScanCard( - additionalBlockchainsToDerive = listOf(blockchain), - onSuccess = { scanResponse -> - handleScanResponse(scanResponse = scanResponse, session = session, blockchain = blockchain) - }, - onFailure = { - store.dispatchOnMain(WalletConnectAction.FailureEstablishingSession(null)) - }, - R.string.wallet_connect_scan_card_message, - ), - ) + handleScanResponse(scanResponse = scanResponse, session = session, blockchain = blockchain) } private suspend fun getAvailableBlockchains(card: Card, walletState: WalletState): List { @@ -259,6 +254,7 @@ class WalletConnectMiddleware { walletState: WalletState, blockchain: Blockchain, session: WalletConnectSession, + walletConnectManager: WalletConnectManager, ) { val factory = WcWalletManagerFactory( factory = store.state.globalState.tapWalletManager.walletManagerFactory, @@ -273,21 +269,20 @@ class WalletConnectMiddleware { ) return } - val wallet = walletManager.wallet - val derivedKey = - if (wallet.publicKey.blockchainKey.contentEquals(wallet.publicKey.seedKey)) { - null - } else { - walletManager.wallet.publicKey.blockchainKey - } - val walletForSession = WalletForSession( - cardId = scanResponse.card.cardId, - walletPublicKey = wallet.publicKey.seedKey, - derivedPublicKey = derivedKey, - derivationPath = wallet.publicKey.derivationPath, - derivationStyle = scanResponse.card.derivationStyle, - blockchain = wallet.blockchain, - ) + val wallet = walletManager.wallet + val derivedKey = + if (wallet.publicKey.blockchainKey.contentEquals(wallet.publicKey.seedKey)) { + null + } else { + walletManager.wallet.publicKey.blockchainKey + } + val walletForSession = WalletForSession( + walletPublicKey = wallet.publicKey.seedKey, + derivedPublicKey = derivedKey, + derivationPath = wallet.publicKey.derivationPath, + derivationStyle = scanResponse.card.derivationStyle, + blockchain = wallet.blockchain, + ) withMainContext { val updatedSession = session.copy(wallet = walletForSession) diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectReducer.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectReducer.kt index 544b6fa7be..e4cc76254c 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectReducer.kt @@ -10,6 +10,7 @@ class WalletConnectReducer { if (action !is WalletConnectAction) return state return when (action) { + is WalletConnectAction.ResetState -> return WalletConnectState() is WalletConnectAction.ApproveSession.Success -> { state.copy( loading = false, diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectState.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectState.kt index 0bdfaf69f6..97afb372a2 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectState.kt @@ -40,7 +40,6 @@ data class WalletConnectSession( @JsonClass(generateAdapter = true) data class WalletForSession( - val cardId: String, val walletPublicKey: ByteArray? = null, val derivedPublicKey: ByteArray? = null, val derivationPath: DerivationPath? = null, @@ -59,7 +58,6 @@ data class WalletForSession( other as WalletForSession - if (cardId != other.cardId) return false if (walletPublicKey != null) { if (other.walletPublicKey == null) return false if (!walletPublicKey.contentEquals(other.walletPublicKey)) return false @@ -76,8 +74,7 @@ data class WalletForSession( } override fun hashCode(): Int { - var result = cardId.hashCode() - result = 31 * result + (walletPublicKey?.contentHashCode() ?: 0) + var result = (walletPublicKey?.contentHashCode() ?: 0) result = 31 * result + (derivedPublicKey?.contentHashCode() ?: 0) result = 31 * result + (derivationPath?.hashCode() ?: 0) result = 31 * result + isTestNet.hashCode() @@ -112,7 +109,6 @@ sealed class WalletConnectDialog : StateDialog { val data: BinanceMessageData, val session: WCSession, val sessionId: Long, - val cardId: String, val dAppName: String, ) : WalletConnectDialog() } diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/SessionsAdapter.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/SessionsAdapter.kt deleted file mode 100644 index 95c28cf26a..0000000000 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/SessionsAdapter.kt +++ /dev/null @@ -1,55 +0,0 @@ -package com.tangem.tap.features.details.ui.walletconnect - -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView -import com.google.android.material.chip.Chip -import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction -import com.tangem.tap.features.details.redux.walletconnect.WalletConnectSession -import com.tangem.tap.store -import com.tangem.wallet.R - -class WalletConnectSessionsAdapter - : ListAdapter( - DiffUtilCallback -) { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SessionsViewHolder { - val layout = LayoutInflater.from(parent.context) - .inflate(R.layout.item_wallet_connect_session, parent, false) - return SessionsViewHolder(layout) - } - - override fun onBindViewHolder(holder: SessionsViewHolder, position: Int) { - holder.bind(currentList[position]) - } - - object DiffUtilCallback : DiffUtil.ItemCallback() { - override fun areContentsTheSame( - oldItem: WalletConnectSession, newItem: WalletConnectSession, - ) = oldItem == newItem - - override fun areItemsTheSame( - oldItem: WalletConnectSession, newItem: WalletConnectSession, - ) = oldItem == newItem - } - - class SessionsViewHolder(val view: View) : - RecyclerView.ViewHolder(view) { - - fun bind(session: WalletConnectSession) { - view.findViewById(R.id.tv_card_id).text = view.context.getString( - R.string.wallet_connect_card_number, session.wallet.cardId - ) - view.findViewById(R.id.tv_d_app_name).text = session.peerMeta.name - - view.findViewById(R.id.btn_disconnect).setOnClickListener { - store.dispatch(WalletConnectAction.DisconnectSession(session.session)) - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectScreen.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectScreen.kt index 71a9386b36..8474878afc 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectScreen.kt @@ -169,7 +169,6 @@ fun WalletConnectScreenPreview() { sessions = listOf( WcSessionForScreen( description = "session from some dApp", - cardId = "12312312321", sessionId = "", ), ), diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectScreenState.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectScreenState.kt index 44792f9623..e1d915dc5b 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectScreenState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectScreenState.kt @@ -11,14 +11,12 @@ data class WalletConnectScreenState( data class WcSessionForScreen( val description: String, - val cardId: String, val sessionId: String, ) { companion object { fun fromSession(session: WalletConnectSession): WcSessionForScreen { return WcSessionForScreen( description = session.peerMeta.name, - cardId = session.wallet.cardId, sessionId = session.session.toUri(), ) } diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/ApproveWcSessionDialog.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/ApproveWcSessionDialog.kt index b9fd651bb8..ab95ef6ef8 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/ApproveWcSessionDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/ApproveWcSessionDialog.kt @@ -14,7 +14,6 @@ class ApproveWcSessionDialog { fun create(session: WalletConnectSession, networks: List, context: Context): AlertDialog { val message = context.getString( R.string.wallet_connect_request_session_start, - session.wallet.cardId, session.peerMeta.name, session.peerMeta.url, ) diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/BnbTransactionDialog.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/BnbTransactionDialog.kt index 2ec39ca844..3d0fb57930 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/BnbTransactionDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/BnbTransactionDialog.kt @@ -15,7 +15,6 @@ class BnbTransactionDialog { data: BinanceMessageData, session: WCSession, sessionId: Long, - cardId: String, dAppName: String, context: Context, ): AlertDialog { @@ -40,7 +39,7 @@ class BnbTransactionDialog { val fullMessage = context.getString( R.string.wallet_connect_bnb_sign_message, - dAppName, cardId, message + dAppName, message, ) val positiveButtonTitle = context.getText(R.string.common_sign) diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/PersonalSignDialog.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/PersonalSignDialog.kt index 789384c758..5d6e001087 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/PersonalSignDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/PersonalSignDialog.kt @@ -15,10 +15,12 @@ class PersonalSignDialog { context: Context, ): AlertDialog { val message = - context.getString(R.string.wallet_connect_alert_sign_message, data.cardId) + - context.getString(R.string.wallet_connect_personal_sign_message, - data.dAppName, - data.message) + context.getString(R.string.wallet_connect_alert_sign_message) + + context.getString( + R.string.wallet_connect_personal_sign_message, + data.dAppName, + data.message, + ) return AlertDialog.Builder(context).apply { setTitle(context.getString(R.string.wallet_connect)) setMessage(message) @@ -37,7 +39,6 @@ class PersonalSignDialog { } data class PersonalSignDialogData( - val cardId: String, val dAppName: String, val message: String, val session: WCSession, diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/TransactionDialog.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/TransactionDialog.kt index 192fc3d9e1..245cbd2ae0 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/TransactionDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/TransactionDialog.kt @@ -17,7 +17,6 @@ class TransactionDialog { ): AlertDialog { val message = context.getString( R.string.wallet_connect_create_tx_message, - data.cardId, data.dAppName, data.dAppUrl, data.amount, @@ -53,7 +52,6 @@ class TransactionDialog { } data class TransactionRequestDialogData( - val cardId: String, val dAppName: String, val dAppUrl: String, val amount: String, diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/WcDialog.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/WcDialog.kt index 4bbb63e270..f71c14a348 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/WcDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/dialogs/WcDialog.kt @@ -45,7 +45,6 @@ data class ButtonData( interface DialogMessageData data class WcTransactionDialogMessageData( - val cardId: String, val dAppName: String, val dAppUrl: String, val amount: String, diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsAction.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsAction.kt index ee4bd5ddab..5c915f9cb0 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsAction.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsAction.kt @@ -4,9 +4,9 @@ import com.tangem.Message import com.tangem.blockchain.common.WalletManager import com.tangem.common.extensions.VoidCallback import com.tangem.domain.common.ScanResponse +import com.tangem.tap.common.AssetReader import com.tangem.tap.common.redux.StateDialog import com.tangem.tap.domain.TapError -import com.tangem.tap.domain.twins.AssetReader import com.tangem.tap.domain.twins.TwinCardsManager import com.tangem.tap.features.onboarding.OnboardingWalletBalance import org.rekotlin.Action diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/TwinsCardsFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/TwinsCardsFragment.kt index 7827a4f196..ee7eb79471 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/TwinsCardsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/TwinsCardsFragment.kt @@ -15,10 +15,10 @@ import com.tangem.blockchain.common.Blockchain import com.tangem.common.extensions.VoidCallback import com.tangem.domain.common.TwinCardNumber import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapfrogWidget +import com.tangem.tap.common.AndroidAssetReader import com.tangem.tap.common.extensions.beginDelayedTransition import com.tangem.tap.common.extensions.getDrawableCompat import com.tangem.tap.common.extensions.hide -import com.tangem.tap.common.extensions.readAssetAsString import com.tangem.tap.common.extensions.show import com.tangem.tap.common.extensions.stripZeroPlainString import com.tangem.tap.common.redux.navigation.AppScreen @@ -26,7 +26,6 @@ import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.common.redux.navigation.ShareElement import com.tangem.tap.common.toggleWidget.RefreshBalanceWidget import com.tangem.tap.common.transitions.InternalNoteLayoutTransition -import com.tangem.tap.domain.twins.AssetReader import com.tangem.tap.domain.twins.TwinsCardWidget import com.tangem.tap.features.addBackPressHandler import com.tangem.tap.features.onboarding.products.BaseOnboardingFragment @@ -46,13 +45,6 @@ class TwinsCardsFragment : BaseOnboardingFragment() { private lateinit var twinsWidget: TwinsCardWidget private lateinit var btnRefreshBalanceWidget: RefreshBalanceWidget - private val assetReader: AssetReader by lazy { - object : AssetReader { - override fun readAssetAsString(name: String): String = - requireContext().readAssetAsString(name) - } - } - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) postponeEnterTransition() @@ -250,7 +242,7 @@ class TwinsCardsFragment : BaseOnboardingFragment() { store.dispatch( TwinCardsAction.Wallet.LaunchFirstStep( Message(getString(R.string.twins_recreate_title_format, twinIndexNumber)), - assetReader + AndroidAssetReader(requireContext()), ) ) } diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/AmountMiddleware.kt b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/AmountMiddleware.kt index bfcbc36889..69bdcc3166 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/AmountMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/AmountMiddleware.kt @@ -120,6 +120,7 @@ private fun filterErrorsForAmountField(errors: EnumSet): EnumS TransactionError.TotalExceedsBalance -> { val notAcceptable = listOf(TransactionError.AmountExceedsBalance, TransactionError.FeeExceedsBalance) if (!showIntoAmountField.containsAll(notAcceptable)) showIntoAmountField.add(it) + showIntoAmountField.remove(TransactionError.AmountLowerExistentialDeposit) } else -> showIntoAmountField.add(it) } diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt index ee1b5eb1d2..54be369642 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt @@ -2,6 +2,7 @@ package com.tangem.tap.features.send.redux.middlewares import com.google.firebase.crashlytics.FirebaseCrashlytics import com.tangem.blockchain.blockchains.binance.BinanceTransactionExtras +import com.tangem.blockchain.blockchains.polkadot.ExistentialDepositProvider import com.tangem.blockchain.blockchains.stellar.StellarTransactionExtras import com.tangem.blockchain.blockchains.xrp.XrpTransactionBuilder import com.tangem.blockchain.common.Amount @@ -301,12 +302,21 @@ fun createValidateTransactionError( val tapErrors = errorList.map { when (it) { TransactionError.AmountExceedsBalance -> TapError.AmountExceedsBalance + TransactionError.AmountLowerExistentialDeposit -> { + if (walletManager is ExistentialDepositProvider) { + val args = listOf(walletManager.getExistentialDeposit().stripZeroPlainString()) + TapError.AmountLowerExistentialDeposit(args) + } else { + TapError.UnknownError + } + } TransactionError.FeeExceedsBalance -> TapError.FeeExceedsBalance TransactionError.TotalExceedsBalance -> TapError.TotalExceedsBalance TransactionError.InvalidAmountValue -> TapError.InvalidAmountValue TransactionError.InvalidFeeValue -> TapError.InvalidFeeValue TransactionError.DustAmount -> { - TapError.DustAmount(listOf(walletManager.dustValue?.stripZeroPlainString() ?: "0")) + val args = listOf(walletManager.dustValue?.stripZeroPlainString() ?: "0") + TapError.DustAmount(args) } TransactionError.DustChange -> TapError.DustChange else -> TapError.UnknownError diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt index 9d7ac05a20..4d4154218c 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt @@ -218,7 +218,7 @@ class ReceiptReducer : SendInternalReducer { } private fun String.addPrecisionSign(): String { - val result = if (feeState.feeIsApproximate) "$CAN_BE_LOWER_SIGN $this" else "" + val result = if (feeState.feeIsApproximate) "$CAN_BE_LOWER_SIGN $this" else this return result.trim() } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt index 4215143301..71000abec1 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt @@ -3,8 +3,19 @@ package com.tangem.tap.features.send.redux.reducers import com.tangem.blockchain.blockchains.stellar.StellarMemo import com.tangem.blockchain.common.Blockchain import com.tangem.tap.features.send.redux.SendScreenAction -import com.tangem.tap.features.send.redux.TransactionExtrasAction.* -import com.tangem.tap.features.send.redux.states.* +import com.tangem.tap.features.send.redux.TransactionExtrasAction.BinanceMemo +import com.tangem.tap.features.send.redux.TransactionExtrasAction.Prepare +import com.tangem.tap.features.send.redux.TransactionExtrasAction.Release +import com.tangem.tap.features.send.redux.TransactionExtrasAction.XlmMemo +import com.tangem.tap.features.send.redux.TransactionExtrasAction.XrpDestinationTag +import com.tangem.tap.features.send.redux.states.BinanceMemoState +import com.tangem.tap.features.send.redux.states.InputViewValue +import com.tangem.tap.features.send.redux.states.SendState +import com.tangem.tap.features.send.redux.states.TransactionExtraError +import com.tangem.tap.features.send.redux.states.TransactionExtrasState +import com.tangem.tap.features.send.redux.states.XlmMemoState +import com.tangem.tap.features.send.redux.states.XlmMemoType +import com.tangem.tap.features.send.redux.states.XrpDestinationTagState /** [REDACTED_AUTHOR] @@ -53,42 +64,33 @@ class TransactionExtrasReducer : SendInternalReducer { } private fun handleXlmMemo( - action: XlmMemo, - sendState: SendState, - infoState: TransactionExtrasState, + action: XlmMemo, + sendState: SendState, + infoState: TransactionExtrasState, ): SendState { fun clearMemo(memo: XlmMemoState): XlmMemoState = memo.copy(text = null, id = null, error = null) val result = when (action) { -// is XlmMemo.ChangeSelectedMemo -> { -// val inputViewValue = InputViewValue("", false) -// val memo = infoState.xlmMemo?.copy( -// viewFieldValue = inputViewValue, -// selectedMemoType = action.memoType, -// ) ?: XlmMemoState(inputViewValue, action.memoType) -// -// infoState.copy(xlmMemo = clearMemo(memo)) -// } is XlmMemo.HandleUserInput -> { val inputViewValue = InputViewValue(action.data, true) var memo = infoState.xlmMemo?.copy(viewFieldValue = inputViewValue) - ?: XlmMemoState(inputViewValue) + ?: XlmMemoState(inputViewValue) memo = clearMemo(memo) - memo = when (infoState.xlmMemo?.selectedMemoType) { - XlmMemoType.TEXT -> memo.copy(text = StellarMemo.Text(action.data)) - XlmMemoType.ID -> { - val id = action.data.toBigIntegerOrNull() - if (id != null) { - if (id > XlmMemoState.MAX_NUMBER) { - memo.copy(error = TransactionExtraError.INVALID_XLM_MEMO) - } else { - memo.copy(id = StellarMemo.Id(id)) - } + memo = when (memo.selectedMemoType) { + XlmMemoType.TEXT -> { + if (XlmMemoState.isAssignableValue(action.data)) { + memo.copy(text = StellarMemo.Text(action.data)) } else { - memo + memo.copy(error = TransactionExtraError.INVALID_XLM_MEMO) + } + } + XlmMemoType.ID -> { + if (XlmMemoState.isAssignableValue(action.data)) { + memo.copy(id = StellarMemo.Id(action.data.toBigInteger())) + } else { + memo.copy(error = TransactionExtraError.INVALID_XLM_MEMO) } } - null -> memo } infoState.copy(xlmMemo = memo) } @@ -117,16 +119,16 @@ class TransactionExtrasReducer : SendInternalReducer { } private fun handleXrpTag( - action: XrpDestinationTag, - sendState: SendState, - infoState: TransactionExtrasState, + action: XrpDestinationTag, + sendState: SendState, + infoState: TransactionExtrasState, ): SendState { val result = when (action) { is XrpDestinationTag.HandleUserInput -> { val tag = action.data.toLongOrNull() if (tag != null) { val input = InputViewValue(action.data, true) - val tagState = if (tag <= XrpDestinationTagState.MAX_NUMBER){ + val tagState = if (tag <= XrpDestinationTagState.MAX_NUMBER) { XrpDestinationTagState(input, tag) } else { XrpDestinationTagState(input, error = TransactionExtraError.INVALID_DESTINATION_TAG) diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt b/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt index e4f816c106..30fe37f60a 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt @@ -1,19 +1,20 @@ package com.tangem.tap.features.send.redux.states +import androidx.core.text.isDigitsOnly import com.tangem.blockchain.blockchains.stellar.StellarMemo import com.tangem.tap.features.send.redux.AddressPayIdVerifyAction import java.math.BigInteger data class AddressPayIdState( - val viewFieldValue: InputViewValue = InputViewValue(""), - val normalFieldValue: String? = null, - val truncatedFieldValue: String? = null, - val destinationWalletAddress: String? = null, - val error: AddressPayIdVerifyAction.Error? = null, - val truncateHandler: ((String) -> String)? = null, - val sendingToPayIdEnabled: Boolean = false, - val pasteIsEnabled: Boolean = false, - val inputIsEnabled: Boolean = true + val viewFieldValue: InputViewValue = InputViewValue(""), + val normalFieldValue: String? = null, + val truncatedFieldValue: String? = null, + val destinationWalletAddress: String? = null, + val error: AddressPayIdVerifyAction.Error? = null, + val truncateHandler: ((String) -> String)? = null, + val sendingToPayIdEnabled: Boolean = false, + val pasteIsEnabled: Boolean = false, + val inputIsEnabled: Boolean = true, ) : SendScreenState { override val stateId: StateId = StateId.ADDRESS_PAY_ID @@ -26,9 +27,9 @@ data class AddressPayIdState( } data class TransactionExtrasState( - val xlmMemo: XlmMemoState? = null, - val binanceMemo: BinanceMemoState? = null, - val xrpDestinationTag: XrpDestinationTagState? = null + val xlmMemo: XlmMemoState? = null, + val binanceMemo: BinanceMemoState? = null, + val xrpDestinationTag: XrpDestinationTagState? = null, ) : IdStateHolder { override val stateId: StateId = StateId.TRANSACTION_EXTRAS } @@ -38,11 +39,10 @@ enum class XlmMemoType { } data class XlmMemoState( - val viewFieldValue: InputViewValue = InputViewValue(""), - val selectedMemoType: XlmMemoType = XlmMemoType.ID, - val text: StellarMemo.Text? = null, - val id: StellarMemo.Id? = null, - val error: TransactionExtraError? = null, + val viewFieldValue: InputViewValue = InputViewValue(""), + val text: StellarMemo.Text? = null, + val id: StellarMemo.Id? = null, + val error: TransactionExtraError? = null, ) { val memo: StellarMemo? get() = when (selectedMemoType) { @@ -50,16 +50,37 @@ data class XlmMemoState( XlmMemoType.ID -> id } + val selectedMemoType: XlmMemoType + get() = determineMemoType(viewFieldValue.value) + companion object { - val MAX_NUMBER: BigInteger = BigInteger("FFFFFFFFFFFFFFFF", 16) + fun determineMemoType(value: String): XlmMemoType = when { + value.isNotEmpty() && value.isDigitsOnly() -> XlmMemoType.ID + else -> XlmMemoType.TEXT + } + + fun isAssignableValue(value: String): Boolean = when (determineMemoType(value)) { + XlmMemoType.TEXT -> { + // from org.stellar.sdk.MemoText + value.toByteArray().size <= 28 + } + XlmMemoType.ID -> { + try { + // from com.tangem.blockchain.blockchains.stellar.StellarMemo.toStellarSdkMemo + value.toBigInteger() in BigInteger.ZERO..(Long.MAX_VALUE.toBigInteger() * 2.toBigInteger()) + } catch (ex: NumberFormatException) { + false + } + } + } } } data class BinanceMemoState( val viewFieldValue: InputViewValue = InputViewValue(""), val memo: BigInteger? = null, - val error: TransactionExtraError? = null - ) { + val error: TransactionExtraError? = null, +) { companion object { val MAX_NUMBER: BigInteger = BigInteger("FFFFFFFFFFFFFFFF", 16) } @@ -67,9 +88,9 @@ data class BinanceMemoState( // tag must contains only digits data class XrpDestinationTagState( - val viewFieldValue: InputViewValue = InputViewValue(""), - val tag: Long? = null, - val error: TransactionExtraError? = null + val viewFieldValue: InputViewValue = InputViewValue(""), + val tag: Long? = null, + val error: TransactionExtraError? = null, ) { companion object { const val MAX_NUMBER: Long = 4294967295 diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/SendTransactionFailsDialog.kt b/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/SendTransactionFailsDialog.kt index a4b5ff7539..0e35552e43 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/SendTransactionFailsDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/SendTransactionFailsDialog.kt @@ -2,6 +2,7 @@ package com.tangem.tap.features.send.ui.dialogs import android.content.Context import androidx.appcompat.app.AlertDialog +import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.BlockchainSdkError import com.tangem.common.module.ModuleMessageConverter import com.tangem.tangem_sdk_new.extensions.localizedDescription @@ -47,9 +48,13 @@ private class BlockchainSdkErrorConverter( override fun convert(message: BlockchainSdkError): String { return when (message) { is BlockchainSdkError.CreateAccountUnderfunded -> { - val reserve = message.minReserve.value?.stripZeroPlainString() ?: "0" - val symbol = message.minReserve.currencySymbol - context.getString(R.string.send_error_no_target_account, reserve, symbol) + val resStringId = when (message.blockchain) { + Blockchain.Polkadot, Blockchain.PolkadotTestnet -> R.string.no_account_polkadot + else -> R.string.send_error_no_target_account + } + val reserveValueString = message.minReserve.value?.stripZeroPlainString() ?: "0" + val argument = "$reserveValueString ${message.minReserve.currencySymbol}" + context.getString(resStringId, argument) } else -> message.customMessage } diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt index 96624950c0..fe3bee237d 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt @@ -2,7 +2,6 @@ package com.tangem.tap.features.send.ui.stateSubscribers import android.app.Dialog import android.content.Context -import android.text.InputType import android.text.SpannableStringBuilder import android.view.View import android.view.ViewGroup @@ -31,7 +30,6 @@ import com.tangem.tap.features.send.redux.states.SendState import com.tangem.tap.features.send.redux.states.StateId import com.tangem.tap.features.send.redux.states.TransactionExtraError import com.tangem.tap.features.send.redux.states.TransactionExtrasState -import com.tangem.tap.features.send.redux.states.XlmMemoType import com.tangem.tap.features.send.ui.FeeUiHelper import com.tangem.tap.features.send.ui.SendFragment import com.tangem.tap.features.send.ui.dialogs.RequestFeeErrorDialog @@ -80,14 +78,10 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : showView(binanceMemoContainer, infoState.binanceMemo) infoState.xlmMemo?.let { - etXlmMemo.inputType = when (it.selectedMemoType) { - XlmMemoType.TEXT -> InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS - XlmMemoType.ID -> InputType.TYPE_CLASS_NUMBER - } if (!it.viewFieldValue.isFromUserInput) etXlmMemo.setText(it.viewFieldValue.value) if (it.error != null) { if (it.error == TransactionExtraError.INVALID_XLM_MEMO) { - tilXlmMemo.error = fg.getText(R.string.send_error_invalid_memo_id) + tilXlmMemo.error = fg.getText(R.string.send_extras_error_invalid_memo) } } else { tilXlmMemo.error = null @@ -97,7 +91,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : if (infoState.xrpDestinationTag.error != null) { if (infoState.xrpDestinationTag.error == TransactionExtraError.INVALID_DESTINATION_TAG) { tilDestinationTag.error = - fg.getText(R.string.send_error_invalid_destination_tag) + fg.getText(R.string.send_extras_error_invalid_destination_tag) } } else { tilDestinationTag.error = null @@ -109,7 +103,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : infoState.binanceMemo?.let { if (infoState.binanceMemo.error != null) { if (infoState.binanceMemo.error == TransactionExtraError.INVALID_BINANCE_MEMO) { - tilBinanceMemo.error = fg.getText(R.string.send_error_invalid_memo_id) + tilBinanceMemo.error = fg.getText(R.string.send_extras_error_invalid_memo) } } else { tilBinanceMemo.error = null diff --git a/app/src/main/res/layout/layout_send_address_payid.xml b/app/src/main/res/layout/layout_send_address_payid.xml index 232b778f22..b16e59b974 100644 --- a/app/src/main/res/layout/layout_send_address_payid.xml +++ b/app/src/main/res/layout/layout_send_address_payid.xml @@ -153,6 +153,7 @@ android:layout_height="wrap_content" android:background="@color/backgroundLightGray" android:ellipsize="middle" + android:inputType="text|textNoSuggestions" android:paddingStart="0dp" android:paddingEnd="0dp" android:singleLine="true" diff --git a/app/src/main/res/values-de/strings_blockchain.xml b/app/src/main/res/values-de/strings_blockchain.xml index 2f52667c19..5cb1360d71 100644 --- a/app/src/main/res/values-de/strings_blockchain.xml +++ b/app/src/main/res/values-de/strings_blockchain.xml @@ -5,7 +5,7 @@ Falsche Gebühr Minimaler Betrag ist %s Restbestand zu klein - Das Zielkonto ist nicht erstellt. Der abzusendende Betrag soll %s %s + Gebühr oder mehr sein + Das Zielkonto ist nicht erstellt. Der abzusendende Betrag soll %s + Gebühr oder mehr sein Um ein Konto zu erstellen, senden Sie 1+ XLM an diese Adresse Erhalt der Gebühr fehlgeschlagen Unbekannter Fehler @@ -17,4 +17,11 @@ Der Betrag geht über die Bilanz hinaus Der Gesamtbetrag geht über die Bilanz hinaus Die Gebühr geht über die Bilanz hinaus + Minimum balance is %s + Memo + Tag + Invalid Memo. It won\'t be added to the transaction + Invalid Tag. It won\'t be added to the transaction + %s network has a concept of Existential Deposit. If your account drops below %s %s it will be deactivated and any remaining funds will be destroyed. + Destination account is not active. Send %s or more to activate the account. \ No newline at end of file diff --git a/app/src/main/res/values-de/strings_final.xml b/app/src/main/res/values-de/strings_final.xml index 501e8200d9..16338c6931 100644 --- a/app/src/main/res/values-de/strings_final.xml +++ b/app/src/main/res/values-de/strings_final.xml @@ -86,7 +86,5 @@ Reset to Factory Settings Factory Reset will completely delete the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. Select network - %s network has a concept of Existential Deposit. If your account drops below %s %s it will be deactivated and any remaining funds will be destroyed. - To start working with the card scan the first card and make a backup \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings_blockchain.xml b/app/src/main/res/values-fr/strings_blockchain.xml index f6e2cdef63..5bbb85c2f3 100644 --- a/app/src/main/res/values-fr/strings_blockchain.xml +++ b/app/src/main/res/values-fr/strings_blockchain.xml @@ -5,7 +5,7 @@ Commission non valide Le montant minimal est de %s Le reste est trop petit - Le compte cible n\'a pas été créé. Le montant à envoyer doit être de %s %s + commissions ou plus + Le compte cible n\'a pas été créé. Le montant à envoyer doit être de %s + commissions ou plus Pour créer un compte, envoyez 1+ XLM à cette adresse Échec de réception des commissions Erreur inconnue @@ -17,4 +17,11 @@ Pour ne pas payer une commission élevée la prochaine fois que vous rechargez votre portefeuille, veuillez réduire le montant de %s XTZ Réduire de %s XTZ Non, envoyer toute la somme + Minimum balance is %s + Memo + Tag + Invalid Memo. It won\'t be added to the transaction + Invalid Tag. It won\'t be added to the transaction + %s network has a concept of Existential Deposit. If your account drops below %s %s it will be deactivated and any remaining funds will be destroyed. + Destination account is not active. Send %s or more to activate the account. \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings_final.xml b/app/src/main/res/values-fr/strings_final.xml index 7c59ccee98..42c604b593 100644 --- a/app/src/main/res/values-fr/strings_final.xml +++ b/app/src/main/res/values-fr/strings_final.xml @@ -86,7 +86,5 @@ Reset to Factory Settings Factory Reset will completely delete the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. Select network - %s network has a concept of Existential Deposit. If your account drops below %s %s it will be deactivated and any remaining funds will be destroyed. - To start working with the card scan the first card and make a backup \ No newline at end of file diff --git a/app/src/main/res/values-it/strings_blockchain.xml b/app/src/main/res/values-it/strings_blockchain.xml index cd0f690a23..775778dbb0 100644 --- a/app/src/main/res/values-it/strings_blockchain.xml +++ b/app/src/main/res/values-it/strings_blockchain.xml @@ -7,7 +7,7 @@ L\'importo residuo è molto basso Errore sconosciuto L\'importo supera il saldo - Per creare un account, invia %s %s a questo indirizzo + Per creare un account, invia %s a questo indirizzo Impossibile ottenere la commissione Per creare un account, invia 1+ XLM a questo indirizzo Indirizzo non valido @@ -17,4 +17,11 @@ Per evitare di pagare una commissione maggiore la prossima volta che ricarichi il tuo portafoglio, riduci l\'importo di %s XTZ Riduci di %s XTZ No, invia l\'intero importo + Minimum balance is %s + Memo + Tag + Invalid Memo. It won\'t be added to the transaction + Invalid Tag. It won\'t be added to the transaction + %s network has a concept of Existential Deposit. If your account drops below %s %s it will be deactivated and any remaining funds will be destroyed. + Destination account is not active. Send %s or more to activate the account. \ No newline at end of file diff --git a/app/src/main/res/values-it/strings_final.xml b/app/src/main/res/values-it/strings_final.xml index 7c59ccee98..1c6908d47b 100644 --- a/app/src/main/res/values-it/strings_final.xml +++ b/app/src/main/res/values-it/strings_final.xml @@ -87,6 +87,5 @@ Factory Reset will completely delete the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. Select network %s network has a concept of Existential Deposit. If your account drops below %s %s it will be deactivated and any remaining funds will be destroyed. - To start working with the card scan the first card and make a backup \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index d36add64ec..9c7aef46d4 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -147,10 +147,6 @@ Добавить Удалить Поиск - Памятка - Тег назначения - Недопустимый тег назначения. Он не будет добавлен в транзакцию. - Недопустимый идентификатор памятки. Он не будет добавлен в транзакцию. Приложение Отправить отзыв Успешно отправлено @@ -328,8 +324,8 @@ %1s (%2s) Эта карта не является векселем на предъявителя. В настоящее время мы не можем сопоставить количество подписей на карте с информацией в блокчейне. Это нормально, но в редких случаях может означать, что предыдущий владелец скрывает автономную подпись, что является проблемой безопасности.\n\nНе принимайте эту карту в качестве физического платежа от кого-то, кому Вы не доверяете.\n\nВо всех остальных отношениях - это совершенно безопасно.\n\nTangem — единственный аппаратный кошелек, предлагающий защиту от подсчета подписей. WalletConnect - Карта %1s\nЗапрос на создание транзакции для %2s\n%3s\n\nСумма: %4s\nКомиссия: %5s\nВсего: %6s\nБаланс: %7s - Запрос на запуск сеанса для карты с идентификатором %1s\nдля %2s\n\nURL: %3s + Запрос на создание транзакции для %1s\n%2s\n\nСумма: %3s\nКомиссия: %4s\nВсего: %5s\nБаланс: %6s + Запрос на запуск сеанса для %1s\n\nURL: %2s Сессии WalletConnect Сеанс WalletConnect открыт с %s Упс. Нет сессий. @@ -338,7 +334,7 @@ Карта: %s Коснитесь карты, чтобы привязать ее WalletConnect Не удается отправить транзакцию. Недостаточно средств. - Просьба подписать сообщение\nкартой %s\n\n + Просьба подписать сообщение\n Сообщение для %s:\n%s Буфер обмена содержит код WalletConnect. Использовать скопированное значение или отсканировать QR-код Вставить из буфера обмена @@ -348,7 +344,7 @@ Операция не может быть завершена. \n\nВы уже установили сеанс WalletConnect с этими параметрами. Не удалось установить сеанс WalletConnect: ошибка времени выполнения. Пожалуйста, повторите попытку позже. Транзакция BNB успешно подписана и отправлена в DApp - DApp %s, запрашивает\nподпись транзакции BNB с\nкартой: %s\n\n%s + DApp %s, запрашивает\nподпись транзакции BNB с\n%s Сведения о транзакции:\nОт: %s\nКому: %s\nСумма: %s Торговый ордер на %s\nЦена: %s\nСумма к получению: %s\nСумма к оплате: %s Мои предложения diff --git a/app/src/main/res/values-ru/strings_blockchain.xml b/app/src/main/res/values-ru/strings_blockchain.xml index 98b7ad7194..61a4c91467 100644 --- a/app/src/main/res/values-ru/strings_blockchain.xml +++ b/app/src/main/res/values-ru/strings_blockchain.xml @@ -7,7 +7,7 @@ Сдача слишком мала Для создания учетной записи отправьте 1+ XLM на этот адрес Не удалось получить комиссию - Целевая учетная запись не создана. Сумма для отправки должна быть %1$s %2$s + плата за создание или больше + Целевая учетная запись не создана. Сумма для отправки должна быть %s + плата за создание или больше Неизвестная ошибка Неверный адрес Недопустимая сумма @@ -17,4 +17,6 @@ Чтобы не платить повышенную комиссию при следующем пополнении кошелька, уменьшите сумму на %s XTZ Уменьшить на %s XTZ Нет, отправить все + Минимальный баланс: %s + Аккаунт получателя не активирован. Отправьте %s или более для активации аккаунта. \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings_final.xml b/app/src/main/res/values-ru/strings_final.xml index 27f6ed4b8a..23f2c7f576 100644 --- a/app/src/main/res/values-ru/strings_final.xml +++ b/app/src/main/res/values-ru/strings_final.xml @@ -97,6 +97,10 @@ Сброс к заводским настройкам Сброс к заводским настройкам приведет к полному удалению кошелька с выбранной карты. Вы не сможете восстановить текущий кошелек или использовать эту карту для восстановления кода доступа. Выберите сеть + Memo + Tag + Недопустимый Memo. Он не будет добавлен в транзакцию. + Недопустимый Tag. Он не будет добавлен в транзакцию. Сеть %s использует концепцию экзистенциального депозита. Если баланс вашего счета опустится ниже %s %s, он будет деактивирован, а все оставшиеся средства будут уничтожены. Для начала работы с картой сначала отсканируйте первую карту и сделайте бэкап diff --git a/app/src/main/res/values/strings_blockchain.xml b/app/src/main/res/values/strings_blockchain.xml index 35bc8cf334..6a496314b1 100644 --- a/app/src/main/res/values/strings_blockchain.xml +++ b/app/src/main/res/values/strings_blockchain.xml @@ -7,7 +7,7 @@ Change is too small To create account send 1+ XLM to this address Failed to get fee - Target account is not created. Amount to send should be %s %s + fee or more to create + Target account is not created. Amount to send should be %s + fee or more to create Unknown error Invalid address Invalid amount @@ -17,4 +17,11 @@ To avoid paying an increased commission the next time you top up your wallet, reduce the amount by %s XTZ Reduce by %s XTZ No, send all + Minimum balance is %s + Memo + Tag + Invalid Memo. It won\'t be added to the transaction + Invalid Tag. It won\'t be added to the transaction + %s network has a concept of Existential Deposit. If your account drops below %s %s it will be deactivated and any remaining funds will be destroyed. + Destination account is not active. Send %s or more to activate the account. \ No newline at end of file diff --git a/app/src/main/res/values/strings_final.xml b/app/src/main/res/values/strings_final.xml index dd49ea9071..b1c5e9121e 100644 --- a/app/src/main/res/values/strings_final.xml +++ b/app/src/main/res/values/strings_final.xml @@ -99,7 +99,5 @@ Reset to Factory Settings Factory Reset will completely delete the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. Select network - %s network has a concept of Existential Deposit. If your account drops below %s %s it will be deactivated and any remaining funds will be destroyed. - To start working with the card scan the first card and make a backup diff --git a/app/src/main/res/values/strings_untranslated.xml b/app/src/main/res/values/strings_untranslated.xml index 405518a258..cc9e1a3cf3 100644 --- a/app/src/main/res/values/strings_untranslated.xml +++ b/app/src/main/res/values/strings_untranslated.xml @@ -40,12 +40,6 @@ Remove Search - - Memo - Destination tag - Invalid destination tag. It won\'t be added to the transaction - Invalid Memo ID. It won\'t be added to the transaction - App Send feedback Sent successfully @@ -140,24 +134,23 @@ Card: %s Tap card to bind to wallet connect - Card: %1s\n - Request to create transaction for %2s - \n%3s + + Request to create transaction for %1s + \n%2s - \n\nAmount: %4s - \nFee: %5s - \nTotal: %6s - \nBalance: %7s + \n\nAmount: %3s + \nFee: %4s + \nTotal: %5s + \nBalance: %6s Can\'t send transaction. Not enough funds. - Request to start a session for card with ID %1s\n - for %2s\n\n + Request to start a session for %1s\n\n - URL: %3s + URL: %2s - Requesting to sign a message\nwith card %s\n\n + Requesting to sign a message\n Message for %s:\n%s @@ -305,8 +298,7 @@ The BNB transaction has been successfully signed and sent to the Dapp Dapp %s, requesting to\n -sign BNB transaction with\n -Card: %s\n +sign BNB transaction \n %s Transaction details:\n diff --git a/dependencies.gradle b/dependencies.gradle index 394b8cc997..8762730416 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -2,7 +2,7 @@ ext.versions = [ kotlin : '1.6.10', build_gradle : '7.1.3', tangem_card_sdk : 'develop-159', - tangem_blockchain_sdk: 'develop-111', + tangem_blockchain_sdk: 'develop-113', // tangem_blockchain_sdk: '0.0.1', ]