diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/blockaid/models/request/EvmTransactionScanRequest.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/blockaid/models/request/EvmTransactionScanRequest.kt index fd5aeecfaf..f0d853d793 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/blockaid/models/request/EvmTransactionScanRequest.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/blockaid/models/request/EvmTransactionScanRequest.kt @@ -18,5 +18,5 @@ data class EvmTransactionScanRequest( data class RpcData( @Json(name = "jsonrpc") val jsonrpc: String = "2.0", @Json(name = "method") val method: String, - @Json(name = "params") val params: String, + @Json(name = "params") val params: List>, ) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/blockaid/models/response/AccountSummaryResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/blockaid/models/response/AccountSummaryResponse.kt index 9b3c4ff0c0..84b23d7583 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/blockaid/models/response/AccountSummaryResponse.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/blockaid/models/response/AccountSummaryResponse.kt @@ -5,7 +5,7 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) data class AccountSummaryResponse( - @Json(name = "assets_diffs") val assetsDiffs: List, - @Json(name = "exposures") val exposures: List, + @Json(name = "assets_diffs") val assetsDiffs: List?, + @Json(name = "exposures") val exposures: List?, @Json(name = "traces") val traces: List?, ) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/blockaid/models/response/Trace.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/blockaid/models/response/Trace.kt index 6ae1af201f..89f2f3db60 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/blockaid/models/response/Trace.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/blockaid/models/response/Trace.kt @@ -11,7 +11,7 @@ data class Trace( @JsonClass(generateAdapter = true) data class Exposed( - @Json(name = "token_id") val tokenId: String, + @Json(name = "token_id") val tokenId: String?, @Json(name = "logo_url") val logoUrl: String?, ) diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index a6b74d1e24..b630fbb909 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -1,6 +1,5 @@ - Erforderliche Mindest-XLM-Reserve %1$s Du kannst Deinen Token nicht finden? Gehe zum Bereich „Markt“ auf der Hauptseite und fügen diesen zum kaufen im Portfolio hinzu. Du kannst Deinen Token nicht finden? Gehe zum Bereich „Markt“ auf der Hauptseite und fügen diesen zum verkaufen im Portfolio hinzu. Verkaufen @@ -337,6 +336,7 @@ Weitere Anbieter folgen in Kürze Anbieter Bester Preis + Warnliste der FCA Verfügbar bis zu %s Erhältlich bei %s Für dieses Paar nicht verfügbar @@ -1222,6 +1222,8 @@ Der zu erhaltende Betrag muss mindestens %s betragen Dies kann passieren, weil der Anbieter derzeit nicht in der Lage ist, dein ausgewähltes Paar zu swappen. Bitte warte einen Moment und versuche es später erneut. (Code %s) Ausgewähltes Paar vorübergehend nicht verfügbar + Einige Anbieter sind nicht von der britischen Finanzaufsichtsbehörde (FCA) zugelassen. Sie sollten den Umgang mit ihnen vermeiden. + Warnliste der FCA Service vorübergehend nicht verfügbar Die Menge der zu tauschenden Token darf folgende Werte nicht überschreiten %s Der zu tauschende Betrag muss mindestens %s betragen @@ -1273,6 +1275,7 @@ Wischen Sie nach unten, um zu aktualisieren, oder versuchen Sie es später erneut. Einige Netzwerke sind nicht erreichbar Einige Token-Guthaben konnten nicht aktualisiert werden + Erforderliche Mindest-XLM-Reserve %1$s Trustline öffnen Trustline-Untermenü öffnen Trustline-Titel öffnen diff --git a/core/res/src/main/res/values-es/strings.xml b/core/res/src/main/res/values-es/strings.xml index 659151f3a2..0421d01d9e 100644 --- a/core/res/src/main/res/values-es/strings.xml +++ b/core/res/src/main/res/values-es/strings.xml @@ -1117,6 +1117,7 @@ El monto a recibir debe ser de al menos %s Esto puede suceder porque el proveedor actualmente no puede operar con el par que usted seleccionó. Espere un momento e inténtelo de nuevo. (Código %s) El par seleccionado no está disponible temporalmente + Algunos proveedores no están autorizados por la Autoridad de Conducta Financiera (FCA) del Reino Unido. Deberías evitar tratar con ellos. Servicio no disponible temporalmente La cantidad de tokens a intercambiar no debe exceder %s El monto a cambiar debe ser de al menos %s diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index 1725c7e069..6e8c8d6142 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -323,6 +323,7 @@ D\'autres fournisseurs arriveront bientôt.\nRestez branchés ! Fournisseur Meilleur taux + Liste d’avertissement de la FCA Disponible jusqu\'à %s Disponible à partir de %s Indisponible pour cette paire @@ -1148,6 +1149,8 @@ Le montant à recevoir doit être d\'au moins %s Cela peut se produire car le fournisseur n\'est actuellement pas en mesure d\'échanger la paire que vous avez sélectionnée. Veuillez patienter un instant et réessayer. (Code %s) La paire sélectionnée est temporairement indisponible + Certains fournisseurs ne sont pas autorisés par la Financial Conduct Authority (FCA) du Royaume-Uni. Vous devriez éviter de traiter avec eux. + Liste d’avertissement de la FCA Service temporairement indisponible Le nombre de jetons à échanger ne doit pas dépasser %s Le montant à échanger doit être d\'au moins %s diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index 786a7ceaf2..5cd0491808 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -267,6 +267,7 @@ %sハッシュ デバイスID サポートへのお問い合わせ + サポートチャットを開く 他のカードをリンクする アプリ通貨 フリップして残高を非表示にする @@ -856,6 +857,8 @@ 無効な金額 手数料が残高を超えています 合計金額が残高を超えています + トークンを送信すれば、送信中に変換されます。受信者は必要なものをシームレスに受け取ります。 + スワップして送信 取引が送信されました 設定したいカードまたはリングをスキャンするために準備してください。 ウォレット削除 @@ -1068,6 +1071,8 @@ 送金元: %s 送金先: %s バリデーター: %s + 通知は有効になっていますが、デバイスの設定で通知を許可するまでは機能しません。 + 取引通知 最小%s 最小取引金額は%1$sです。 Tronネットワークの人気トークンの手数料は高い可能性があります。TRXをステーキングすると、取引コストを削減できる可能性があります。 @@ -1234,6 +1239,7 @@ あなたのレビューは、Tangemウォレットをさらに良くするためのモチベーションになります Tangemを楽しんでいますか? トークンを受け取る前に、トークンを関連付ける必要があります。 + トークンを受け取る前にトラストラインを開く必要があります ネットワーク使用料が必要です 対応が必要です ウォレットの作成後、7日以内にアプリ経由でサポートに連絡しましたか?連絡した場合、あるいは連絡したかわからない場合は、「はい」をクリックして指示に従ってください。 @@ -1249,6 +1255,9 @@ 下にスワイプして更新するか、後でもう一度お試しください。 一部のネットワークにアクセスできません 一部のトークン残高を更新できませんでした + 必要な最低XLMリザーブ %1$s + トラストラインを開く + トラストラインタイトルを開く これはテストネットカードです。取引処理はできませんので、テストおよび開発目的でのみご利用ください。 テスト目的のみ 残高が古い可能性があります。ページを更新してください。 diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index a4bb46b82e..8d442b7857 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -1246,6 +1246,9 @@ Свайпните вниз для обновления или попробуйте позже. Некоторые сети недоступны Некоторые балансы токенов не удалось обновить + Открыть Trustline + Согласно правилам сети, чтобы пополнить этот токен, необходимо сначала открыть Trustline — это позволит вашему кошельку принимать и хранить этот актив. + Откройте Trustline Это Testnet карта. Он не может обрабатывать транзакции и используется только в целях тестирования и разработки. Только для целей тестирования Возможно, баланс устарел. Обновите страницу. diff --git a/core/res/src/main/res/values-uk-rUA/strings.xml b/core/res/src/main/res/values-uk-rUA/strings.xml index e260b556af..a6ec71a7c8 100644 --- a/core/res/src/main/res/values-uk-rUA/strings.xml +++ b/core/res/src/main/res/values-uk-rUA/strings.xml @@ -329,6 +329,7 @@ Незабаром з\'являться нові провайдери.\nСлідкуйте за новинами! Провайдер Найкращий курс + Список попереджень FCA Доступно до %s Доступно від %s Недоступно для цієї пари @@ -1140,6 +1141,8 @@ Сума отримання не може бути меншою за %s Це може статися тому, що провайдер наразі не може обміняти обрану пару. Будь ласка, зачекайте трохи та спробуйте ще раз. (Код %s) Обрана пара тимчасово недоступна + Деякі провайдери не мають авторизації від Британського фінансового регулятора (FCA). Рекомендуємо уникати взаємодії з ними. + Список попереджень FCA Сервіс тимчасово недоступний Сума до обміну не повинна перевищувати %s Сума для обміну має бути не менше %s diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index f3f8181cf9..8f66364be9 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -1,6 +1,5 @@ - Required minimum XLM reserve %1$s Can’t find your token? Go to the Market section on the main page and add it to your portfolio for purchase Can’t find your token? Go to the Market section on the main page and add it to your portfolio for selling. Sell @@ -338,6 +337,7 @@ More providers will be available soon Provider Best rate + FCA Warning List Available up to %s Available from %s Unavailable for this pair @@ -864,6 +864,7 @@ network fee will be covered by using %1$s energy network fee will be reduced by spending %1$s energy including a network fee of %1$s + asdflkdsl;kfasl;fn;lnf asdjfnasdk;jf dfk;jasdjf;kajsdnf Transaction has been successfully signed and sent to the blockchain node. Wallet balance will be updated in a while %1$s is an asset in the Tron network. To calculate the fee and make a transaction you need to deposit some Tron (TRX) in your account. Amount exceeds balance @@ -1269,6 +1270,8 @@ The amount to receive must be at least %s This may occur because the provider is currently unable to exchange your selected pair. Please wait a moment and try again. (Code %s) Selected pair temporarily unavailable + Some providers are not authorized by the UK Financial Conduct Authority. You should avoid dealing with them. + FCA Warning List Service temporarily unavailable The amount of tokens to be swapped must not exceed %s The amount to swap must be at least %s @@ -1304,7 +1307,7 @@ Your review keeps us motivated to make Tangem Wallet even better Enjoying Tangem? You must associate your token before receiving tokens - You must open trustline before receiving tokens + You must open trustline for your token before receiving it Network rent fee required Action required Did you contact support via the app within 7 days of creating your wallet? If yes, or if you\'re unsure, click \'Yes\' and follow the instructions. @@ -1320,9 +1323,10 @@ Swipe down to refresh or try again later. Some networks are unreachable Some token balances could not be updated - Open trustline - Open trustline subtiile - Open trustline title + Not enough %1$s. Top up your XLM account to associate this token + Enable Trustline + According to network rules, you need to open a Trustline before depositing this token. It allows your wallet to accept and hold the asset. + Enable Trustline for this token This is a Testnet card. It cannot process transactions and should only be used for testing and development purposes. For testing purposes only Balance may be outdated. Refresh the page. @@ -1346,8 +1350,10 @@ Allow to spend Address Connect + Loading Network Networks + Unlimited Wallet Connected networks View your wallet balance and activity @@ -1364,6 +1370,7 @@ Text about discnected all dApps Disconect All dApps Estimated wallet changes + The transaction couldn\'t be simulated. Please proceed with caution. Malicious transaction Add the %s network to your profile for this wallet The wallet has no required networks diff --git a/core/ui/src/main/res/drawable/ic_edit_new_24.xml b/core/ui/src/main/res/drawable/ic_edit_new_12.xml similarity index 92% rename from core/ui/src/main/res/drawable/ic_edit_new_24.xml rename to core/ui/src/main/res/drawable/ic_edit_new_12.xml index 438006f6fa..6fff0490f2 100644 --- a/core/ui/src/main/res/drawable/ic_edit_new_24.xml +++ b/core/ui/src/main/res/drawable/ic_edit_new_12.xml @@ -1,6 +1,6 @@ > { + val jsonArray = JSONArray(rawParams) + return (0 until jsonArray.length()).map { index -> + val jsonObject = jsonArray.getJSONObject(index) + jsonObject.keys().asSequence().associateWith { key -> jsonObject.getString(key) } + } + } + fun mapToSolanaRequest(from: TransactionData): SolanaTransactionScanRequest { return SolanaTransactionScanRequest( - chain = from.chain, + chain = from.chain.lowercase(), accountAddress = from.accountAddress, metadata = TransactionMetadata(from.domainUrl), method = from.method, @@ -66,15 +75,19 @@ internal object BlockAidMapper { private fun mapSimulationSuccessResult(from: AccountSummaryResponse): SimulationResult { return when { - from.assetsDiffs.isEmpty() && from.exposures.isNotEmpty() -> mapApproveTransaction(from.exposures) - from.assetsDiffs.isNotEmpty() && from.exposures.isEmpty() -> mapSendReceiveTransaction(from.assetsDiffs) + !from.assetsDiffs.isNullOrEmpty() -> mapSendReceiveTransaction( + from.assetsDiffs, + ) + !from.exposures.isNullOrEmpty() -> mapApproveTransaction( + from.exposures, + ) !from.traces.isNullOrEmpty() -> mapNftSendReceiveTransaction(from.traces) else -> SimulationResult.FailedToSimulate } } - private fun mapApproveTransaction(exposures: List): SimulationResult { - val amounts = exposures.flatMap { exposure -> + private fun mapApproveTransaction(exposures: List?): SimulationResult { + val amounts = exposures?.flatMap { exposure -> val tokenInfo = TokenInfo( chainId = exposure.asset.chainId, logoUrl = exposure.asset.logoUrl, @@ -86,25 +99,25 @@ internal object BlockAidMapper { val approval = spender.approval?.hexToBigDecimal() spender.exposure.mapNotNull { detail -> ApprovedAmount( - approvedAmount = approval ?: detail.value.toBigDecimalOrNull() ?: return@mapNotNull null, + approvedAmount = detail.value.toBigDecimalOrNull() ?: approval ?: return@mapNotNull null, isUnlimited = isUnlimited, tokenInfo = tokenInfo, ) } } } - return if (amounts.isNotEmpty()) { + return if (!amounts.isNullOrEmpty()) { SimulationResult.Success(SimulationData.Approve(amounts)) } else { SimulationResult.FailedToSimulate } } - private fun mapSendReceiveTransaction(assetDiffs: List): SimulationResult { + private fun mapSendReceiveTransaction(assetDiffs: List?): SimulationResult { val sendInfo = arrayListOf() val receiveInfo = arrayListOf() - assetDiffs.forEach { diff -> + assetDiffs?.forEach { diff -> val token = TokenInfo( chainId = diff.asset.chainId, logoUrl = diff.asset.logoUrl, @@ -131,8 +144,10 @@ internal object BlockAidMapper { } private fun mapNftSendReceiveTransaction(traces: List?): SimulationResult { - val sendInfo = traces?.map { - AmountInfo.NonFungibleTokens(name = "${it.asset.name} #${it.exposed.tokenId}", logoUrl = it.exposed.logoUrl) + val sendInfo = traces?.mapNotNull { + it.exposed?.let { exposed -> + AmountInfo.NonFungibleTokens(name = "${it.asset.name} #${exposed.tokenId}", logoUrl = exposed.logoUrl) + } } return if (!sendInfo.isNullOrEmpty()) { diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcCommonTransactionUMConverter.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcCommonTransactionUMConverter.kt index 853990637c..84dc4e2c49 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcCommonTransactionUMConverter.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcCommonTransactionUMConverter.kt @@ -5,6 +5,7 @@ import com.tangem.domain.walletconnect.model.WcSolanaMethod import com.tangem.domain.walletconnect.usecase.method.WcMessageSignUseCase import com.tangem.domain.walletconnect.usecase.method.WcSignState import com.tangem.domain.walletconnect.usecase.method.WcSignUseCase +import com.tangem.domain.walletconnect.usecase.method.WcTransactionUseCase import com.tangem.features.walletconnect.transaction.entity.common.WcCommonTransactionUM import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM import com.tangem.utils.converter.Converter @@ -13,6 +14,7 @@ import javax.inject.Inject internal class WcCommonTransactionUMConverter @Inject constructor( private val signTypedDataUMConverter: WcSignTypedDataUMConverter, private val signTransactionUMConverter: WcSignTransactionUMConverter, + private val sendTransactionUMConverter: WcSendTransactionUMConverter, ) : Converter { override fun convert(value: Input): WcCommonTransactionUM? { @@ -38,7 +40,14 @@ internal class WcCommonTransactionUMConverter @Inject constructor( else -> null } } - else -> TODO("[REDACTED_JIRA]") + is WcTransactionUseCase -> sendTransactionUMConverter.convert( + WcSendTransactionUMConverter.Input( + useCase = value.useCase, + signState = value.signState, + actions = value.actions, + ), + ) + else -> null } } diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSendTransactionUMConverter.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSendTransactionUMConverter.kt new file mode 100644 index 0000000000..d91c5cfc46 --- /dev/null +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSendTransactionUMConverter.kt @@ -0,0 +1,89 @@ +package com.tangem.features.walletconnect.transaction.converter + +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.domain.walletconnect.model.WcEthMethod +import com.tangem.domain.walletconnect.model.WcSolanaMethod +import com.tangem.domain.walletconnect.usecase.method.WcSignState +import com.tangem.domain.walletconnect.usecase.method.WcSignStep +import com.tangem.domain.walletconnect.usecase.method.WcTransactionUseCase +import com.tangem.features.walletconnect.impl.R +import com.tangem.features.walletconnect.transaction.entity.blockaid.WcSendReceiveTransactionCheckResultsUM +import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM +import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestBlockUM +import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoItemUM +import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoUM +import com.tangem.features.walletconnect.transaction.entity.send.WcSendTransactionItemUM +import com.tangem.features.walletconnect.transaction.entity.send.WcSendTransactionUM +import com.tangem.utils.converter.Converter +import kotlinx.collections.immutable.toImmutableList +import javax.inject.Inject + +internal class WcSendTransactionUMConverter @Inject constructor( + private val appInfoContentUMConverter: WcTransactionAppInfoContentUMConverter, + private val networkInfoUMConverter: WcNetworkInfoUMConverter, + private val requestBlockUMConverter: WcTransactionRequestBlockUMConverter, +) : Converter { + + override fun convert(value: Input): WcSendTransactionUM? = when (value.useCase.method) { + is WcEthMethod.SendTransaction, + is WcEthMethod.SignTransaction, + is WcSolanaMethod.SignAllTransaction, + is WcSolanaMethod.SignTransaction, + -> WcSendTransactionUM( + transaction = WcSendTransactionItemUM( + onDismiss = value.actions.onDismiss, + onSend = value.actions.onSign, + appInfo = appInfoContentUMConverter.convert( + WcTransactionAppInfoContentUMConverter.Input( + session = value.useCase.session, + onShowVerifiedAlert = value.actions.onShowVerifiedAlert, + ), + ), + walletName = value.useCase.session.wallet.name, + networkInfo = networkInfoUMConverter.convert(value.useCase.network), + address = value.useCase.walletAddress.toShortAddressText(), + estimatedWalletChanges = WcSendReceiveTransactionCheckResultsUM(), + isLoading = value.signState.domainStep == WcSignStep.Signing, + ), + transactionRequestInfo = WcTransactionRequestInfoUM( + blocks = buildList { + add( + requestBlockUMConverter.convert( + WcTransactionRequestBlockUMConverter.Input(value.useCase.rawSdkRequest), + ), + ) + (value.useCase.method as? WcEthMethod.SendTransaction)?.transaction?.let { transaction -> + add( + WcTransactionRequestBlockUM( + info = buildList { + transaction.to?.let { + add( + WcTransactionRequestInfoItemUM( + title = resourceReference(R.string.wc_transaction_info_to_title), + description = it, + ), + ) + } + add( + WcTransactionRequestInfoItemUM( + title = resourceReference(R.string.send_from_wallet_android), + description = transaction.from, + ), + ) + }.toImmutableList(), + ), + ) + } + }.toImmutableList(), + onCopy = value.actions.onCopy, + ), + ) + else -> null + } + + data class Input( + val useCase: WcTransactionUseCase, + val signState: WcSignState<*>, + val actions: WcTransactionActionsUM, + ) +} \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSignTypedDataUMConverter.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSignTypedDataUMConverter.kt index be17ac0cdf..260bf7461c 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSignTypedDataUMConverter.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSignTypedDataUMConverter.kt @@ -72,13 +72,13 @@ internal class WcSignTypedDataUMConverter @Inject constructor( ), ) - private fun String.toShortAddressText() = - "${take(ADDRESS_FIRST_PART_LENGTH)}...${takeLast(ADDRESS_SECOND_PART_LENGTH)}" - data class Input( val useCase: WcMessageSignUseCase, val signState: WcSignState<*>, val signModel: WcMessageSignUseCase.SignModel, val actions: WcTransactionActionsUM, ) -} \ No newline at end of file +} + +internal fun String.toShortAddressText() = + "${take(ADDRESS_FIRST_PART_LENGTH)}...${takeLast(ADDRESS_SECOND_PART_LENGTH)}" \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/entity/blockaid/WcSendReceiveTransactionCheckResultsUM.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/entity/blockaid/WcSendReceiveTransactionCheckResultsUM.kt index 87e77e9bfd..418d483031 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/entity/blockaid/WcSendReceiveTransactionCheckResultsUM.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/entity/blockaid/WcSendReceiveTransactionCheckResultsUM.kt @@ -3,6 +3,7 @@ package com.tangem.features.walletconnect.transaction.entity.blockaid import com.tangem.core.ui.extensions.TextReference internal data class WcSendReceiveTransactionCheckResultsUM( - val estimatedWalletChanges: WcEstimatedWalletChangesUM?, + val estimatedWalletChanges: WcEstimatedWalletChangesUM? = null, val notificationText: TextReference? = null, + val isLoading: Boolean = true, ) \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/entity/send/WcSendTransactionUM.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/entity/send/WcSendTransactionUM.kt index 50ad8b67ff..e7bfe5f339 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/entity/send/WcSendTransactionUM.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/entity/send/WcSendTransactionUM.kt @@ -1,7 +1,7 @@ package com.tangem.features.walletconnect.transaction.entity.send import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent -import com.tangem.features.walletconnect.transaction.entity.blockaid.WcEstimatedWalletChangesUM +import com.tangem.features.walletconnect.transaction.entity.blockaid.WcSendReceiveTransactionCheckResultsUM import com.tangem.features.walletconnect.transaction.entity.common.WcCommonTransactionUM import com.tangem.features.walletconnect.transaction.entity.common.WcNetworkInfoUM import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionAppInfoContentUM @@ -16,7 +16,7 @@ internal data class WcSendTransactionItemUM( val onDismiss: () -> Unit, val onSend: () -> Unit, val appInfo: WcTransactionAppInfoContentUM, - val estimatedWalletChanges: WcEstimatedWalletChangesUM, + val estimatedWalletChanges: WcSendReceiveTransactionCheckResultsUM?, val walletName: String, val networkInfo: WcNetworkInfoUM, val networkFee: String? = null, diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt index 41f9283c12..7d6e89e107 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt @@ -9,6 +9,7 @@ import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router import com.tangem.core.ui.clipboard.ClipboardManager +import com.tangem.domain.core.lce.Lce import com.tangem.domain.walletconnect.WcRequestUseCaseFactory import com.tangem.domain.walletconnect.usecase.method.* import com.tangem.features.walletconnect.transaction.components.common.WcTransactionModelParams @@ -17,14 +18,15 @@ import com.tangem.features.walletconnect.transaction.entity.common.WcTransaction import com.tangem.features.walletconnect.transaction.entity.send.WcSendTransactionUM import com.tangem.features.walletconnect.transaction.routes.WcTransactionRoutes import com.tangem.features.walletconnect.transaction.converter.WcCommonTransactionUMConverter +import com.tangem.features.walletconnect.transaction.entity.blockaid.WcSendReceiveTransactionCheckResultsUM +import com.tangem.features.walletconnect.transaction.ui.blockaid.WcSendAndReceiveBlockAidUiConverter import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import javax.inject.Inject +@Suppress("LongParameterList") @Stable @ModelScoped internal class WcSendTransactionModel @Inject constructor( @@ -34,6 +36,7 @@ internal class WcSendTransactionModel @Inject constructor( private val clipboardManager: ClipboardManager, private val useCaseFactory: WcRequestUseCaseFactory, private val converter: WcCommonTransactionUMConverter, + private val blockAidUiConverter: WcSendAndReceiveBlockAidUiConverter, ) : Model(), WcCommonTransactionModel { private val params = paramsContainer.require() @@ -49,28 +52,49 @@ internal class WcSendTransactionModel @Inject constructor( is WcTransactionUseCase, is WcListTransactionUseCase, -> { - useCase.invoke().onEach { signState -> - if (signingIsDone(signState)) return@onEach - val transactionUM = converter.convert( - WcCommonTransactionUMConverter.Input( - useCase = useCase, - signState = signState, - actions = WcTransactionActionsUM( - onShowVerifiedAlert = ::showVerifiedAlert, - onDismiss = { cancel(useCase) }, - onSign = useCase::sign, - onCopy = { copyData(useCase.rawSdkRequest.request.params) }, - ), - ), - ) as? WcSendTransactionUM - _uiState.emit(transactionUM) - } - .launchIn(this) + observeTransactionData(useCase) } } } } + private suspend fun observeSecurityData(useCase: WcSignUseCase) { + (useCase as? BlockAidTransactionCheck)?.let { + useCase.securityStatus.collectLatest { + val blockAidState = when (it) { + is Lce.Content -> blockAidUiConverter.convert(it.content.result) + is Lce.Error -> WcSendReceiveTransactionCheckResultsUM(isLoading = false) + is Lce.Loading -> WcSendReceiveTransactionCheckResultsUM(isLoading = true) + } + val current = _uiState.value + _uiState.emit( + current?.copy(transaction = current.transaction.copy(estimatedWalletChanges = blockAidState)), + ) + } + } + } + + private fun CoroutineScope.observeTransactionData(useCase: WcSignUseCase) { + useCase.invoke().onEach { signState -> + if (signingIsDone(signState)) return@onEach + val transactionUM = converter.convert( + WcCommonTransactionUMConverter.Input( + useCase = useCase, + signState = signState, + actions = WcTransactionActionsUM( + onShowVerifiedAlert = ::showVerifiedAlert, + onDismiss = { cancel(useCase) }, + onSign = useCase::sign, + onCopy = { copyData(useCase.rawSdkRequest.request.params) }, + ), + ), + ) as? WcSendTransactionUM + _uiState.emit(transactionUM) + observeSecurityData(useCase) + } + .launchIn(this) + } + override fun dismiss() { _uiState.value?.transaction?.onDismiss?.invoke() ?: router.pop() } diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/approve/WcSpendAllowanceItem.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/approve/WcSpendAllowanceItem.kt index 329402c6cd..2c1322217f 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/approve/WcSpendAllowanceItem.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/approve/WcSpendAllowanceItem.kt @@ -78,7 +78,7 @@ internal fun WcSpendAllowanceItem(spendAllowance: WcSpendAllowanceUM, modifier: Spacer(modifier = Modifier.width(TangemTheme.dimens.spacing8)) Icon( - painter = painterResource(id = R.drawable.ic_edit_new_24), + painter = painterResource(id = R.drawable.ic_edit_new_12), contentDescription = null, tint = TangemTheme.colors.icon.informative, ) diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/blockaid/TransactionCheckResultsItem.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/blockaid/TransactionCheckResultsItem.kt index a07199a0f5..6a8cb9829e 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/blockaid/TransactionCheckResultsItem.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/blockaid/TransactionCheckResultsItem.kt @@ -27,15 +27,20 @@ internal fun TransactionCheckResultsItem(item: WcSendReceiveTransactionCheckResu Column( modifier = modifier - .padding(12.dp) .fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(12.dp), ) { - item.notificationText?.let { - WcTransactionCheckErrorItem(it.resolveReference()) - } - item.estimatedWalletChanges?.let { - WcEstimatedWalletChangesItem(it) + if (item.isLoading) { + WcEstimatedWalletChangesLoadingItem() + } else { + if (item.notificationText != null) { + WcTransactionCheckErrorItem(item.notificationText.resolveReference()) + } + if (item.estimatedWalletChanges != null) { + WcEstimatedWalletChangesItem(item.estimatedWalletChanges) + } else { + WcEstimatedWalletChangesNotLoadedItem() + } } } } @@ -59,6 +64,7 @@ private fun TransactionCheckResultsItemPreview( private class TransactionCheckResultsItemProvider : PreviewParameterProvider { override val values = sequenceOf( WcSendReceiveTransactionCheckResultsUM( + isLoading = false, notificationText = TextReference.Str("The transaction approves erc20 tokens to a known malicious address"), estimatedWalletChanges = WcEstimatedWalletChangesUM( items = persistentListOf( diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/blockaid/WcEstimatedWalletChangesLoadingItem.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/blockaid/WcEstimatedWalletChangesLoadingItem.kt new file mode 100644 index 0000000000..abd604faa3 --- /dev/null +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/blockaid/WcEstimatedWalletChangesLoadingItem.kt @@ -0,0 +1,69 @@ +package com.tangem.features.walletconnect.transaction.ui.blockaid + +import android.content.res.Configuration +import androidx.compose.animation.animateContentSize +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.tooling.preview.Devices +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.tangem.core.ui.extensions.stringResourceSafe +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreview +import com.tangem.features.walletconnect.impl.R +import com.tangem.features.walletconnect.transaction.ui.common.WcSmallTitleItem + +@Composable +internal fun WcEstimatedWalletChangesLoadingItem(modifier: Modifier = Modifier) { + Column( + modifier = modifier + .clip(RoundedCornerShape(14.dp)) + .background(color = TangemTheme.colors.background.action) + .fillMaxWidth() + .animateContentSize(), + ) { + WcSmallTitleItem( + textRex = R.string.wc_estimated_wallet_changes, + modifier = Modifier.padding(bottom = 16.dp), + ) + + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding(bottom = 14.dp), + ) { + CircularProgressIndicator( + color = TangemTheme.colors.icon.accent, + strokeWidth = 2.dp, + modifier = Modifier.size(24.dp), + ) + Text( + modifier = modifier + .fillMaxWidth(), + text = stringResourceSafe(R.string.wc_common_loading), + color = TangemTheme.colors.text.disabled, + style = TangemTheme.typography.body2, + ) + } + } +} + +@Composable +@Preview(showBackground = true, device = Devices.PIXEL_7_PRO) +@Preview(showBackground = true, device = Devices.PIXEL_7_PRO, uiMode = Configuration.UI_MODE_NIGHT_YES) +private fun WcEstimatedWalletChangesLoadingItems() { + TangemThemePreview { + Box( + modifier = Modifier + .background(TangemTheme.colors.background.tertiary), + ) { + WcEstimatedWalletChangesLoadingItem() + } + } +} \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/blockaid/WcEstimatedWalletChangesNotLoadedItem.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/blockaid/WcEstimatedWalletChangesNotLoadedItem.kt new file mode 100644 index 0000000000..04671ce12c --- /dev/null +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/blockaid/WcEstimatedWalletChangesNotLoadedItem.kt @@ -0,0 +1,58 @@ +package com.tangem.features.walletconnect.transaction.ui.blockaid + +import android.content.res.Configuration +import androidx.compose.animation.animateContentSize +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.tooling.preview.Devices +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.tangem.core.ui.extensions.stringResourceSafe +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreview +import com.tangem.features.walletconnect.impl.R +import com.tangem.features.walletconnect.transaction.ui.common.WcSmallTitleItem + +@Composable +internal fun WcEstimatedWalletChangesNotLoadedItem(modifier: Modifier = Modifier) { + Column( + modifier = modifier + .clip(RoundedCornerShape(14.dp)) + .background(color = TangemTheme.colors.background.action) + .fillMaxWidth() + .animateContentSize(), + ) { + WcSmallTitleItem( + textRex = R.string.wc_estimated_wallet_changes, + modifier = Modifier.padding(bottom = 16.dp), + ) + + Text( + modifier = modifier + .fillMaxWidth() + .padding(start = 12.dp, bottom = 14.dp), + text = stringResourceSafe(R.string.wc_estimated_wallet_changes_not_simulated), + color = TangemTheme.colors.text.tertiary, + style = TangemTheme.typography.body2, + ) + } +} + +@Composable +@Preview(showBackground = true, device = Devices.PIXEL_7_PRO) +@Preview(showBackground = true, device = Devices.PIXEL_7_PRO, uiMode = Configuration.UI_MODE_NIGHT_YES) +private fun WcEstimatedWalletChangesNotLoadedItems() { + TangemThemePreview { + Box( + modifier = Modifier + .background(TangemTheme.colors.background.tertiary), + ) { + WcEstimatedWalletChangesNotLoadedItem() + } + } +} \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/blockaid/WcSendAndReceiveBlockAidUiConverter.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/blockaid/WcSendAndReceiveBlockAidUiConverter.kt index 7bc7b50afe..89890d3b27 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/blockaid/WcSendAndReceiveBlockAidUiConverter.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/blockaid/WcSendAndReceiveBlockAidUiConverter.kt @@ -16,13 +16,15 @@ import com.tangem.features.walletconnect.transaction.entity.blockaid.WcEstimated import com.tangem.utils.converter.Converter import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList +import javax.inject.Inject private const val DECIMALS_AMOUNT = 2 -internal class WcSendAndReceiveBlockAidUiConverter : +internal class WcSendAndReceiveBlockAidUiConverter @Inject constructor() : Converter { override fun convert(value: CheckTransactionResult): WcSendReceiveTransactionCheckResultsUM { return WcSendReceiveTransactionCheckResultsUM( + isLoading = false, notificationText = when (value.validation) { ValidationResult.SAFE, ValidationResult.FAILED_TO_VALIDATE -> null ValidationResult.UNSAFE -> TextReference.Str("") // TODO("Add text after approve with designer") diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/common/WcSmallTitleItem.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/common/WcSmallTitleItem.kt index e6d70ced09..501084213c 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/common/WcSmallTitleItem.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/common/WcSmallTitleItem.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.res.TangemTheme @@ -14,7 +15,7 @@ fun WcSmallTitleItem(@StringRes textRex: Int, modifier: Modifier = Modifier) { Text( modifier = modifier .fillMaxWidth() - .padding(top = TangemTheme.dimens.spacing12, start = TangemTheme.dimens.spacing12), + .padding(top = 12.dp, start = 12.dp), text = stringResourceSafe(textRex), color = TangemTheme.colors.text.tertiary, style = TangemTheme.typography.subtitle2, diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/send/WcSendTransactionModalBottomSheet.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/send/WcSendTransactionModalBottomSheet.kt index 6bfd5d7ea3..f6a2782b93 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/send/WcSendTransactionModalBottomSheet.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/send/WcSendTransactionModalBottomSheet.kt @@ -20,6 +20,7 @@ import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheet import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetWithFooter import com.tangem.core.ui.components.divider.DividerWithPadding +import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview @@ -28,10 +29,11 @@ import com.tangem.features.walletconnect.connections.ui.WcAppInfoItem import com.tangem.features.walletconnect.impl.R import com.tangem.features.walletconnect.transaction.entity.blockaid.WcEstimatedWalletChangeUM import com.tangem.features.walletconnect.transaction.entity.blockaid.WcEstimatedWalletChangesUM +import com.tangem.features.walletconnect.transaction.entity.blockaid.WcSendReceiveTransactionCheckResultsUM import com.tangem.features.walletconnect.transaction.entity.common.WcNetworkInfoUM import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionAppInfoContentUM import com.tangem.features.walletconnect.transaction.entity.send.WcSendTransactionItemUM -import com.tangem.features.walletconnect.transaction.ui.blockaid.WcEstimatedWalletChangesItem +import com.tangem.features.walletconnect.transaction.ui.blockaid.TransactionCheckResultsItem import com.tangem.features.walletconnect.transaction.ui.common.WcSendTransactionItems import com.tangem.features.walletconnect.transaction.ui.common.WcSmallTitleItem import com.tangem.features.walletconnect.transaction.ui.common.WcTransactionRequestButtons @@ -89,7 +91,9 @@ internal fun WcSendTransactionModalBottomSheet( ) } Column(modifier = Modifier.padding(top = 16.dp)) { - WcEstimatedWalletChangesItem(state.estimatedWalletChanges) + if (state.estimatedWalletChanges != null) { + TransactionCheckResultsItem(state.estimatedWalletChanges) + } Spacer(Modifier.height(16.dp)) WcSendTransactionItems( walletName = state.walletName, @@ -153,19 +157,24 @@ private class WcSendTransactionStateProvider : CollectionPreviewParameterProvide verifiedState = VerifiedDAppState.Verified {}, appSubtitle = "react-app.walletconnect.com", ), - estimatedWalletChanges = WcEstimatedWalletChangesUM( - items = persistentListOf( - WcEstimatedWalletChangeUM( - iconRes = R.drawable.ic_send_new_24, - title = resourceReference(R.string.common_send), - description = "- 42 USDT", - tokenIconUrl = "https://tangem.com", - ), - WcEstimatedWalletChangeUM( - iconRes = R.drawable.ic_receive_new_24, - title = resourceReference(R.string.common_receive), - description = "+ 1,131.46 MATIC", - tokenIconUrl = "https://tangem.com", + estimatedWalletChanges = WcSendReceiveTransactionCheckResultsUM( + notificationText = TextReference.Str( + "The transaction approves erc20 tokens to a known malicious address", + ), + estimatedWalletChanges = WcEstimatedWalletChangesUM( + items = persistentListOf( + WcEstimatedWalletChangeUM( + iconRes = R.drawable.ic_send_new_24, + title = resourceReference(R.string.common_send), + description = "- 42 USDT", + tokenIconUrl = "https://tangem.com", + ), + WcEstimatedWalletChangeUM( + iconRes = R.drawable.ic_receive_new_24, + title = resourceReference(R.string.common_receive), + description = "+ 1,131.46 MATIC", + tokenIconUrl = "https://tangem.com", + ), ), ), ),