diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index 4bf9538ce4..f4809d2272 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -2377,6 +2377,7 @@
All dApps disconnected
Allow to spend
By approving, you allow dApp or Smart contract to use tokens in future transactions.
+ Change address
Address
Connect
Loading
diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/bitcoin/WcBitcoinSignPsbtUseCase.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/bitcoin/WcBitcoinSignPsbtUseCase.kt
index 302376444a..af1d2ac464 100644
--- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/bitcoin/WcBitcoinSignPsbtUseCase.kt
+++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/bitcoin/WcBitcoinSignPsbtUseCase.kt
@@ -19,7 +19,9 @@ import com.tangem.domain.core.lce.LceFlow
import com.tangem.domain.walletconnect.WcTransactionSignerProvider
import com.tangem.domain.walletconnect.model.HandleMethodError
import com.tangem.domain.walletconnect.model.WcBitcoinMethod
+import com.tangem.domain.walletconnect.model.WcPsbtOutput
import com.tangem.domain.walletconnect.usecase.method.BlockAidTransactionCheck
+import com.tangem.domain.walletconnect.usecase.method.WcPsbtUseCase
import com.tangem.domain.walletconnect.usecase.method.WcSignState
import com.tangem.domain.walletconnect.usecase.method.WcTransactionUseCase
import com.tangem.domain.walletmanager.WalletManagersFacade
@@ -51,7 +53,8 @@ internal class WcBitcoinSignPsbtUseCase @AssistedInject constructor(
blockAidDelegate: BlockAidVerificationDelegate,
@SdkMoshi private val moshi: Moshi,
) : BaseWcSignUseCase(),
- WcTransactionUseCase {
+ WcTransactionUseCase,
+ WcPsbtUseCase {
override val wallet get() = context.session.wallet
@@ -120,6 +123,20 @@ internal class WcBitcoinSignPsbtUseCase @AssistedInject constructor(
}
}
+ override suspend fun parsePsbtOutputs(): List {
+ val walletManager = walletManagersFacade.getOrCreateWalletManager(wallet.walletId, network)
+ ?: return emptyList()
+ return when (val result = walletManager.parsePsbtOutputs(method.psbt)) {
+ is SdkResult.Success -> result.data.map { output ->
+ WcPsbtOutput(
+ address = output.address,
+ amountSatoshi = output.amountSatoshi,
+ )
+ }
+ is SdkResult.Failure -> emptyList()
+ }
+ }
+
override fun invoke(): Flow> {
val transactionData = TransactionData.Compiled(
value = TransactionData.Compiled.Data.RawString(method.psbt),
diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/utils/BlockAidVerificationDelegate.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/utils/BlockAidVerificationDelegate.kt
index bcd5f64cb5..d18221f88b 100644
--- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/utils/BlockAidVerificationDelegate.kt
+++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/utils/BlockAidVerificationDelegate.kt
@@ -54,13 +54,17 @@ internal class BlockAidVerificationDelegate @Inject constructor(
is WcSolanaMethod.SignAllTransaction -> TransactionParams.Solana(method.transaction)
is WcSolanaMethod.SignTransaction -> TransactionParams.Solana(listOf(method.transaction))
is WcSolanaMethod.SignAndSendTransaction -> TransactionParams.Solana(listOf(method.transaction))
- is WcSolanaMethod.SignMessage,
- is WcBitcoinMethod,
- -> {
- // BlockAid doesn't support Solana message signing and Bitcoin methods
+ is WcSolanaMethod.SignMessage -> {
+ // BlockAid doesn't support Solana message signing
emit(Lce.Content(createSafeResult()))
return@flow
}
+ is WcBitcoinMethod -> {
+ // BlockAid doesn't support Bitcoin methods: don't synthesize a SAFE result for an unscanned
+ // transaction
+ emit(Lce.Content(failedResult))
+ return@flow
+ }
else -> {
emit(Lce.Content(failedResult))
return@flow
diff --git a/domain/wallet-connect/models/src/main/java/com/tangem/domain/walletconnect/model/WcPsbtOutput.kt b/domain/wallet-connect/models/src/main/java/com/tangem/domain/walletconnect/model/WcPsbtOutput.kt
new file mode 100644
index 0000000000..0c960e9523
--- /dev/null
+++ b/domain/wallet-connect/models/src/main/java/com/tangem/domain/walletconnect/model/WcPsbtOutput.kt
@@ -0,0 +1,13 @@
+package com.tangem.domain.walletconnect.model
+
+/**
+ * A single output of a parsed PSBT (Partially Signed Bitcoin Transaction).
+ *
+ * @property address recipient address decoded from the output script, or `null` if it could not be decoded
+ * (e.g. `OP_RETURN` or non-standard scripts)
+ * @property amountSatoshi output amount, in satoshi
+ */
+data class WcPsbtOutput(
+ val address: String?,
+ val amountSatoshi: Long,
+)
\ No newline at end of file
diff --git a/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/method/WcPsbtUseCase.kt b/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/method/WcPsbtUseCase.kt
new file mode 100644
index 0000000000..5c0824ca3a
--- /dev/null
+++ b/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/method/WcPsbtUseCase.kt
@@ -0,0 +1,17 @@
+package com.tangem.domain.walletconnect.usecase.method
+
+import com.tangem.domain.walletconnect.model.WcPsbtOutput
+
+/**
+ * WalletConnect use case that can expose the outputs of a PSBT (`signPsbt` method) for display before signing.
+ *
+ */
+interface WcPsbtUseCase {
+
+ /**
+ * Parses the PSBT of the current request and returns its outputs (recipient + amount).
+ *
+ * Returns an empty list if the PSBT cannot be parsed (the UI then falls back to the raw request data).
+ */
+ suspend fun parsePsbtOutputs(): List
+}
\ No newline at end of file
diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcBtcSendTransferRequestInfoConverter.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcBtcSendTransferRequestInfoConverter.kt
new file mode 100644
index 0000000000..570f411303
--- /dev/null
+++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcBtcSendTransferRequestInfoConverter.kt
@@ -0,0 +1,52 @@
+package com.tangem.features.walletconnect.transaction.converter
+
+import com.tangem.core.ui.extensions.resourceReference
+import com.tangem.domain.walletconnect.model.WcBitcoinMethod
+import com.tangem.features.walletconnect.impl.R
+import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestBlockUM
+import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoItemUM
+import com.tangem.utils.converter.Converter
+import kotlinx.collections.immutable.toImmutableList
+import javax.inject.Inject
+
+/**
+ * Builds a transaction request details block (recipient and amount) for a Bitcoin `sendTransfer` WalletConnect request.
+ *
+ */
+internal class WcBtcSendTransferRequestInfoConverter @Inject constructor() :
+ Converter {
+
+ override fun convert(value: Input): WcTransactionRequestBlockUM {
+ val method = value.method
+ return WcTransactionRequestBlockUM(
+ info = buildList {
+ add(WcTransactionRequestInfoItemUM(resourceReference(R.string.common_from), method.account))
+ add(WcTransactionRequestInfoItemUM(resourceReference(R.string.common_to), method.recipientAddress))
+ add(
+ WcTransactionRequestInfoItemUM(
+ title = resourceReference(R.string.common_amount),
+ description = formatAmount(method.amount, value.decimals, value.symbol),
+ ),
+ )
+ val changeAddress = method.changeAddress
+ if (!changeAddress.isNullOrEmpty()) {
+ add(WcTransactionRequestInfoItemUM(resourceReference(R.string.wc_change_address), changeAddress))
+ }
+ }.toImmutableList(),
+ )
+ }
+
+ private fun formatAmount(amount: String, decimals: Int, symbol: String): String {
+ val value = amount.toBigDecimalOrNull()
+ ?.movePointLeft(decimals)
+ ?.stripTrailingZeros()
+ ?: return amount
+ return "${value.toPlainString()} $symbol"
+ }
+
+ data class Input(
+ val method: WcBitcoinMethod.SendTransfer,
+ val decimals: Int,
+ val symbol: String,
+ )
+}
\ No newline at end of file
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
index b4f72c25b2..6decf0a891 100644
--- 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
@@ -6,6 +6,7 @@ import com.tangem.domain.models.wallet.isHotWallet
import com.tangem.domain.walletconnect.model.WcBitcoinMethod
import com.tangem.domain.walletconnect.model.WcEthMethod
import com.tangem.domain.walletconnect.model.WcMethod
+import com.tangem.domain.walletconnect.model.WcPsbtOutput
import com.tangem.domain.walletconnect.model.WcSolanaMethod
import com.tangem.domain.walletconnect.usecase.method.BlockAidTransactionCheck
import com.tangem.domain.walletconnect.usecase.method.WcMethodContext
@@ -15,11 +16,13 @@ import com.tangem.features.send.api.entity.FeeSelectorUM
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.WcTransactionFeeState
+import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestBlockUM
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.features.walletconnect.utils.WcNotificationsFactory
import com.tangem.utils.converter.Converter
+import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import javax.inject.Inject
@@ -27,6 +30,8 @@ internal class WcSendTransactionUMConverter @Inject constructor(
private val appInfoContentUMConverter: WcTransactionAppInfoContentUMConverter,
private val networkInfoUMConverter: WcNetworkInfoUMConverter,
private val requestBlockUMConverter: WcTransactionRequestBlockUMConverter,
+ private val btcSendTransferRequestInfoConverter: WcBtcSendTransferRequestInfoConverter,
+ private val signPsbtRequestInfoConverter: WcSignPsbtRequestInfoConverter,
private val notificationsFactory: WcNotificationsFactory,
) : Converter {
@@ -76,13 +81,7 @@ internal class WcSendTransactionUMConverter @Inject constructor(
is WcTransactionFeeState.Success -> value.feeSelectorUM ?: FeeSelectorUM.Loading
},
transactionRequestInfo = WcTransactionRequestInfoUM(
- blocks = buildList {
- addAll(
- requestBlockUMConverter.convert(
- WcTransactionRequestBlockUMConverter.Input(value.context.rawSdkRequest),
- ),
- )
- }.toImmutableList(),
+ blocks = buildRequestInfoBlocks(value),
onCopy = value.actions.onCopy,
),
)
@@ -97,6 +96,37 @@ internal class WcSendTransactionUMConverter @Inject constructor(
}
}
+ private fun buildRequestInfoBlocks(value: Input): ImmutableList = buildList {
+ addAll(
+ requestBlockUMConverter.convert(
+ WcTransactionRequestBlockUMConverter.Input(value.context.rawSdkRequest),
+ ),
+ )
+ val method = value.context.method
+ if (method is WcBitcoinMethod.SendTransfer) {
+ add(
+ btcSendTransferRequestInfoConverter.convert(
+ WcBtcSendTransferRequestInfoConverter.Input(
+ method = method,
+ decimals = value.cryptoCurrencyStatus.currency.decimals,
+ symbol = value.cryptoCurrencyStatus.currency.symbol,
+ ),
+ ),
+ )
+ }
+ if (method is WcBitcoinMethod.SignPsbt && value.psbtOutputs != null) {
+ addAll(
+ signPsbtRequestInfoConverter.convert(
+ WcSignPsbtRequestInfoConverter.Input(
+ outputs = value.psbtOutputs,
+ decimals = value.cryptoCurrencyStatus.currency.decimals,
+ symbol = value.cryptoCurrencyStatus.currency.symbol,
+ ),
+ ),
+ )
+ }
+ }.toImmutableList()
+
data class Input(
val context: WcMethodContext,
val portfolioName: AccountTitleUM?,
@@ -106,6 +136,7 @@ internal class WcSendTransactionUMConverter @Inject constructor(
val feeSelectorUM: FeeSelectorUM?,
val cryptoCurrencyStatus: CryptoCurrencyStatus,
val securityCheck: BlockAidTransactionCheck.Result?,
+ val psbtOutputs: List?,
val onFeeReload: () -> Unit,
)
}
\ No newline at end of file
diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSignPsbtRequestInfoConverter.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSignPsbtRequestInfoConverter.kt
new file mode 100644
index 0000000000..0d6c17811f
--- /dev/null
+++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSignPsbtRequestInfoConverter.kt
@@ -0,0 +1,66 @@
+package com.tangem.features.walletconnect.transaction.converter
+
+import com.tangem.core.ui.extensions.combinedReference
+import com.tangem.core.ui.extensions.resourceReference
+import com.tangem.core.ui.extensions.stringReference
+import com.tangem.domain.walletconnect.model.WcPsbtOutput
+import com.tangem.features.walletconnect.impl.R
+import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestBlockUM
+import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoItemUM
+import com.tangem.utils.converter.Converter
+import kotlinx.collections.immutable.toImmutableList
+import java.math.BigDecimal
+import javax.inject.Inject
+
+/**
+ * Builds transaction request details blocks (recipient + amount per output) for a Bitcoin `signPsbt` request.
+ *
+ */
+internal class WcSignPsbtRequestInfoConverter @Inject constructor() :
+ Converter> {
+
+ override fun convert(value: Input): List {
+ val outputs = value.outputs
+ if (outputs.isEmpty()) return emptyList()
+ val shouldShowIndex = outputs.size > 1
+ return outputs.mapIndexed { index, output ->
+ val recipientTitle = when {
+ output.address == null -> resourceReference(R.string.common_no_address)
+ shouldShowIndex -> combinedReference(
+ resourceReference(R.string.common_to),
+ stringReference(" ${index + 1}"),
+ )
+ else -> resourceReference(R.string.common_to)
+ }
+ WcTransactionRequestBlockUM(
+ info = buildList {
+ add(
+ WcTransactionRequestInfoItemUM(
+ title = recipientTitle,
+ description = output.address.orEmpty(),
+ ),
+ )
+ add(
+ WcTransactionRequestInfoItemUM(
+ title = resourceReference(R.string.common_amount),
+ description = formatAmount(output.amountSatoshi, value.decimals, value.symbol),
+ ),
+ )
+ }.toImmutableList(),
+ )
+ }
+ }
+
+ private fun formatAmount(amountSatoshi: Long, decimals: Int, symbol: String): String {
+ val value = BigDecimal.valueOf(amountSatoshi)
+ .movePointLeft(decimals)
+ .stripTrailingZeros()
+ return "${value.toPlainString()} $symbol"
+ }
+
+ data class Input(
+ val outputs: List,
+ val decimals: Int,
+ val symbol: String,
+ )
+}
\ No newline at end of file
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 171810fbb8..b03a710fd8 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
@@ -38,6 +38,7 @@ import com.tangem.domain.walletconnect.WcAnalyticEvents
import com.tangem.domain.walletconnect.WcAnalyticEvents.SignatureRequestReceived.EmulationStatus
import com.tangem.domain.walletconnect.WcAnalyticEvents.SolanaLargeTransaction
import com.tangem.domain.walletconnect.WcRequestUseCaseFactory
+import com.tangem.domain.walletconnect.model.WcPsbtOutput
import com.tangem.domain.walletconnect.model.WcRequestError
import com.tangem.domain.walletconnect.model.WcRequestError.Companion.message
import com.tangem.domain.walletconnect.usecase.method.*
@@ -100,6 +101,7 @@ internal class WcSendTransactionModel @Inject constructor(
private var useCase: WcSignUseCase<*> by Delegates.notNull()
private var signState: WcSignState<*> by Delegates.notNull()
private var wcApproval: WcApproval? = null
+ private var psbtOutputs: List? = null
private var sign: () -> Unit = {}
private val blockAidUiConverter = WcSendAndReceiveBlockAidUiConverter()
private val feeReloadState = MutableStateFlow(false)
@@ -126,6 +128,9 @@ internal class WcSendTransactionModel @Inject constructor(
.onNone { unknownMethodRunnable() }
.getOrNull() ?: return@launch
this@WcSendTransactionModel.useCase = useCase
+ if (useCase is WcPsbtUseCase) {
+ psbtOutputs = useCase.parsePsbtOutputs()
+ }
(useCase as? WcMutableFee)
?.dAppFee()
?.let { dAppFee ->
@@ -283,6 +288,7 @@ internal class WcSendTransactionModel @Inject constructor(
cryptoCurrencyStatus = cryptoCurrencyStatus,
onFeeReload = ::triggerFeeReload,
securityCheck = securityCheck.getOrNull(),
+ psbtOutputs = psbtOutputs,
portfolioName = portfolioNameDelegate.createAccountTitleUM(useCase.session),
),
)
diff --git a/features/walletconnect/impl/src/test/kotlin/com/tangem/features/walletconnect/transaction/converter/WcBtcSendTransferRequestInfoConverterTest.kt b/features/walletconnect/impl/src/test/kotlin/com/tangem/features/walletconnect/transaction/converter/WcBtcSendTransferRequestInfoConverterTest.kt
new file mode 100644
index 0000000000..30bd3a50bf
--- /dev/null
+++ b/features/walletconnect/impl/src/test/kotlin/com/tangem/features/walletconnect/transaction/converter/WcBtcSendTransferRequestInfoConverterTest.kt
@@ -0,0 +1,106 @@
+package com.tangem.features.walletconnect.transaction.converter
+
+import com.google.common.truth.Truth
+import com.tangem.core.ui.extensions.resourceReference
+import com.tangem.domain.walletconnect.model.WcBitcoinMethod
+import com.tangem.features.walletconnect.impl.R
+import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestBlockUM
+import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoItemUM
+import kotlinx.collections.immutable.toImmutableList
+import org.junit.jupiter.api.Test
+
+class WcBtcSendTransferRequestInfoConverterTest {
+
+ private val converter = WcBtcSendTransferRequestInfoConverter()
+
+ @Test
+ fun `GIVEN sendTransfer with change address WHEN convert THEN block with from to amount and change`() {
+ val input = WcBtcSendTransferRequestInfoConverter.Input(
+ method = WcBitcoinMethod.SendTransfer(
+ account = "bc1qsenderaddress",
+ recipientAddress = "bc1qrecipientaddress",
+ amount = "5000000",
+ memo = null,
+ changeAddress = "bc1qchangeaddress",
+ ),
+ decimals = 8,
+ symbol = "BTC",
+ )
+
+ val expected = WcTransactionRequestBlockUM(
+ info = listOf(
+ WcTransactionRequestInfoItemUM(resourceReference(R.string.common_from), "bc1qsenderaddress"),
+ WcTransactionRequestInfoItemUM(resourceReference(R.string.common_to), "bc1qrecipientaddress"),
+ WcTransactionRequestInfoItemUM(resourceReference(R.string.common_amount), "0.05 BTC"),
+ WcTransactionRequestInfoItemUM(resourceReference(R.string.wc_change_address), "bc1qchangeaddress"),
+ ).toImmutableList(),
+ )
+
+ Truth.assertThat(converter.convert(input)).isEqualTo(expected)
+ }
+
+ @Test
+ fun `GIVEN sendTransfer without change address WHEN convert THEN block with from to amount only`() {
+ val input = WcBtcSendTransferRequestInfoConverter.Input(
+ method = WcBitcoinMethod.SendTransfer(
+ account = "bc1qsenderaddress",
+ recipientAddress = "bc1qrecipientaddress",
+ amount = "100000000",
+ memo = null,
+ changeAddress = null,
+ ),
+ decimals = 8,
+ symbol = "BTC",
+ )
+
+ val expected = WcTransactionRequestBlockUM(
+ info = listOf(
+ WcTransactionRequestInfoItemUM(resourceReference(R.string.common_from), "bc1qsenderaddress"),
+ WcTransactionRequestInfoItemUM(resourceReference(R.string.common_to), "bc1qrecipientaddress"),
+ WcTransactionRequestInfoItemUM(resourceReference(R.string.common_amount), "1 BTC"),
+ ).toImmutableList(),
+ )
+
+ Truth.assertThat(converter.convert(input)).isEqualTo(expected)
+ }
+
+ @Test
+ fun `GIVEN blank change address WHEN convert THEN change address item is omitted`() {
+ val input = WcBtcSendTransferRequestInfoConverter.Input(
+ method = WcBitcoinMethod.SendTransfer(
+ account = "bc1qsenderaddress",
+ recipientAddress = "bc1qrecipientaddress",
+ amount = "1",
+ memo = null,
+ changeAddress = "",
+ ),
+ decimals = 8,
+ symbol = "BTC",
+ )
+
+ val result = converter.convert(input)
+
+ Truth.assertThat(result.info).hasSize(3)
+ Truth.assertThat(result.info.last().title).isEqualTo(resourceReference(R.string.common_amount))
+ }
+
+ @Test
+ fun `GIVEN non-numeric amount WHEN convert THEN raw amount is shown`() {
+ val input = WcBtcSendTransferRequestInfoConverter.Input(
+ method = WcBitcoinMethod.SendTransfer(
+ account = "bc1qsenderaddress",
+ recipientAddress = "bc1qrecipientaddress",
+ amount = "not-a-number",
+ memo = null,
+ changeAddress = null,
+ ),
+ decimals = 8,
+ symbol = "BTC",
+ )
+
+ val amountItem = converter.convert(input).info[2]
+
+ Truth.assertThat(amountItem.title).isEqualTo(resourceReference(R.string.common_amount))
+ Truth.assertThat(amountItem.description).isEqualTo("not-a-number")
+ }
+}
\ No newline at end of file
diff --git a/features/walletconnect/impl/src/test/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSignPsbtRequestInfoConverterTest.kt b/features/walletconnect/impl/src/test/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSignPsbtRequestInfoConverterTest.kt
new file mode 100644
index 0000000000..79224f7acd
--- /dev/null
+++ b/features/walletconnect/impl/src/test/kotlin/com/tangem/features/walletconnect/transaction/converter/WcSignPsbtRequestInfoConverterTest.kt
@@ -0,0 +1,82 @@
+package com.tangem.features.walletconnect.transaction.converter
+
+import com.google.common.truth.Truth
+import com.tangem.core.ui.extensions.combinedReference
+import com.tangem.core.ui.extensions.resourceReference
+import com.tangem.core.ui.extensions.stringReference
+import com.tangem.domain.walletconnect.model.WcPsbtOutput
+import com.tangem.features.walletconnect.impl.R
+import org.junit.jupiter.api.Test
+
+class WcSignPsbtRequestInfoConverterTest {
+
+ private val converter = WcSignPsbtRequestInfoConverter()
+
+ @Test
+ fun `GIVEN single output WHEN convert THEN one block with to and amount`() {
+ val input = WcSignPsbtRequestInfoConverter.Input(
+ outputs = listOf(WcPsbtOutput(address = "bc1qrecipient", amountSatoshi = 100_000L)),
+ decimals = 8,
+ symbol = "BTC",
+ )
+
+ val result = converter.convert(input)
+
+ Truth.assertThat(result).hasSize(1)
+ Truth.assertThat(result[0].info.map { it.title }).containsExactly(
+ resourceReference(R.string.common_to),
+ resourceReference(R.string.common_amount),
+ ).inOrder()
+ Truth.assertThat(result[0].info[0].description).isEqualTo("bc1qrecipient")
+ Truth.assertThat(result[0].info[1].description).isEqualTo("0.001 BTC")
+ }
+
+ @Test
+ fun `GIVEN multiple outputs WHEN convert THEN indexed blocks per output`() {
+ val input = WcSignPsbtRequestInfoConverter.Input(
+ outputs = listOf(
+ WcPsbtOutput(address = "bc1qfirst", amountSatoshi = 250_000L),
+ WcPsbtOutput(address = "bc1qsecond", amountSatoshi = 1_0000_0000L),
+ ),
+ decimals = 8,
+ symbol = "BTC",
+ )
+
+ val result = converter.convert(input)
+
+ Truth.assertThat(result).hasSize(2)
+ Truth.assertThat(result[0].info[0].title)
+ .isEqualTo(combinedReference(resourceReference(R.string.common_to), stringReference(" 1")))
+ Truth.assertThat(result[0].info[1].description).isEqualTo("0.0025 BTC")
+ Truth.assertThat(result[1].info[0].title)
+ .isEqualTo(combinedReference(resourceReference(R.string.common_to), stringReference(" 2")))
+ Truth.assertThat(result[1].info[0].description).isEqualTo("bc1qsecond")
+ Truth.assertThat(result[1].info[1].description).isEqualTo("1 BTC")
+ }
+
+ @Test
+ fun `GIVEN output with undecodable address WHEN convert THEN no address title and empty recipient`() {
+ val input = WcSignPsbtRequestInfoConverter.Input(
+ outputs = listOf(WcPsbtOutput(address = null, amountSatoshi = 50_000L)),
+ decimals = 8,
+ symbol = "BTC",
+ )
+
+ val result = converter.convert(input)
+
+ Truth.assertThat(result[0].info[0].title).isEqualTo(resourceReference(R.string.common_no_address))
+ Truth.assertThat(result[0].info[0].description).isEqualTo("")
+ Truth.assertThat(result[0].info[1].description).isEqualTo("0.0005 BTC")
+ }
+
+ @Test
+ fun `GIVEN no outputs WHEN convert THEN empty list`() {
+ val input = WcSignPsbtRequestInfoConverter.Input(
+ outputs = emptyList(),
+ decimals = 8,
+ symbol = "BTC",
+ )
+
+ Truth.assertThat(converter.convert(input)).isEmpty()
+ }
+}
\ No newline at end of file
diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml
index eef36fbda4..074e02bb80 100644
--- a/gradle/tangem_dependencies.toml
+++ b/gradle/tangem_dependencies.toml
@@ -5,7 +5,7 @@
# https://github.com/tangem/tangem-sdk-android/
# https://github.com/tangem/vico
-tangemBlockchainSdk = "develop-1566"
+tangemBlockchainSdk = "develop-1567"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
tangemCardSdk = "develop-624"
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^