diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000000..57188dd623
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,15 @@
+[*.{kt,kts}]
+ktlint_code_style = official
+ktlint_ignore_back_ticked_identifier = true
+
+indent_size = 4
+indent_style = space
+insert_final_newline = true
+
+ij_kotlin_allow_trailing_comma = true
+ij_kotlin_allow_trailing_comma_on_call_site = true
+
+ij_kotlin_imports_layout = *, java.**, javax.**, kotlin.**, ^
+ij_kotlin_packages_to_use_import_on_demand = java.util.*, kotlinx.android.synthetic.**
+
+max_line_length = 120
diff --git a/.gitignore b/.gitignore
index 4cc00a7e1f..dd64e70b22 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,8 @@ local.properties
# User-specific configurations
.idea
+!.idea/codeStyles
+!.idea/inspectionProfiles
# LayoutInspector files
/captures
@@ -26,4 +28,4 @@ local.properties
**/fastlane/report.xml
**/fastlane/Preview.html
**/fastlane/screenshots
-**/fastlane/test_output
\ No newline at end of file
+**/fastlane/test_output
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 0000000000..ad9c1261c4
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,204 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ xmlns:android
+
+ ^$
+
+
+
+
+
+
+
+
+ xmlns:.*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*:id
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:name
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ name
+
+ ^$
+
+
+
+
+
+
+
+
+ style
+
+ ^$
+
+
+
+
+
+
+
+
+ .*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*
+
+ http://schemas.android.com/apk/res/android
+
+
+ ANDROID_ATTRIBUTE_ORDER
+
+
+
+
+
+
+ .*
+
+ .*
+
+
+ BY_NAME
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000000..79ee123c2b
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000000..ba5af7a4ce
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 3f12b8e345..105d4d8323 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -6,13 +6,13 @@ apply plugin: 'com.google.firebase.crashlytics'
apply from: '../dependencies.gradle'
android {
- compileSdkVersion 31
+ compileSdkVersion 32
defaultConfig {
applicationId "com.tangem.wallet"
versionCode project.hasProperty('versionCode') ? project.property('versionCode') as int : 1
versionName project.hasProperty('versionName') ? project.property('versionName') : "1.0.0.-SNAPSHOT"
minSdkVersion 21
- targetSdkVersion 31
+ targetSdkVersion 32
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
buildConfigField 'Boolean', environmentConfig.testActionEnabled, 'false'
@@ -83,12 +83,11 @@ dependencies {
implementation implementation(project(path: ':network'))
implementation implementation(project(path: ':common'))
- implementation 'androidx.core:core-ktx:1.7.0'
+ implementation 'androidx.core:core-ktx:1.8.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'androidx.fragment:fragment-ktx:1.4.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
implementation 'com.google.android.material:material:1.5.0'
- implementation "androidx.core:core-ktx:1.7.0"
implementation 'com.google.android.play:core:1.10.3'
implementation 'com.google.android.play:core-ktx:1.8.1'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
@@ -164,14 +163,14 @@ dependencies {
implementation 'com.google.android.gms:play-services-wallet:19.1.0'
//Compose
- implementation 'androidx.activity:activity-compose:1.4.0'
+ implementation 'androidx.activity:activity-compose:1.5.0'
implementation 'androidx.compose.material:material:1.1.1'
implementation 'androidx.compose.animation:animation:1.1.1'
- implementation 'androidx.compose.foundation:foundation:1.1.1'
- implementation 'androidx.compose.foundation:foundation-layout:1.1.1'
+ implementation 'androidx.compose.foundation:foundation:1.2.0-rc03'
implementation 'androidx.compose.ui:ui:1.1.1'
implementation 'androidx.compose.ui:ui-tooling:1.1.1'
implementation "com.google.accompanist:accompanist-appcompat-theme:0.23.0"
+ implementation "com.google.accompanist:accompanist-systemuicontroller:0.23.0"
implementation "com.github.skydoves:androidveil:1.1.2"
diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt
index 7593f303e7..78d55638ca 100644
--- a/app/src/main/java/com/tangem/tap/MainActivity.kt
+++ b/app/src/main/java/com/tangem/tap/MainActivity.kt
@@ -5,6 +5,8 @@ import android.content.pm.ActivityInfo
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.WindowCompat
+import androidx.core.view.WindowInsetsControllerCompat
import by.kirich1409.viewbindingdelegate.viewBinding
import com.google.android.material.snackbar.Snackbar
import com.tangem.TangemSdk
@@ -27,11 +29,11 @@ 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
-import java.lang.ref.WeakReference
-import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
+import java.lang.ref.WeakReference
+import kotlin.coroutines.CoroutineContext
lateinit var tangemSdk: TangemSdk
lateinit var tangemSdkManager: TangemSdkManager
@@ -83,8 +85,10 @@ class MainActivity : AppCompatActivity(), SnackbarHandler {
}
private fun systemActions() {
- // makes the status bar text dark
- window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
+ WindowCompat.setDecorFitsSystemWindows(window, false)
+ WindowInsetsControllerCompat(window, binding.root)
+ .isAppearanceLightStatusBars = true
+
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
}
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 a199be957b..e601bdc95c 100644
--- a/app/src/main/java/com/tangem/tap/common/DialogManager.kt
+++ b/app/src/main/java/com/tangem/tap/common/DialogManager.kt
@@ -107,6 +107,12 @@ class DialogManager : StoreSubscriber {
dAppName = state.dialog.dAppName,
context = context
)
+ is WalletConnectDialog.UnsupportedNetwork ->
+ SimpleAlertDialog.create(
+ titleRes = R.string.wallet_connect,
+ messageRes = R.string.wallet_connect_scanner_error_unsupported_network,
+ context = context
+ )
is BackupDialog.AddMoreBackupCards -> AddMoreBackupCardsDialog.create(context)
is BackupDialog.BackupInProgress -> BackupInProgressDialog.create(context)
is BackupDialog.UnfinishedBackupFound -> UnfinishedBackupFoundDialog.create(context)
diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt
index 26ec96a604..7589f86c3a 100644
--- a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt
+++ b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt
@@ -63,7 +63,11 @@ fun FragmentActivity.popBackTo(screen: AppScreen?, inclusive: Boolean = false) {
}
fun FragmentActivity.getPreviousScreen(): AppScreen? {
- val indexOfLastFragment = this.supportFragmentManager.backStackEntryCount - 1
+ val indexOfLastFragment = if (this.supportFragmentManager.backStackEntryCount > 0) {
+ this.supportFragmentManager.backStackEntryCount - 1
+ } else {
+ 0
+ }
val tag = if (indexOfLastFragment < this.supportFragmentManager.backStackEntryCount)
this.supportFragmentManager.getBackStackEntryAt(indexOfLastFragment).name
else null
diff --git a/app/src/main/java/com/tangem/tap/common/extensions/StringBuilder.kt b/app/src/main/java/com/tangem/tap/common/extensions/StringBuilder.kt
index 3f8fa992ff..961e77e8f7 100644
--- a/app/src/main/java/com/tangem/tap/common/extensions/StringBuilder.kt
+++ b/app/src/main/java/com/tangem/tap/common/extensions/StringBuilder.kt
@@ -19,4 +19,6 @@ fun StringBuilder.appendIfNotNull(value: String?, prefix: String? = null, postfi
fun String.appendIfNotNull(value: String?, prefix: String? = null, postfix: String? = null): String {
return StringBuilder(this).apply { appendIfNotNull(value, prefix, postfix) }.toString()
-}
\ No newline at end of file
+}
+
+fun StringBuilder.breakLine(count: Int = 1): StringBuilder = append("\n".repeat(count))
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt b/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt
index 40acdd1b7d..39e0103066 100644
--- a/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt
+++ b/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt
@@ -8,7 +8,7 @@ import com.tangem.tap.common.TestActions
import com.tangem.tap.domain.TapError
import com.tangem.tap.domain.extensions.amountToCreateAccount
import com.tangem.tap.domain.getFirstToken
-import com.tangem.tap.features.demo.isDemoWallet
+import com.tangem.tap.features.demo.isDemoCard
import com.tangem.tap.features.wallet.redux.AddressData
import com.tangem.tap.features.wallet.redux.reducers.createAddressesData
import com.tangem.tap.network.NetworkConnectivity
@@ -21,7 +21,10 @@ import timber.log.Timber
[REDACTED_AUTHOR]
*/
suspend fun WalletManager.safeUpdate(): Result = try {
- if (isDemoWallet() || TestActions.testAmountInjectionForWalletManagerEnabled) {
+ val scanResponse = store.state.globalState.scanResponse
+ ?: error("Scan response must not be null")
+
+ if (scanResponse.isDemoCard() || TestActions.testAmountInjectionForWalletManagerEnabled) {
delay(500)
TestActions.testAmountInjectionForWalletManagerEnabled = false
Result.Success(wallet)
diff --git a/app/src/main/java/com/tangem/tap/common/feedback/FeedbackData.kt b/app/src/main/java/com/tangem/tap/common/feedback/FeedbackData.kt
index dc2a7d07d5..6578b97356 100644
--- a/app/src/main/java/com/tangem/tap/common/feedback/FeedbackData.kt
+++ b/app/src/main/java/com/tangem/tap/common/feedback/FeedbackData.kt
@@ -2,6 +2,7 @@ package com.tangem.tap.common.feedback
import android.content.Context
import com.tangem.domain.common.TapWorkarounds
+import com.tangem.tap.common.extensions.breakLine
import com.tangem.wallet.R
interface FeedbackData {
@@ -17,9 +18,9 @@ interface FeedbackData {
fun joinTogether(context: Context, infoHolder: AdditionalFeedbackInfo): String {
return StringBuilder().apply {
append(context.getString(mainMessageResId))
- appendLine(3)
+ breakLine(3)
append(context.getString(getDataCollectionMessageResId()))
- appendLine()
+ breakLine()
append(createOptionalMessage(infoHolder))
}.toString()
}
@@ -31,7 +32,7 @@ class RateCanBeBetterEmail : FeedbackData {
override fun createOptionalMessage(infoHolder: AdditionalFeedbackInfo): String = FeedbackDataBuilder(infoHolder)
.appendCardInfo()
- .appendLine()
+ .breakLine()
.appendPhoneInfo()
.build()
}
@@ -43,7 +44,7 @@ class ScanFailsEmail : FeedbackData {
override fun joinTogether(context: Context, infoHolder: AdditionalFeedbackInfo): String = StringBuilder().apply {
append(context.getString(mainMessageResId))
- appendLine(4)
+ breakLine(4)
append(createOptionalMessage(infoHolder))
}.toString()
@@ -53,7 +54,7 @@ class ScanFailsEmail : FeedbackData {
}
class SendTransactionFailedEmail(
- val error: String
+ val error: String,
) : FeedbackData {
override val subjectResId: Int = R.string.feedback_subject_tx_failed
@@ -63,7 +64,7 @@ class SendTransactionFailedEmail(
.appendCardInfo()
.appendDelimiter()
.appendTxFailedBlockchainInfo(error)
- .appendLine()
+ .breakLine()
.appendPhoneInfo()
.build()
}
@@ -89,7 +90,7 @@ class FeedbackEmail : FeedbackData {
override fun createOptionalMessage(infoHolder: AdditionalFeedbackInfo): String = FeedbackDataBuilder(infoHolder)
.appendCardInfo()
.appendWalletsInfo()
- .appendLine()
+ .breakLine()
.appendPhoneInfo()
.build()
}
diff --git a/app/src/main/java/com/tangem/tap/common/feedback/FeedbackDataBuilder.kt b/app/src/main/java/com/tangem/tap/common/feedback/FeedbackDataBuilder.kt
index 9e5378e9e5..a3a9ee5575 100644
--- a/app/src/main/java/com/tangem/tap/common/feedback/FeedbackDataBuilder.kt
+++ b/app/src/main/java/com/tangem/tap/common/feedback/FeedbackDataBuilder.kt
@@ -1,5 +1,7 @@
package com.tangem.tap.common.feedback
+import com.tangem.tap.common.extensions.breakLine
+
class FeedbackDataBuilder(
private val infoHolder: AdditionalFeedbackInfo
) {
@@ -10,8 +12,8 @@ class FeedbackDataBuilder(
return this
}
- fun appendLine(count: Int = 1): FeedbackDataBuilder {
- builder.appendLine(count)
+ fun breakLine(count: Int = 1): FeedbackDataBuilder {
+ builder.breakLine(count)
return this
}
@@ -34,7 +36,7 @@ class FeedbackDataBuilder(
infoHolder.tokens[it.blockchain]?.let { tokens ->
builder.append("Tokens:")
- appendLine()
+ breakLine()
tokens.forEach { token ->
builder.appendKeyValue("Name", token.name)
builder.appendKeyValue("ID", token.id ?: "[custom token]")
@@ -74,8 +76,4 @@ private fun StringBuilder.appendKeyValue(key: String, value: String): StringBuil
return if (value.isNotBlank()) this.append("$key: $value\n") else this
}
-private fun StringBuilder.appendDelimiter(): StringBuilder = append("----------\n")
-
-private fun StringBuilder.appendLine(count: Int = 1): StringBuilder {
- return append(List(count) { "\n" }.joinToString(separator = ""))
-}
\ No newline at end of file
+private fun StringBuilder.appendDelimiter(): StringBuilder = append("----------\n")
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt b/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt
index 20d1eda08c..9e22833682 100644
--- a/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt
+++ b/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt
@@ -5,44 +5,25 @@ import com.tangem.TangemSdk
import com.tangem.blockchain.common.TransactionSigner
import com.tangem.blockchain.common.Wallet
import com.tangem.common.CompletionResult
-import com.tangem.tap.domain.tasks.SignHashTask
+import com.tangem.common.card.Card
import com.tangem.tap.domain.tasks.SignHashesTask
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
class TangemSigner(
+ private val card: Card,
private val tangemSdk: TangemSdk,
private val initialMessage: Message,
private val signerCallback: (TangemSignerResponse) -> Unit,
) : TransactionSigner {
- override suspend fun sign(hash: ByteArray, cardId: String, publicKey: Wallet.PublicKey): CompletionResult {
+ override suspend fun sign(
+ hashes: List,
+ publicKey: Wallet.PublicKey
+ ): CompletionResult> {
return suspendCoroutine { continuation ->
- val command = SignHashTask(hash, publicKey)
- tangemSdk.startSessionWithRunnable(
- runnable = command,
- cardId = cardId,
- initialMessage = initialMessage,
- ) { result ->
- when (result) {
- is CompletionResult.Success -> {
- signerCallback(
- TangemSignerResponse(
- result.data.totalSignedHashes,
- result.data.remainingSignatures
- )
- )
- continuation.resume(CompletionResult.Success(result.data.signature))
- }
- is CompletionResult.Failure ->
- continuation.resume(CompletionResult.Failure(result.error))
- }
- }
- }
- }
+ val cardId = if (card.backupStatus?.isActive == true) null else card.cardId
- override suspend fun sign(hashes: List, cardId: String, publicKey: Wallet.PublicKey): CompletionResult> {
- return suspendCoroutine { continuation ->
val task = SignHashesTask(hashes, publicKey)
tangemSdk.startSessionWithRunnable(
runnable = task,
@@ -65,6 +46,21 @@ class TangemSigner(
}
}
}
+
+ override suspend fun sign(
+ hash: ByteArray,
+ publicKey: Wallet.PublicKey
+ ): CompletionResult {
+ val result = sign(
+ hashes = listOf(hash),
+ publicKey = publicKey
+ )
+
+ return when (result) {
+ is CompletionResult.Success -> CompletionResult.Success(result.data.first())
+ is CompletionResult.Failure -> CompletionResult.Failure(result.error)
+ }
+ }
}
data class TangemSignerResponse(
diff --git a/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt b/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt
index e636c4fa07..34b8289884 100644
--- a/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt
+++ b/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt
@@ -32,9 +32,10 @@ fun WalletManagerFactory.makeWalletManagerForApp(
return when {
scanResponse.isTangemTwins() && scanResponse.secondTwinPublicKey != null -> {
makeTwinWalletManager(
- card.cardId,
- wallet.publicKey, scanResponse.secondTwinPublicKey!!.hexToBytes(),
- environmentBlockchain, wallet.curve
+ walletPublicKey = wallet.publicKey,
+ pairPublicKey = scanResponse.secondTwinPublicKey!!.hexToBytes(),
+ blockchain = environmentBlockchain,
+ curve = wallet.curve
)
}
seedKey != null && derivationParams != null -> {
@@ -47,7 +48,6 @@ fun WalletManagerFactory.makeWalletManagerForApp(
?: return null
makeWalletManager(
- cardId = card.cardId,
blockchain = environmentBlockchain,
seedKey = wallet.publicKey,
derivedKey = derivedKey,
@@ -56,7 +56,6 @@ fun WalletManagerFactory.makeWalletManagerForApp(
}
else -> {
makeWalletManager(
- cardId = card.cardId,
blockchain = environmentBlockchain,
walletPublicKey = wallet.publicKey,
curve = wallet.curve
diff --git a/app/src/main/java/com/tangem/tap/domain/statePrinter/WalletStateConverter.kt b/app/src/main/java/com/tangem/tap/domain/statePrinter/WalletStateConverter.kt
index 07ac4886bb..57762aaf51 100644
--- a/app/src/main/java/com/tangem/tap/domain/statePrinter/WalletStateConverter.kt
+++ b/app/src/main/java/com/tangem/tap/domain/statePrinter/WalletStateConverter.kt
@@ -57,7 +57,6 @@ class WalletStateConverter : StringStateConverter {
walletMap["publicKey"] = publicKeyMap
walletMap["amounts"] = amounts
walletMap["addresses"] = wallet.addresses.toString()
- walletMap["cardId"] = wallet.cardId
return walletMap
}
diff --git a/app/src/main/java/com/tangem/tap/domain/termsOfUse/CardTou.kt b/app/src/main/java/com/tangem/tap/domain/termsOfUse/CardTou.kt
index 032c0b97ca..f05065bc8d 100644
--- a/app/src/main/java/com/tangem/tap/domain/termsOfUse/CardTou.kt
+++ b/app/src/main/java/com/tangem/tap/domain/termsOfUse/CardTou.kt
@@ -4,16 +4,17 @@ import android.content.res.Resources
import android.net.Uri
import androidx.core.os.ConfigurationCompat
import com.tangem.common.card.Card
-import java.util.*
+import java.util.Locale
/**
[REDACTED_AUTHOR]
*/
class CardTou {
- private val locale: Locale = ConfigurationCompat.getLocales(Resources.getSystem().configuration).get(0)
+ private val locale: Locale =
+ ConfigurationCompat.getLocales(Resources.getSystem().configuration).get(0)!!
fun getUrl(card: Card): Uri? {
- val issuerName = card.issuer.name ?: return null
+ val issuerName = card.issuer.name
if (issuerName.lowercase(Locale.getDefault()) != "start2coin") return null
val baseUrl = "https://app.tangem.com/tou/"
diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect/EthSignHelper.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect/EthSignHelper.kt
index fe8a593787..b366229775 100644
--- a/app/src/main/java/com/tangem/tap/domain/walletconnect/EthSignHelper.kt
+++ b/app/src/main/java/com/tangem/tap/domain/walletconnect/EthSignHelper.kt
@@ -1,11 +1,13 @@
package com.tangem.tap.domain.walletconnect
import com.github.salomonbrys.kotson.fromJson
+import com.github.salomonbrys.kotson.toMap
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.JsonArray
import com.google.gson.JsonParser
import com.google.gson.annotations.SerializedName
+import com.tangem.blockchain.common.Blockchain
import com.trustwallet.walletconnect.JSONRPC_VERSION
import com.trustwallet.walletconnect.models.ethereum.WCEthereumSignMessage
@@ -18,9 +20,11 @@ class EthSignHelper {
.create()
}
- fun tryToParseEthTypedMessage(data: String): WCEthereumSignMessage? {
- val request =
- gson.fromJson(data)
+ fun parseCustomRequest(data: String): CustomJsonRpcRequest {
+ return gson.fromJson(data)
+ }
+
+ fun tryToParseEthTypedMessage(request: CustomJsonRpcRequest): WCEthereumSignMessage? {
return if (request.method == WCMethodExtended.ETH_SIGN_TYPE_DATA_V4) {
WCEthereumSignMessage(
listOf(
@@ -53,12 +57,26 @@ class EthSignHelper {
}
}
-data class CustomJsonRpcRequests(
+data class CustomJsonRpcRequest(
val id: Long,
val jsonrpc: String = JSONRPC_VERSION,
val method: WCMethodExtended?,
val params: JsonArray
-)
+) {
+
+ fun blockchainFromChainId(): Blockchain? {
+ return try {
+ val hex = params[0].asJsonObject.toMap()[CHAIN_ID_KEY]?.asString ?: ""
+ Blockchain.fromChainId(Integer.decode(hex))
+ } catch (exception: Exception) {
+ null
+ }
+ }
+
+ companion object {
+ const val CHAIN_ID_KEY = "chainId"
+ }
+}
enum class WCMethodExtended {
@SerializedName("wc_sessionRequest")
@@ -95,5 +113,10 @@ enum class WCMethodExtended {
GET_ACCOUNTS,
@SerializedName("trust_signTransaction")
- SIGN_TRANSACTION;
+ SIGN_TRANSACTION,
+
+ @SerializedName("wallet_switchEthereumChain")
+ SWITCH_CHAIN,
+
+ ;
}
\ No newline at end of file
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 dd94266b06..7d36064f1e 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
@@ -11,14 +11,20 @@ import com.tangem.tap.store
import com.tangem.tap.walletConnectRepository
import com.trustwallet.walletconnect.WCClient
import com.trustwallet.walletconnect.models.WCPeerMeta
-import com.trustwallet.walletconnect.models.binance.*
+import com.trustwallet.walletconnect.models.binance.WCBinanceCancelOrder
+import com.trustwallet.walletconnect.models.binance.WCBinanceTradeOrder
+import com.trustwallet.walletconnect.models.binance.WCBinanceTransferOrder
+import com.trustwallet.walletconnect.models.binance.WCBinanceTxConfirmParam
import com.trustwallet.walletconnect.models.ethereum.WCEthereumSignMessage
import com.trustwallet.walletconnect.models.ethereum.WCEthereumTransaction
import com.trustwallet.walletconnect.models.session.WCSession
import com.trustwallet.walletconnect.models.session.WCSessionUpdate
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
-import okhttp3.*
+import okhttp3.Interceptor
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.Response
import okhttp3.logging.HttpLoggingInterceptor
import timber.log.Timber
import java.util.*
@@ -71,6 +77,22 @@ class WalletConnectManager {
}
}
+ fun updateBlockchain(session: WalletConnectSession) {
+ sessions[session.session]?.client?.updateSession(
+ accounts = listOfNotNull(session.getAddress()),
+ chainId = session.wallet.blockchain?.getChainId(),
+ approved = true
+ )
+
+
+ val updatedSession = sessions[session.session]?.copy(
+ wallet = session.wallet
+ )
+ if (updatedSession != null) {
+ sessions[session.session] = updatedSession
+ }
+ }
+
private fun setupConnectionTimeoutCheck(session: WCSession) {
scope.launch {
delay(20_000)
@@ -409,23 +431,43 @@ class WalletConnectManager {
Timber.d("Custom Request")
Timber.d(data)
- val message = EthSignHelper.tryToParseEthTypedMessage(data)
- if (message != null) {
- Timber.d("onEthSign_v4: $message")
- store.state.globalState.analyticsHandlers?.logWcEvent(
- Analytics.WcAnalyticsEvent.Action(
- Analytics.WcAction.PersonalSign
+ val request = EthSignHelper.parseCustomRequest(data)
+
+ when (request.method) {
+ WCMethodExtended.ETH_SIGN_TYPE_DATA_V4 -> handleTypedDataV4(request, client, id)
+ WCMethodExtended.SWITCH_CHAIN -> {
+ val blockchain = request.blockchainFromChainId()
+ Timber.d("WC switch chainID\nNew Blockchain: $blockchain")
+ val session = sessions[client.session]?.toWalletConnectSession()
+ if (session != null) {
+ store.dispatchOnMain(WalletConnectAction.SwitchBlockchain(blockchain, session))
+ }
+ }
+ else -> {
+ Timber.d("WC: unrecognized custom request")
+ }
+ }
+ }
+
+ }
+
+ private fun handleTypedDataV4(request: CustomJsonRpcRequest, client: WCClient, id: Long) {
+ val message = EthSignHelper.tryToParseEthTypedMessage(request)
+ if (message != null) {
+ Timber.d("onEthSign_v4: $message")
+ store.state.globalState.analyticsHandlers?.logWcEvent(
+ Analytics.WcAnalyticsEvent.Action(
+ Analytics.WcAction.PersonalSign
+ )
+ )
+ sessions[client.session]?.toWalletConnectSession()?.let { sessionData ->
+ store.dispatchOnMain(
+ WalletConnectAction.HandlePersonalSignRequest(
+ message,
+ sessionData,
+ id
)
)
- sessions[client.session]?.toWalletConnectSession()?.let { sessionData ->
- store.dispatchOnMain(
- WalletConnectAction.HandlePersonalSignRequest(
- message,
- sessionData,
- id
- )
- )
- }
}
}
}
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 1d0dc4a9e0..a3b0d31a89 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
@@ -5,8 +5,17 @@ import com.tangem.blockchain.blockchains.ethereum.EthereumGasLoader
import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionExtras
import com.tangem.blockchain.blockchains.ethereum.EthereumUtils
import com.tangem.blockchain.blockchains.ethereum.EthereumUtils.Companion.toKeccak
-import com.tangem.blockchain.common.*
-import com.tangem.blockchain.extensions.*
+import com.tangem.blockchain.common.Amount
+import com.tangem.blockchain.common.AmountType
+import com.tangem.blockchain.common.CommonSigner
+import com.tangem.blockchain.common.TransactionData
+import com.tangem.blockchain.common.TransactionSender
+import com.tangem.blockchain.common.Wallet
+import com.tangem.blockchain.common.WalletManager
+import com.tangem.blockchain.extensions.Result
+import com.tangem.blockchain.extensions.SimpleResult
+import com.tangem.blockchain.extensions.hexToBigDecimal
+import com.tangem.blockchain.extensions.isAscii
import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.hexToBytes
@@ -17,7 +26,11 @@ import com.tangem.operations.sign.SignHashCommand
import com.tangem.tap.common.analytics.Analytics
import com.tangem.tap.common.extensions.safeUpdate
import com.tangem.tap.common.extensions.toFormattedString
-import com.tangem.tap.features.details.redux.walletconnect.*
+import com.tangem.tap.features.details.redux.walletconnect.WalletConnectSession
+import com.tangem.tap.features.details.redux.walletconnect.WalletForSession
+import com.tangem.tap.features.details.redux.walletconnect.WcPersonalSignData
+import com.tangem.tap.features.details.redux.walletconnect.WcTransactionData
+import com.tangem.tap.features.details.redux.walletconnect.WcTransactionType
import com.tangem.tap.features.details.ui.walletconnect.dialogs.PersonalSignDialogData
import com.tangem.tap.features.details.ui.walletconnect.dialogs.TransactionRequestDialogData
import com.tangem.tap.store
@@ -25,8 +38,8 @@ import com.tangem.tap.tangemSdk
import com.tangem.tap.tangemSdkManager
import com.trustwallet.walletconnect.models.ethereum.WCEthereumSignMessage
import com.trustwallet.walletconnect.models.ethereum.WCEthereumTransaction
-import timber.log.Timber
import java.math.BigDecimal
+import timber.log.Timber
class WalletConnectSdkHelper {
@@ -108,9 +121,8 @@ class WalletConnectSdkHelper {
)
val blockchain = session.wallet.getBlockchainForSession()
return factory.makeWalletManager(
- session.wallet.cardId,
- blockchain,
- publicKey
+ blockchain = blockchain,
+ publicKey = publicKey
)
}
@@ -124,7 +136,7 @@ class WalletConnectSdkHelper {
private suspend fun sendTransaction(data: WcTransactionData): String? {
val result = (data.walletManager as TransactionSender).send(
transactionData = data.transaction,
- signer = Signer(tangemSdk)
+ signer = CommonSigner(tangemSdk)
)
return when (result) {
SimpleResult.Success -> {
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
new file mode 100644
index 0000000000..7c978b7b6f
--- /dev/null
+++ b/app/src/main/java/com/tangem/tap/domain/walletconnect/WcWalletManagerFactory.kt
@@ -0,0 +1,95 @@
+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
+import com.tangem.tap.features.details.redux.walletconnect.WalletForSession
+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
+ ): WalletManager? {
+ val blockchainToMake = if (blockchain == Blockchain.Ethereum && wallet.isTestNet) {
+ Blockchain.EthereumTestnet
+ } else {
+ blockchain
+ }
+
+ val blockchainNetwork = BlockchainNetwork(
+ blockchain = blockchainToMake,
+ derivationPath = wallet.derivationPath?.rawPath,
+ 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(
+ cardId = wallet.cardId,
+ blockchain = blockchainToMake,
+ publicKey = Wallet.PublicKey(
+ wallet.walletPublicKey!!,
+ wallet.derivedPublicKey,
+ wallet.derivationPath
+ ),
+ tokens = blockchainNetworkWithTokens.tokens,
+ curve = blockchainToMake.getPrimaryCurve() ?: EllipticCurve.Secp256k1
+ )
+ } else {
+ null
+ }
+ }
+ }
+
+ suspend fun getWalletManager(
+ scanResponse: ScanResponse, blockchain: Blockchain, walletState: WalletState
+ ): WalletManager? {
+ val card = scanResponse.card
+ val blockchainToMake = if (blockchain == Blockchain.Ethereum && card.isTestCard) {
+ Blockchain.EthereumTestnet
+ } else {
+ blockchain
+ }
+
+ val blockchainNetwork = BlockchainNetwork(
+ blockchain = blockchainToMake,
+ card = card
+ )
+
+ return if (walletState.cardId == card.cardId) {
+ walletState.getWalletManager(blockchainNetwork)
+ } else {
+ if (currenciesRepository
+ .loadSavedCurrencies(card.cardId, card.settings.isHDWalletAllowed)
+ .contains(blockchainNetwork)
+ ) {
+ factory.makeWalletManagerForApp(
+ scanResponse = scanResponse,
+ blockchainNetwork = blockchainNetwork
+ )
+ } else {
+ null
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/demo/DemoHelper.kt b/app/src/main/java/com/tangem/tap/features/demo/DemoHelper.kt
index 7fe717e1a5..f7ccf6156a 100644
--- a/app/src/main/java/com/tangem/tap/features/demo/DemoHelper.kt
+++ b/app/src/main/java/com/tangem/tap/features/demo/DemoHelper.kt
@@ -109,7 +109,7 @@ class DemoConfig {
testDemoCardIds).distinct()
}
- private val releaseDemoCardIds = mutableListOf(
+ private val releaseDemoCardIds = mutableListOf(
// Tangem Wallet:
"AC01000000041100",
"AC01000000042462",
@@ -284,7 +284,10 @@ class DemoTransactionSender(
override suspend fun send(transactionData: TransactionData, signer: TransactionSigner): SimpleResult {
val dataToSign = randomString(32).toByteArray()
- val signerResponse = signer.sign(dataToSign, walletManager.wallet.cardId, walletManager.wallet.publicKey)
+ val signerResponse = signer.sign(
+ hash = dataToSign,
+ publicKey = walletManager.wallet.publicKey
+ )
return when (signerResponse) {
is CompletionResult.Success -> SimpleResult.Failure(Exception(ID))
is CompletionResult.Failure -> SimpleResult.fromTangemSdkError(signerResponse.error)
diff --git a/app/src/main/java/com/tangem/tap/features/demo/Extentions.kt b/app/src/main/java/com/tangem/tap/features/demo/Extentions.kt
index 99ecfbc227..66d09bdbf0 100644
--- a/app/src/main/java/com/tangem/tap/features/demo/Extentions.kt
+++ b/app/src/main/java/com/tangem/tap/features/demo/Extentions.kt
@@ -1,10 +1,10 @@
package com.tangem.tap.features.demo
-import com.tangem.blockchain.common.WalletManager
+import com.tangem.common.card.Card
import com.tangem.domain.common.ScanResponse
/**
[REDACTED_AUTHOR]
*/
fun ScanResponse.isDemoCard(): Boolean = DemoHelper.isDemoCardId(card.cardId)
-fun WalletManager.isDemoWallet(): Boolean = DemoHelper.isDemoCardId(wallet.cardId)
\ No newline at end of file
+fun Card.isDemoCard(): Boolean = DemoHelper.isDemoCardId(cardId)
\ No newline at end of file
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 a180d20d4a..471ccaa44c 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 android.app.Activity
+import com.tangem.blockchain.common.Blockchain
import com.tangem.domain.common.ScanResponse
import com.tangem.tap.common.redux.NotificationAction
import com.tangem.wallet.R
@@ -47,6 +48,16 @@ sealed class WalletConnectAction : Action {
data class Success(val session: WalletConnectSession) : WalletConnectAction()
}
+ data class SwitchBlockchain(
+ val blockchain: Blockchain?,
+ val session: WalletConnectSession
+ ) : WalletConnectAction()
+
+ data class UpdateBlockchain(
+ val updatedSession: WalletConnectSession
+ ) : WalletConnectAction()
+
+
data class FailureEstablishingSession(val session: WCSession?) : WalletConnectAction()
data class SetSessionsRestored(val sessions: List) :
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 25c5d373b4..7f7a88748a 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
@@ -1,10 +1,8 @@
package com.tangem.tap.features.details.redux.walletconnect
import com.tangem.blockchain.common.Blockchain
-import com.tangem.blockchain.common.WalletManager
import com.tangem.common.extensions.guard
import com.tangem.domain.common.ScanResponse
-import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.extensions.getFromClipboard
@@ -14,11 +12,10 @@ import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.currenciesRepository
import com.tangem.tap.domain.extensions.isMultiwalletAllowed
-import com.tangem.tap.domain.extensions.makeWalletManagerForApp
-import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.domain.walletconnect.BnbHelper
import com.tangem.tap.domain.walletconnect.WalletConnectManager
import com.tangem.tap.domain.walletconnect.WalletConnectNetworkUtils
+import com.tangem.tap.domain.walletconnect.WcWalletManagerFactory
import com.tangem.tap.features.demo.DemoHelper
import com.tangem.tap.scope
import com.tangem.tap.store
@@ -159,6 +156,45 @@ class WalletConnectMiddleware {
action.id, action.data, action.sessionData
)
}
+ is WalletConnectAction.SwitchBlockchain -> {
+ val blockchain = action.blockchain.guard {
+ store.dispatchOnMain(GlobalAction.ShowDialog(WalletConnectDialog.UnsupportedNetwork))
+ return
+ }
+
+ val factory = WcWalletManagerFactory(
+ factory = store.state.globalState.tapWalletManager.walletManagerFactory,
+ 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 updatedSession = action.session.copy(wallet = updatedWallet)
+ store.dispatchOnMain(WalletConnectAction.UpdateBlockchain(updatedSession))
+ }
+ }
+ is WalletConnectAction.UpdateBlockchain -> {
+ walletConnectManager.updateBlockchain(action.updatedSession)
+ }
}
}
@@ -189,8 +225,13 @@ class WalletConnectMiddleware {
return
}
+ val factory = WcWalletManagerFactory(
+ factory = store.state.globalState.tapWalletManager.walletManagerFactory,
+ currenciesRepository = currenciesRepository
+ )
+ val walletState = store.state.walletState
scope.launch {
- val walletManager = getWalletManager(scanResponse, blockchain).guard {
+ val walletManager = factory.getWalletManager(scanResponse, blockchain, walletState).guard {
store.dispatchOnMain(WalletConnectAction.FailureEstablishingSession(session.session))
store.dispatchOnMain(
GlobalAction.ShowDialog(
@@ -232,37 +273,4 @@ class WalletConnectMiddleware {
}
}
-
- private suspend fun getWalletManager(
- scanResponse: ScanResponse, blockchain: Blockchain
- ): WalletManager? {
- val card = scanResponse.card
- val factory = store.state.globalState.tapWalletManager.walletManagerFactory
- val blockchainToMake = if (blockchain == Blockchain.Ethereum && card.isTestCard) {
- Blockchain.EthereumTestnet
- } else {
- blockchain
- }
-
- val blockchainNetwork = BlockchainNetwork(
- blockchain = blockchainToMake,
- card = card
- )
-
- return if (store.state.globalState.scanResponse?.card?.cardId == card.cardId) {
- store.state.walletState.getWalletManager(blockchainNetwork)
- } else {
- if (currenciesRepository
- .loadSavedCurrencies(card.cardId, card.settings.isHDWalletAllowed)
- .contains(blockchainNetwork)
- ) {
- factory.makeWalletManagerForApp(
- scanResponse = scanResponse,
- blockchainNetwork = blockchainNetwork
- )
- } else {
- null
- }
- }
- }
}
\ No newline at end of file
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 216367e9ee..191fa7b170 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
@@ -34,6 +34,11 @@ class WalletConnectReducer {
is WalletConnectAction.RefuseOpeningSession -> state.copy(loading = false)
is WalletConnectAction.OpeningSessionTimeout -> state.copy(loading = false)
is WalletConnectAction.FailureEstablishingSession -> state.copy(loading = false)
+ is WalletConnectAction.UpdateBlockchain -> state.copy(
+ sessions = state.sessions
+ .filterNot { it.peerId == action.updatedSession.peerId }
+ + action.updatedSession
+ )
else -> state
}
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 4f5861c67b..fbd95c6393 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
@@ -82,6 +82,7 @@ data class WalletForSession(
sealed class WalletConnectDialog : StateDialog {
data class ClipboardOrScanQr(val clipboardUri: String) : WalletConnectDialog()
object UnsupportedCard : WalletConnectDialog()
+ object UnsupportedNetwork : WalletConnectDialog()
data class AddNetwork(val network: String) : WalletConnectDialog()
object OpeningSessionRejected : WalletConnectDialog()
object SessionTimeout : WalletConnectDialog()
diff --git a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt
index c453cdadc4..f1b3fa3f55 100644
--- a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt
+++ b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt
@@ -1,10 +1,14 @@
package com.tangem.tap.features.home
import android.os.Bundle
+import android.view.LayoutInflater
import android.view.View
+import android.view.ViewGroup
+import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.platform.ComposeView
+import androidx.core.view.WindowInsetsControllerCompat
import androidx.fragment.app.Fragment
import com.google.accompanist.appcompattheme.AppCompatTheme
import com.tangem.tap.common.redux.navigation.AppScreen
@@ -15,48 +19,36 @@ import com.tangem.tap.features.home.redux.HomeState
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction
import com.tangem.tap.features.tokens.redux.TokensAction
import com.tangem.tap.store
-import com.tangem.wallet.R
import org.rekotlin.StoreSubscriber
-class HomeFragment : Fragment(R.layout.fragment_home), StoreSubscriber {
+class HomeFragment : Fragment(), StoreSubscriber {
- var homeState: MutableState = mutableStateOf(store.state.homeState)
+ private var homeState: MutableState = mutableStateOf(store.state.homeState)
+ private var composeView: ComposeView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
store.dispatch(HomeAction.Init)
}
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?,
+ ): View? {
+ val context = container?.context ?: return null
store.dispatch(BackupAction.CheckForUnfinishedBackup)
-
-
- getView()?.findViewById(R.id.cv_stories)?.setContent {
- AppCompatTheme {
- StoriesScreen(
- homeState,
- onScanButtonClick = { store.dispatch(HomeAction.ReadCard) },
- onShopButtonClick = {
- store.dispatch(HomeAction.GoToShop(store.state.globalState.userCountryCode))
- },
- onSearchTokensClick = {
- store.dispatch(NavigationAction.NavigateTo(AppScreen.AddTokens))
- store.dispatch(TokensAction.AllowToAddTokens(false))
- store.dispatch(TokensAction.LoadCurrencies())
- }
- )
+ composeView = ComposeView(context).apply {
+ setContent {
+ AppCompatTheme {
+ ScreenContent()
+ }
}
}
- }
- private fun getRegionProvider(): RegionProvider = RegionService(
- listOf(
-// TelephonyManagerRegionProvider(requireContext()),
- LocaleRegionProvider()
- )
- )
+ return composeView
+ }
override fun onStart() {
super.onStart()
@@ -72,6 +64,11 @@ class HomeFragment : Fragment(R.layout.fragment_home), StoreSubscriber
+ val signer = TangemSigner(
+ card = card,
+ tangemSdk = tangemSdk,
+ initialMessage = action.messageForSigner
+ ) { signResponse ->
store.dispatch(
GlobalAction.UpdateWalletSignedHashes(
walletSignedHashes = signResponse.totalSignedHashes,
@@ -171,7 +189,7 @@ private fun sendTransaction(
)
}
val sendResult = try {
- if (walletManager.isDemoWallet()) {
+ if (card.isDemoCard()) {
DemoTransactionSender(walletManager).send(txData, signer)
} else {
(walletManager as TransactionSender).send(txData, signer)
@@ -340,5 +358,4 @@ private fun updateWarnings(dispatch: (Action) -> Unit) {
val warnings = warningsManager.getWarnings(WarningMessage.Location.SendScreen, listOf(blockchain))
dispatch(SendAction.Warnings.Set(warnings))
-}
-
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt
index ba70c84e05..21489b82f3 100644
--- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt
+++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt
@@ -73,6 +73,9 @@ data class WalletState(
val walletManagers: List
get() = wallets.mapNotNull { it.walletManager }
+ val cardId: String?
+ get() = wallets.firstOrNull()?.walletManager?.wallet?.cardId
+
fun getWalletManager(currency: Currency?): WalletManager? {
if (currency?.blockchain == null) return null
return getWalletStore(currency)?.walletManager
diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt
index a7ee50446d..064647d863 100644
--- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt
+++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt
@@ -45,6 +45,7 @@ class TradeCryptoMiddleware {
val selectedWalletData = store.state.walletState.getSelectedWalletData() ?: return
val exchangeManager = store.state.globalState.exchangeManager ?: return
+ val card = store.state.globalState.scanResponse?.card ?: return
val appCurrency = store.state.globalState.appCurrency
val addresses = selectedWalletData.walletAddresses?.list.orEmpty()
@@ -59,7 +60,13 @@ class TradeCryptoMiddleware {
return
}
- scope.launch { exchangeManager.buyErc20TestnetTokens(walletManager, currency.token) }
+ scope.launch {
+ exchangeManager.buyErc20TestnetTokens(
+ card = card,
+ walletManager = walletManager,
+ token = currency.token
+ )
+ }
return
}
diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt
index 7a4ac13ea5..7c63b551f9 100644
--- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt
+++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt
@@ -1,8 +1,5 @@
package com.tangem.tap.features.wallet.redux.middlewares
-import android.content.Intent
-import android.net.Uri
-import androidx.core.content.ContextCompat
import com.tangem.blockchain.blockchains.solana.RentProvider
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.AmountType
@@ -15,12 +12,7 @@ import com.tangem.domain.common.extensions.withMainContext
import com.tangem.operations.attestation.Attestation
import com.tangem.operations.attestation.OnlineCardVerifier
import com.tangem.tap.common.analytics.Analytics
-import com.tangem.tap.common.extensions.copyToClipboard
-import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
-import com.tangem.tap.common.extensions.dispatchOnMain
-import com.tangem.tap.common.extensions.onCardScanned
-import com.tangem.tap.common.extensions.shareText
-import com.tangem.tap.common.extensions.stripZeroPlainString
+import com.tangem.tap.common.extensions.*
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.common.redux.navigation.AppScreen
@@ -233,9 +225,7 @@ class WalletMiddleware {
action.context.shareText(action.address)
}
is WalletAction.ExploreAddress -> {
- val uri = Uri.parse(action.exploreUrl)
- val intent = Intent(Intent.ACTION_VIEW, uri)
- ContextCompat.startActivity(action.context, intent, null)
+ store.dispatchOpenUrl(action.exploreUrl)
}
is WalletAction.Send -> {
val newAction = prepareSendAction(action.amount, store.state.walletState)
diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt
index 176fa48a14..73f315e29b 100644
--- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt
+++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt
@@ -13,6 +13,7 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.transition.TransitionInflater
import by.kirich1409.viewbindingdelegate.viewBinding
import coil.load
+import coil.size.Scale
import com.tangem.tap.MainActivity
import com.tangem.tap.common.extensions.show
import com.tangem.tap.common.recyclerView.SpaceItemDecoration
@@ -166,6 +167,8 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber onSuccess() },
diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/images/CurrencyIconView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/images/CurrencyIconView.kt
new file mode 100644
index 0000000000..35d89aaa27
--- /dev/null
+++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/images/CurrencyIconView.kt
@@ -0,0 +1,30 @@
+package com.tangem.tap.features.wallet.ui.images
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import androidx.constraintlayout.utils.widget.ImageFilterView
+import com.google.android.material.card.MaterialCardView
+import com.tangem.tangem_sdk_new.extensions.dpToPx
+import com.tangem.wallet.databinding.ViewCurrencyIconBinding
+
+class CurrencyIconView @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+) : MaterialCardView(context, attrs, defStyleAttr) {
+ private val binding = ViewCurrencyIconBinding.inflate(
+ LayoutInflater.from(context),
+ this
+ )
+
+ val imageView: ImageFilterView
+ get() = binding.iv
+
+ init {
+ elevation = 0f
+ cardElevation = 0f
+ radius = dpToPx(8f)
+ background = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/CurrencyExchangeManager.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/CurrencyExchangeManager.kt
index 811c9c0545..8d1085d316 100644
--- a/app/src/main/java/com/tangem/tap/network/exchangeServices/CurrencyExchangeManager.kt
+++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/CurrencyExchangeManager.kt
@@ -7,6 +7,7 @@ import com.tangem.blockchain.common.AmountType
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.Token
import com.tangem.blockchain.extensions.Result
+import com.tangem.common.card.Card
import com.tangem.tap.common.extensions.safeUpdate
import com.tangem.tap.common.redux.global.CryptoCurrencyName
import com.tangem.tap.common.redux.global.GlobalAction
@@ -68,7 +69,11 @@ class CurrencyExchangeManager(
enum class Action { Buy, Sell }
}
-suspend fun CurrencyExchangeManager.buyErc20TestnetTokens(walletManager: EthereumWalletManager, token: Token) {
+suspend fun CurrencyExchangeManager.buyErc20TestnetTokens(
+ card: Card,
+ walletManager: EthereumWalletManager,
+ token: Token,
+) {
walletManager.safeUpdate()
val amountToSend = Amount(walletManager.wallet.blockchain)
@@ -85,7 +90,9 @@ suspend fun CurrencyExchangeManager.buyErc20TestnetTokens(walletManager: Ethereu
val transaction = walletManager.createTransaction(amountToSend, fee, destinationAddress)
val signer = TangemSigner(
- tangemSdk = tangemSdk, Message()
+ card = card,
+ tangemSdk = tangemSdk,
+ initialMessage = Message(),
) { signResponse ->
store.dispatch(
GlobalAction.UpdateWalletSignedHashes(
diff --git a/app/src/main/res/drawable/ic_overlay.xml b/app/src/main/res/drawable/ic_overlay.xml
index 586397f855..5487da88f8 100644
--- a/app/src/main/res/drawable/ic_overlay.xml
+++ b/app/src/main/res/drawable/ic_overlay.xml
@@ -4,10 +4,18 @@
-
-
-
+
+
+
diff --git a/app/src/main/res/drawable/shape_badge_custom_currency.xml b/app/src/main/res/drawable/shape_badge_custom_currency.xml
index 2c3b7f7bd4..cfd740103d 100644
--- a/app/src/main/res/drawable/shape_badge_custom_currency.xml
+++ b/app/src/main/res/drawable/shape_badge_custom_currency.xml
@@ -7,7 +7,7 @@
android:height="12dp" />
diff --git a/app/src/main/res/drawable/shape_rectangle_rounded_8.xml b/app/src/main/res/drawable/shape_rectangle_rounded_8.xml
index a788f39093..4f20cb0e64 100644
--- a/app/src/main/res/drawable/shape_rectangle_rounded_8.xml
+++ b/app/src/main/res/drawable/shape_rectangle_rounded_8.xml
@@ -5,4 +5,4 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
deleted file mode 100644
index 7a95116cd8..0000000000
--- a/app/src/main/res/layout/fragment_home.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/fragment_wallet.xml b/app/src/main/res/layout/fragment_wallet.xml
index e77908ee26..102ae199f4 100644
--- a/app/src/main/res/layout/fragment_wallet.xml
+++ b/app/src/main/res/layout/fragment_wallet.xml
@@ -18,14 +18,14 @@
app:liftOnScroll="true">
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ app:menu="@menu/wallet"
+ app:navigationIcon="@drawable/ic_wallet_24"
+ app:navigationIconTint="@color/darkGray6"
+ app:title="@string/wallet_title"
+ app:titleCentered="true" />
@@ -43,44 +43,44 @@
android:overScrollMode="never">
+ android:id="@+id/cl_wallet"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipToPadding="false"
+ android:paddingBottom="74dp">
+ android:id="@+id/iv_card"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:layout_marginTop="8dp"
+ android:layout_marginEnd="16dp"
+ android:layout_marginBottom="12dp"
+ android:adjustViewBounds="true"
+ android:contentDescription="@null"
+ android:elevation="3dp"
+ android:maxHeight="215dp"
+ android:scaleType="fitCenter"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:src="@drawable/card_placeholder_black" />
-
-
-
-
-
-
+ app:layout_constraintTop_toBottomOf="@id/barrier" />
+
+
+
+
+
+
-
+ android:id="@+id/rv_multiwallet"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:nestedScrollingEnabled="false"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/rv_pending_transaction" />
+ android:id="@+id/l_buttons_long"
+ layout="@layout/layout_wallet_long_buttons"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:layout_marginTop="30dp"
+ android:layout_marginEnd="16dp"
+ android:visibility="gone"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/l_address"
+ app:layout_constraintVertical_bias="1" />
+ android:id="@+id/l_buttons_short"
+ layout="@layout/layout_wallet_short_buttons"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:layout_marginTop="30dp"
+ android:layout_marginEnd="16dp"
+ android:visibility="gone"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/l_address"
+ app:layout_constraintVertical_bias="1" />
+
+
-
-
-
-
-
diff --git a/app/src/main/res/layout/item_currency_wallet.xml b/app/src/main/res/layout/item_currency_wallet.xml
index de692cfa83..9ac49b1ad9 100644
--- a/app/src/main/res/layout/item_currency_wallet.xml
+++ b/app/src/main/res/layout/item_currency_wallet.xml
@@ -16,45 +16,62 @@
android:elevation="3dp">
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="12dp"
+ android:paddingBottom="12dp"
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp"
+ android:animateLayoutChanges="true"
+ android:clipToPadding="false">
-
+
+
+
+ android:id="@+id/badge_custom_balance"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:background="@drawable/shape_badge_custom_currency"
+ android:visibility="gone"
+ app:layout_constraintBottom_toBottomOf="@id/iv_currency"
+ app:layout_constraintEnd_toEndOf="@id/iv_currency"
+ tools:visibility="visible" />
-
+ app:layout_constraintTop_toTopOf="parent" />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/view_currency_icon.xml b/app/src/main/res/layout/view_currency_icon.xml
new file mode 100644
index 0000000000..6859d75600
--- /dev/null
+++ b/app/src/main/res/layout/view_currency_icon.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/values-de/strings_final.xml b/app/src/main/res/values-de/strings_final.xml
index 97ba0b8f36..b16f96f533 100644
--- a/app/src/main/res/values-de/strings_final.xml
+++ b/app/src/main/res/values-de/strings_final.xml
@@ -59,6 +59,7 @@
The %s token is the main currency on the %s network and cannot be hidden as long as you have other tokens on this network in the list.
%s network not found. Please, add it first and try again.
+ This network is not supported. Please select another network.
%s network
Security & Privacy
diff --git a/app/src/main/res/values-fr/strings_final.xml b/app/src/main/res/values-fr/strings_final.xml
index 5f6407ce70..027a27e7a8 100644
--- a/app/src/main/res/values-fr/strings_final.xml
+++ b/app/src/main/res/values-fr/strings_final.xml
@@ -59,6 +59,7 @@
The %s token is the main currency on the %s network and cannot be hidden as long as you have other tokens on this network in the list.
%s network not found. Please, add it first and try again.
+ This network is not supported. Please select another network.
%s network
Security & Privacy
diff --git a/app/src/main/res/values-it/strings_final.xml b/app/src/main/res/values-it/strings_final.xml
index 5f6407ce70..2645b859e0 100644
--- a/app/src/main/res/values-it/strings_final.xml
+++ b/app/src/main/res/values-it/strings_final.xml
@@ -59,6 +59,8 @@
The %s token is the main currency on the %s network and cannot be hidden as long as you have other tokens on this network in the list.
%s network not found. Please, add it first and try again.
+ This network is not supported. Please select another network.
+
%s network
Security & Privacy
diff --git a/app/src/main/res/values-ru/strings_final.xml b/app/src/main/res/values-ru/strings_final.xml
index a7309bed9c..158fab15b2 100644
--- a/app/src/main/res/values-ru/strings_final.xml
+++ b/app/src/main/res/values-ru/strings_final.xml
@@ -61,9 +61,12 @@
Скрыть
Вы скрываете токен с главного экрана, но в любой момент сможете добавить его обратно.
Невозможно скрыть %s
- Токен %s является основной валютой в сети %s и не может быть скрыт, до тех пор пока у вас в списке есть другие токены этой сети.
+
+ Токен %s является основной валютой в сети %s и не может быть скрыт до тех пор, пока у вас в списке есть другие токены этой сети.
Сеть %s не найдена. Пожалуйста, добавьте её и попробуйте заново.
+ Сеть не поддерживается. Пожалуйста, выберите другую сеть.
+
Сеть %s
Бэкап кошелька не был произведен
diff --git a/app/src/main/res/values/strings_final.xml b/app/src/main/res/values/strings_final.xml
index 958f8f3c5e..daca6f30ab 100644
--- a/app/src/main/res/values/strings_final.xml
+++ b/app/src/main/res/values/strings_final.xml
@@ -64,6 +64,8 @@
The %s token is the main currency on the %s network and cannot be hidden as long as you have other tokens on this network in the list.
%s network not found. Please, add it first and try again.
+ This network is not supported. Please select another network.
+
%s network
Your wallet has not been backed up
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index f36d1cd4bf..09cdff0b35 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -5,10 +5,6 @@
- @color/colorPrimary
- @color/colorSecondary
- @color/darkGray6
- - true
- - true
- - true
- - @null
- @color/menu_accent_color
- @style/Widget.AppTheme.CardView
diff --git a/app/src/main/res/values/zendesk_styles.xml b/app/src/main/res/values/zendesk_styles.xml
index ebb4fcab6b..0022b241b1 100644
--- a/app/src/main/res/values/zendesk_styles.xml
+++ b/app/src/main/res/values/zendesk_styles.xml
@@ -4,4 +4,15 @@
- @color/darkGray6
- @color/darkGray6
+
+ // Contact us FAB style
+
diff --git a/dependencies.gradle b/dependencies.gradle
index 45200c5dcf..b4a597ff72 100644
--- a/dependencies.gradle
+++ b/dependencies.gradle
@@ -1,12 +1,12 @@
ext.versions = [
kotlin : '1.6.10',
build_gradle : '7.1.3',
- tamgem_card_sdk : 'develop-154',
- tamgem_blockchain_sdk: 'develop-93',
+ tamgem_card_sdk : 'develop-156',
+ tamgem_blockchain_sdk: 'develop-96',
]
ext.environmentConfig = [
environment : "ENVIRONMENT",
testActionEnabled: "TEST_ACTION_ENABLED",
logEnabled : "LOG_ENABLED",
-]
\ No newline at end of file
+]
diff --git a/domain/build.gradle b/domain/build.gradle
index d7a8832fd4..f4b0183cc8 100644
--- a/domain/build.gradle
+++ b/domain/build.gradle
@@ -85,4 +85,4 @@ dependencies {
testImplementation "com.google.truth:truth:1.1.3"
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
-}
\ No newline at end of file
+}